ATLAS Offline Software
Loading...
Searching...
No Matches
ITkPixelCsvWaferIdAlg.cxx
Go to the documentation of this file.
1/*
2Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
7
8
9#include "GaudiKernel/EventContext.h"
11
12#include <fstream>
13#include <sstream>
14#include <stdexcept>
15#include <bitset>
16
17
19 ISvcLocator* pSvcLocator)
20 : AthReentrantAlgorithm(name, pSvcLocator)
21{
22}
23
25 ATH_MSG_INFO("Initializing CsvWaferId algorithm");
26 ATH_CHECK(detStore()->retrieve(m_pixIdHelper, "PixelID"));
27 ATH_MSG_INFO("Retrieved PixelID helper");
29 ATH_MSG_INFO("Loaded CSV file");
30 return StatusCode::SUCCESS;
31}
32
33StatusCode ITkPixelCsvWaferIdAlg::execute(const EventContext& ctx) const {
34
35 ATH_CHECK ( ctx.valid() );
36
37 if (m_done.load(std::memory_order_acquire)) {
38 return StatusCode::SUCCESS;
39 }
40
41 bool expected = false;
42 if (!m_done.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
43 return StatusCode::SUCCESS;
44 }
45
46 ATH_MSG_INFO("Executing CsvWaferId algorithm");
47
48 std::ofstream output(m_outputFile.value());
49 if (!output.good()) {
50 ATH_MSG_FATAL("Could not open wafer ID output file: " << m_outputFile.value());
51 return StatusCode::FAILURE;
52 }
53
54 for (const CsvRow& row : m_rows) {
55 const std::pair< Identifier, int> w_and_fe_id = waferId(row);
56 const Identifier id = w_and_fe_id.first;
57 const std::string waferId_str = id.get_identifier32().getString();
58 const auto bec = m_pixIdHelper->barrel_ec(id);
59 const auto ld = m_pixIdHelper->layer_disk(id);
60 const auto phi = m_pixIdHelper->phi_module(id);
61 const auto eta = m_pixIdHelper->eta_module(id);
62
63 std::string x = waferId_str.substr(0, waferId_str.length() - 2 );
64 std::stringstream ss;
65 ss << std::hex << x;
66 unsigned n;
67 ss >> n;
68 std::bitset<32> b(n);
69 b <<= 2; //shift left by two bits, to add FE bits
70 int fe = w_and_fe_id.second;
71 std::bitset<32> febits = std::bitset<32>(fe);
72 b |= febits;
73
74 if (msgLvl(MSG::DEBUG)) {
75 output << waferId_str << "\t"
76 << x << "\t"
77 << b.to_string() << "\t"
78 << febits.to_string() << "\t"
79 << bec << "\t"
80 << ld << "\t"
81 << phi << "\t"
82 << eta << "\t";
83 }
84 //convert back to hex
85 std::stringstream res;
86 res << std::hex << std::uppercase << b.to_ulong();
87 // keep this, might be useful later
88 //output << res.str() << "\n";
89 output << b.to_ulong() << "\n";
90
91 }
92
93 ATH_MSG_INFO("Wrote " << m_rows.size() << " wafer IDs to " << m_outputFile.value());
94 return StatusCode::SUCCESS;
95}
96
98 const std::string resolvedCsv = PathResolver::find_file(m_csvFile.value(), "DATAPATH");
99 if (resolvedCsv.empty()) {
100 ATH_MSG_FATAL("Could not resolve CSV file: " << m_csvFile.value());
101 return StatusCode::FAILURE;
102 }
103
104
105 std::ifstream input(resolvedCsv);
106 if (!input.good()) {
107 ATH_MSG_FATAL("Could not open CSV file: " << resolvedCsv);
108 return StatusCode::FAILURE;
109 }
110
111 m_rows.clear();
112
113 ATH_MSG_INFO("Loading CSV");
114 std::string line;
115 bool firstLine = true;
116 while (std::getline(input, line)) {
117 if (line.empty()) {
118 continue;
119 }
120
121 if (firstLine) {
122 firstLine = false;
123 continue;
124 }
125 const std::vector<std::string> fields = splitCsvLine(line);
126 if (fields.size() < 3) {
127 ATH_MSG_WARNING("Skipping malformed CSV line: " << line);
128 continue;
129 }
130
131 CsvRow row;
132 row.spChain = trim(fields[0]);
133 row.md = trim(fields[1]);
134 row.fe = std::stoi(trim(fields[2]));
135
136 m_rows.push_back(std::move(row));
137 }
138
139 ATH_MSG_INFO("Loaded " << m_rows.size() << " CSV rows from " << resolvedCsv);
140 return StatusCode::SUCCESS;
141}
142
143std::pair < Identifier, int > ITkPixelCsvWaferIdAlg::waferId(const CsvRow& row) const {
144 ATH_MSG_DEBUG("waferId lookup for SP chain " << row.spChain
145 << ", module " << row.md << ", FE " << row.fe);
146
147 //SP chain is like G-IS-L05-R05-A-SP2
148 std::vector<std::string> spChain_cur = parseSPChain(row.spChain);
149
150 int bec = barrel_ec(spChain_cur);
151 int ld = layer_disk(spChain_cur);
152 int phi = phi_module(spChain_cur, row.md, row.fe );
153 int eta = eta_module(spChain_cur, row.md, row.fe );
154 int fe_n = feID(spChain_cur, row.fe );
155
156 return std::pair< Identifier, int > (m_pixIdHelper->wafer_id(bec, ld, phi, eta), fe_n);
157}
158
159std::string ITkPixelCsvWaferIdAlg::trim(const std::string& input) {
160 const auto begin = input.find_first_not_of(" \t\r\n");
161 if (begin == std::string::npos) {
162 return "";
163 }
164
165 const auto end = input.find_last_not_of(" \t\r\n");
166 return input.substr(begin, end - begin + 1);
167}
168
169std::vector<std::string> ITkPixelCsvWaferIdAlg::splitCsvLine(const std::string& line) {
170 std::vector<std::string> fields;
171 std::stringstream ss(line);
172 std::string field;
173
174 while (std::getline(ss, field, ',')) {
175 fields.push_back(field);
176 }
177
178 return fields;
179}
180
181std::vector<std::string> ITkPixelCsvWaferIdAlg::parseSPChain(const std::string& spChain) {
182 std::vector<std::string> elements;
183 std::stringstream ss(spChain);
184 std::string element;
185
186 while (std::getline(ss, element, '-')) {
187 elements.push_back(element);
188 }
189
190 return elements;
191}
192
193
194int ITkPixelCsvWaferIdAlg::barrel_ec(const std::vector<std::string>& spchain) const {
195
196 if (spchain[1] == "IS" &&
197 (spchain[2] == "L0" || spchain[2] == "L1") &&
198 spchain.at(3)[0] != 'R') { // inner flat barrel
199 return 0;
200 }
201 else if (spchain[1] == "OB" &&
202 (spchain[2] == "L2" || spchain[2] == "L3" ||
203 spchain[2] == "L4") &&
204 (spchain.at(3)[0] == 'B')) { // Outer flat barrel has 3 layers
205 return 0;
206 }
207 else{
208 //Need to calculat the side sign because eta is always positive.
209 std::string sideAC = spchain[4];
210 if(sideAC != "A" && sideAC != "C"){
211 sideAC = spchain[5];
212 }
213 int side = (sideAC == "A")? 1 : -1; // A for side pos, C for side neg
214 return side*2; // endcap is +2 or -2 - this includes barrel rings, in offline they are treated as endcap
215 }
216}
217
218int ITkPixelCsvWaferIdAlg::layer_disk(const std::vector<std::string>& spchain) const {
219 int b_ec = barrel_ec(spchain);
220 if( b_ec == 0 ){ // flat barrel
221 return spchain.at(2)[1] - '0';
222 }
223 else{ // endcap and barrel rings - all considered as 'endcap' disks
224 if (spchain[2] == "L01" &&
225 (spchain.at(5) == "SP1" || spchain.at(5) == "SP3")) { // barrel vertical small combined rings, disk 0
226 return 0;
227 }
228 else if (spchain[2] == "L01" &&
229 (spchain.at(5) == "SP2" || spchain.at(5) == "SP4")) { // barrel vertical large combined rings, disk 2
230 return 2;
231 }
232 else if(spchain[1] == "OB" && (spchain[2] == "L2" || //OB inclined rings, disks 3, 5, 7
233 spchain[2] == "L3" ||
234 spchain[2] == "L4") ){
235 return (2* ((spchain.at(2))[1] -'0') - 1);
236 }
237 else if(spchain[1] == "IS" && spchain[2] == "L05"){
238 return 1; // end-cap rings, inner system, disk 1
239 }
240 else if(spchain[1] == "IS" && spchain[2] == "L1"){
241 return 2; // end-cap rings, inner system, layer 2
242 }
243 else if(spchain[1] == "EC"){ //outer end-cap
244 return 2* (spchain.at(2)[1]-'0'); // disks 4, 6, 8
245 }
246 else{
247 ATH_MSG_WARNING("Bad values in layer_disk function, return -9999");
248 return -9999;
249 }
250 }
251}
252
253int ITkPixelCsvWaferIdAlg::phi_module(const std::vector<std::string>& spchain, const std::string& mod, int fe ) const {
254
255 int b_ec = barrel_ec(spchain);
256 int ld = layer_disk(spchain);
257
258 if( b_ec == 0 ){ // flat barrel
259 std::string phi_str = (spchain.at(3)).substr(1,2);
260 if(ld == 0 || ld ==1 ){ //inner system flat barrel
261 return std::stoi(phi_str) - 1;
262 }
263 else{ //outer flat barrel
264 int phi = std::stoi(phi_str) - 1 ;
265 phi = (mod[2] == 'T') ? 2*phi + 1 : 2*phi; //(TOCHECK)
266 return phi;
267 }
268 }
269 else{ // endcap and barrel rings - all considered as disks
270 if (spchain[2] == "L01" &&
271 (spchain.at(5) == "SP1" || spchain.at(5) == "SP3")) { // barrel vertical small combined rings, disk 0
272 std::string sp_str(1, (spchain.at(5)[2])); // SP=1 and SP=3 alternate in phi
273 if(sp_str == "1"){
274 return 6 * (stoi(mod) - 1 ) + 2 * (fe - 1); // probably wrong offset, TOCHECK
275 }
276 else if(sp_str == "3"){
277 return 6 * (stoi(mod) - 1 ) + 2 * (fe - 1) + 1; // probably wrong offset, TOCHECK
278 }
279 else{
280 ATH_MSG_WARNING("Bad input for phi_module,return -9999 ");
281 return -9999;
282 }
283 }
284 else if (spchain[2] == "L01" &&
285 (spchain.at(5) == "SP2" || spchain.at(5) == "SP4")) {
286 // barrel vertical large combined rings (quad modules), disk 2
287 std::string sp_str(1, spchain.at(5)[2]); // SP=2 and SP=4 alternate in phi
288 if(sp_str == "2"){
289 return 2 * (stoi(mod) - 1 ) ; // probably wrong offset, TODO need to revisit
290 }
291 else if(sp_str == "4"){
292 return 2 * (stoi(mod) - 1 ) + 1; // probably wrong offset, TODO need to revisit
293 }
294 else{
295 ATH_MSG_WARNING("Bad input for phi_module,return -9999 ");
296 return -9999;
297 }
298 }
299 //barrel inclined rings
300 else if(ld == 3 || ld == 5 || ld ==7){ //OB inclined rings, disks 3, 5, 7
301 std::string phi_str = mod.substr(3,2);
302 int phi = std::stoi(phi_str);
303 return phi;
304 }
305 else if(ld == 1){ //end-cap intermediate rings, inner system, disk 1 - triplets: one module per FE /!\ 0-17
306 return 6 * (stoi(mod) - 1 ) + 2 * (fe - 1); // probably wrong offset, TODO need to revisit
307 }
308 else if(ld == 2){ // end-cap rings, inner system, layer 2 // 0-19
309 std::string sp_str(1, spchain.at(5)[2]); // SP=1 and SP=2 alternate in phi
310 if(sp_str == "1"){
311 return 2 * (stoi(mod) - 1 ) ; // probably wrong offset, TODO need to revisit
312 }
313 else if(sp_str == "2"){
314 return 2 * (stoi(mod) - 1 ) + 1; // probably wrong offset, TODO need to revisit
315 }
316 //return stoi(mod) * fe;
317 }
318 else if(ld == 4 || ld == 6 || ld ==8){ //Outer EC disks 4, 6, 8
319 std::string phi_str = mod.substr(2,2);
320 int phi = std::stoi(phi_str);
321 return phi;
322 }
323 else{
324 ATH_MSG_WARNING("Bad input for phi_module,return -9999 ");
325 return -9999;
326 }
327 }
328 return -9999;
329}
330
331
332int ITkPixelCsvWaferIdAlg::eta_module(const std::vector<std::string>& spchain, const std::string& mod, int fe) const {
333 int b_ec = barrel_ec(spchain);
334 int ld = layer_disk(spchain);
335 int side = (spchain[4] == "A") ? 1 : -1; // A for side pos, C for side neg
336
337 if( b_ec == 0 ){ // flat barrel
338 if(ld ==0){ //triplets, one front-end is considered as one module
339 return side * (3 * (std::stoi(mod) -1) + fe );
340 }
341 else if(ld == 1){
342 return side * std::stoi(mod);
343 }
344 else if(ld < 5){
345 std::string eta_str(1, mod[4]);
346 int eta = std::stoi(eta_str);
347 return side * eta;
348 }
349 else{
350 ATH_MSG_WARNING("Bad layer for flat barrel: " << ld);
351 return -9999;
352 }
353 }
354 //barrel rings and end caps - all considered as disks
355 else{
356 if(spchain[2] == "L01"){ // barrel vertical small and large combined rings, disk 0
357 std::string eta_str = (spchain.at(3)).substr(1,2);
358 return std::stoi(eta_str);
359 }
360 else if(ld == 3 || ld == 5 || ld ==7){ //OB inclined rings, disks 3, 5, 7
361 std::string eta_str = (spchain.at(3)).substr(1,2);
362 return std::stoi(eta_str) - 1 ;
363 }
364 else if(ld == 1){ //end-cap rings, inner system, disk 1 (L05) - triplets: one module per FE
365 std::string eta_str = (spchain.at(3)).substr(1,2);
366 return std::stoi(eta_str) - 1;
367 }
368 else if(ld == 2){ // end-cap rings, inner system, disk 2 - eta from 15 to 22
369 std::string eta_str = (spchain.at(3)).substr(1,2);
370 return std::stoi(eta_str) + 14 ;
371 }
372 else if(ld == 4 || ld == 6 || ld ==8){ //Outer EC disks 4, 6, 8
373 std::string eta_str = (spchain.at(3)).substr(1,2);
374 return std::stoi(eta_str) - 1 ;
375 }
376 else{
377 ATH_MSG_WARNING("Bad input for eta_module,return -9999 ");
378 return -9999;
379 }
380 }
381 return -9999;
382}
383
384
385int ITkPixelCsvWaferIdAlg::feID(const std::vector<std::string>& spchain, int fe) const {
386 int ld = layer_disk(spchain);
387 if(ld < 2){ //triplets
388 return 0;
389 }
390 else{ // quads: need to calculate properly
391 return fe-1;
392 }
393
394}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::pair< std::vector< unsigned int >, bool > res
static Double_t ss
This is an Identifier helper class for the Pixel subdetector.
#define x
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
virtual StatusCode initialize() override
virtual StatusCode execute(const EventContext &ctx) const override
static std::string trim(const std::string &input)
std::atomic< bool > m_done
static std::vector< std::string > splitCsvLine(const std::string &line)
std::vector< CsvRow > m_rows
int phi_module(const std::vector< std::string > &spchain, const std::string &mod, int fe) const
Gaudi::Property< std::string > m_outputFile
static std::vector< std::string > parseSPChain(const std::string &spChain)
int feID(const std::vector< std::string > &spchain, int fe) const
Gaudi::Property< std::string > m_csvFile
int barrel_ec(const std::vector< std::string > &spchain) const
std::pair< Identifier, int > waferId(const CsvRow &row) const
int eta_module(const std::vector< std::string > &spchain, const std::string &mod, int fe) const
ITkPixelCsvWaferIdAlg(const std::string &name, ISvcLocator *pSvcLocator)
int layer_disk(const std::vector< std::string > &spchain) const
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)