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* Author: Fabrice Balli, fabrice.balli at cern.ch
5* Date: 04/2026
6* Description: ITkPix front end chip identifier calculation
7
8*/
9
12
13
14#include "GaudiKernel/EventContext.h"
16
17#include <fstream>
18#include <sstream>
19#include <limits>
20#include <bit>
21
22
24 ISvcLocator* pSvcLocator)
25 : AthReentrantAlgorithm(name, pSvcLocator)
26{
27}
28
30 ATH_MSG_INFO("Initializing CsvWaferId algorithm");
31 ATH_CHECK(detStore()->retrieve(m_pixIdHelper, "PixelID"));
32 ATH_MSG_INFO("Retrieved PixelID helper");
34 ATH_MSG_INFO("Loaded CSV file");
35 return StatusCode::SUCCESS;
36}
37
38StatusCode ITkPixelCsvWaferIdAlg::execute(const EventContext& ctx) const {
39
40 ATH_CHECK ( ctx.valid() );
41
42 if (m_done.load(std::memory_order_acquire)) {
43 return StatusCode::SUCCESS;
44 }
45
46 bool expected = false;
47 if (!m_done.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
48 return StatusCode::SUCCESS;
49 }
50
51 ATH_MSG_INFO("Executing CsvWaferId algorithm");
52
53 std::ofstream output(m_outputFile.value());
54 if (!output.good()) {
55 ATH_MSG_FATAL("Could not open wafer ID output file: " << m_outputFile.value());
56 return StatusCode::FAILURE;
57 }
58 output << "DetectorResourceID,TrueDetectorResourceID,FELIX Card Name,Uplink Pin,DMA buffer,SourceID\n";
59
60 std::vector<int> dma_buffer_vec = DmaBuffer();
61
62 for (size_t i = 0; i < m_rows.size(); ++i) {
63 const CsvRow& row = m_rows[i];
64 const auto w_and_fe_id = waferId(row);
65 const Identifier& id = std::get<0>(w_and_fe_id);
66 const int fe = std::get<1>(w_and_fe_id);
67 //Keep this in case we need a dedicated function to get the online ID one day
68 //std::bitset<32> onlineId = std::get<2>(w_and_fe_id);
69 std::bitset<32> onlineId = std::bitset<32>("00001000000000000000000000000000");
70 const std::string waferId_str = id.get_identifier32().getString();
71 const auto bec = m_pixIdHelper->barrel_ec(id);
72 const auto ld = m_pixIdHelper->layer_disk(id);
73 const auto phi = m_pixIdHelper->phi_module(id);
74 const auto eta = m_pixIdHelper->eta_module(id);
75
76 std::bitset<32> sID = sourceID( parseSPChain(row.spChain), row.md, row.fe, row.flx_card_device, dma_buffer_vec[i]);
77
78 std::string x = waferId_str.substr(0, waferId_str.length() - 2 );
79 std::stringstream ss;
80 ss << std::hex << x;
81 unsigned n;
82 ss >> n;
83 std::bitset<32> b(n);
84 // Check bit position
85 bitcheck(b, 0, 23, "DetResID: Wafer ID");
86
87 std::bitset<32> febits = std::bitset<32>(fe);
88 febits <<= 30; //shift left by 30 bits
89
90 // Check bit position
91 bitcheck(febits, 30, 31, "DetResID: Chip ID");
92
93 b |= febits;
94
95 if (msgLvl(MSG::DEBUG)) {
96 output << waferId_str << "\t"
97 << x << "\t"
98 << b.to_string() << "\t"
99 << febits.to_string() << "\t"
100 << std::dec << bec << "\t"
101 << ld << "\t"
102 << phi << "\t"
103 << eta << "\t"
104 << std::hex<< onlineId.to_ulong() << "\t";
105 }
106 //convert back to hex
107 std::stringstream res;
108 res << std::hex << std::uppercase << b.to_ulong();
109 // keep this, might be useful later
110 //output << res.str() << "\n";
111 output << std::hex << (b| onlineId).to_ulong() << ","
112 << (b| onlineId).to_ulong() << ","
113 << row.flx_card_device << ","
114 << row.fiber << ","
115 << dma_buffer_vec[i] << ","
116 << sID.to_ulong() << "\n";
117
118 }
119 output.close();
120 ATH_MSG_INFO("Wrote " << m_rows.size() << " wafer IDs to " << m_outputFile.value());
121
122 // Perform sanity checks
123 ATH_MSG_INFO("Performing sanity checks of " << m_outputFile.value());
125
126 return StatusCode::SUCCESS;
127}
128
130 const std::string resolvedCsv = PathResolver::find_file(m_csvFile.value(), "DATAPATH");
131 if (resolvedCsv.empty()) {
132 ATH_MSG_FATAL("Could not resolve CSV file: " << m_csvFile.value());
133 return StatusCode::FAILURE;
134 }
135 std::ifstream input(resolvedCsv);
136 if (!input.good()) {
137 ATH_MSG_FATAL("Could not open CSV file: " << resolvedCsv);
138 return StatusCode::FAILURE;
139 }
140 const std::string resolvedFelixCsv = PathResolver::find_file(m_FelixCardFile.value(), "DATAPATH");
141 if (resolvedFelixCsv.empty()) {
142 ATH_MSG_FATAL("Could not resolve FELIX CSV file: " << m_FelixCardFile.value());
143 return StatusCode::FAILURE;
144 }
145 std::ifstream inputFelix(resolvedFelixCsv);
146 if (!inputFelix.good()) {
147 ATH_MSG_FATAL("Could not open FELIX CSV file: " << resolvedFelixCsv);
148 return StatusCode::FAILURE;
149 }
150
151 //Load and store module CSV sheet
152 m_rows.clear();
153
154 ATH_MSG_INFO("Loading FE chips CSV");
155 std::string line;
156 bool firstLine = true;
157 while (std::getline(input, line)) {
158 if (line.empty()) {
159 continue;
160 }
161
162 if (firstLine) {
163 firstLine = false;
164 continue;
165 }
166 const std::vector<std::string> fields = splitCsvLine(line);
167 if (fields.size() < 5) {
168 ATH_MSG_WARNING("Skipping malformed Chips CSV line: " << line);
169 continue;
170 }
171
172 CsvRow row;
173 row.spChain = trim(fields[0]);
174 row.md = trim(fields[1]);
175 row.fe = std::stoi(trim(fields[2]));
176 row.flx_card_device = trim(fields[3]);
177 row.fiber = static_cast<unsigned int>(std::stoul(trim(fields[4])));
178
179 m_rows.push_back(std::move(row));
180 }
181
182 ATH_MSG_INFO("Loaded " << m_rows.size() << " Front-End Chips CSV rows from " << resolvedCsv);
183
184
185 //Load and store FELIX CSV sheet
186
187
188 m_felix_rows.clear();
189
190 ATH_MSG_INFO("Loading FELIX CSV");
191 firstLine = true;
192 while (std::getline(inputFelix, line)) {
193 if (line.empty()) {
194 continue;
195 }
196 if (firstLine) {
197 firstLine = false;
198 continue;
199 }
200 const std::vector<std::string> fields = splitCsvLine(line);
201 if (fields.size() < 3) {
202 ATH_MSG_WARNING("Skipping malformed FELIX CSV line: " << line);
203 continue;
204 }
205
206 FelixCsvRow row;
207 row.host = trim(fields[0]);
208 row.card1 = (unsigned int) std::stoi(trim(fields[1]));
209 row.card2 = (unsigned int) std::stoi(trim(fields[2]));
210 m_felix_rows.push_back(std::move(row));
211 }
212
213 ATH_MSG_INFO("Loaded " << m_felix_rows.size() << " FELIX CSV rows from " << resolvedFelixCsv);
214 return StatusCode::SUCCESS;
215}
216
217std::tuple< Identifier, int, std::bitset<32> > ITkPixelCsvWaferIdAlg::waferId(const CsvRow& row) const {
218 ATH_MSG_DEBUG("waferId lookup for SP chain " << row.spChain
219 << ", module " << row.md << ", FE " << row.fe);
220
221 //SP chain is like G-IS-L05-R05-A-SP2
222 std::vector<std::string> spChain_cur = parseSPChain(row.spChain);
223
224 int bec = barrel_ec(spChain_cur);
225 int ld = layer_disk(spChain_cur);
226 int phi = phi_module(spChain_cur, row.md, row.fe );
227 int eta = eta_module(spChain_cur, row.md, row.fe );
228 int fe_n = feID(spChain_cur, row.fe );
229 std::bitset<32> online_id = onlineId(spChain_cur, row.md, row.fe);
230
231 return std::make_tuple(m_pixIdHelper->wafer_id(bec, ld, phi, eta), fe_n, online_id);
232}
233
234std::string ITkPixelCsvWaferIdAlg::trim(const std::string& input) {
235 const auto begin = input.find_first_not_of(" \t\r\n");
236 if (begin == std::string::npos) {
237 return "";
238 }
239
240 const auto end = input.find_last_not_of(" \t\r\n");
241 return input.substr(begin, end - begin + 1);
242}
243
244std::vector<std::string> ITkPixelCsvWaferIdAlg::splitCsvLine(const std::string& line) {
245 std::vector<std::string> fields;
246 std::stringstream ss(line);
247 std::string field;
248
249 while (std::getline(ss, field, ',')) {
250 fields.push_back(field);
251 }
252 return fields;
253}
254
255std::vector<std::string> ITkPixelCsvWaferIdAlg::parseSPChain(const std::string& spChain) {
256 std::vector<std::string> elements;
257 std::stringstream ss(spChain);
258 std::string element;
259
260 while (std::getline(ss, element, '-')) {
261 elements.push_back(element);
262 }
263
264 return elements;
265}
266
267
268int ITkPixelCsvWaferIdAlg::barrel_ec(const std::vector<std::string>& spchain) const {
269
270 if (spchain[1] == "IS" &&
271 (spchain[2] == "L0" || spchain[2] == "L1") &&
272 spchain.at(3)[0] != 'R') { // inner flat barrel
273 return 0;
274 }
275 else if (spchain[1] == "OB" &&
276 (spchain[2] == "L2" || spchain[2] == "L3" ||
277 spchain[2] == "L4") &&
278 (spchain.at(3)[0] == 'B')) { // Outer flat barrel has 3 layers
279 return 0;
280 }
281 else{
282 //Need to calculat the side sign because eta is always positive.
283 std::string sideAC = spchain[4];
284 if(sideAC != "A" && sideAC != "C"){
285 sideAC = spchain[5];
286 }
287 int side = (sideAC == "A")? 1 : -1; // A for side pos, C for side neg
288 return side*2; // endcap is +2 or -2 - this includes barrel rings, in offline they are treated as endcap
289 }
290}
291
292int ITkPixelCsvWaferIdAlg::layer_disk(const std::vector<std::string>& spchain) const {
293 int b_ec = barrel_ec(spchain);
294 if( b_ec == 0 ){ // flat barrel
295 return spchain.at(2)[1] - '0';
296 }
297 else{ // endcap and barrel rings - all considered as 'endcap' disks
298 if (spchain[2] == "L01" &&
299 (spchain.at(5) == "SP1" || spchain.at(5) == "SP3")) { // barrel vertical small combined rings, disk 0
300 ATH_MSG_DEBUG("added layer 0 barrel vertical combined ring: SP chain "
301 << spchain[1]<< spchain[2]<< spchain[3]<< spchain[4]<< spchain[5]);
302 return 0;
303 }
304 else if (spchain[2] == "L01" &&
305 (spchain.at(5) == "SP2" || spchain.at(5) == "SP4")) { // barrel vertical large combined rings, disk 2
306 return 2;
307 }
308 else if(spchain[1] == "OB" && (spchain[2] == "L2" || //OB inclined rings, disks 3, 5, 7
309 spchain[2] == "L3" ||
310 spchain[2] == "L4") ){
311 return (2* ((spchain.at(2))[1] -'0') - 1);
312 }
313 else if(spchain[1] == "IS" && spchain[2] == "L05"){
314 return 1; // end-cap rings, inner system, disk 1
315 }
316 else if(spchain[1] == "IS" && spchain[2] == "L1"){
317 return 2; // end-cap rings, inner system, layer 2
318 }
319 else if(spchain[1] == "EC"){ //outer end-cap
320 return 2* (spchain.at(2)[1]-'0'); // disks 4, 6, 8
321 }
322 else{
323 ATH_MSG_WARNING("Bad values in layer_disk function, return -9999");
324 return -9999;
325 }
326 }
327}
328
329int ITkPixelCsvWaferIdAlg::phi_module(const std::vector<std::string>& spchain, const std::string& mod, int fe ) const {
330
331 int b_ec = barrel_ec(spchain);
332 int ld = layer_disk(spchain);
333
334 if( b_ec == 0 ){ // flat barrel
335 std::string phi_str = (spchain.at(3)).substr(1,2);
336 if(ld == 0 || ld ==1 ){ //inner system flat barrel
337 return std::stoi(phi_str) - 1;
338 }
339 else{ //outer flat barrel
340 int phi = std::stoi(phi_str) - 1 ;
341 phi = (mod[2] == 'T') ? 2*phi + 1 : 2*phi;
342 return phi;
343 }
344 }
345 else{ // endcap and barrel rings - all considered as disks
346 if (ld == 0) { // barrel vertical small combined rings, disk 0
347 std::string sp_str(1, (spchain.at(5)[2])); // SP=1 and SP=3 alternate in phi
348 if(sp_str == "1"){
349 ATH_MSG_DEBUG( "return phi = " << 6 * (stoi(mod) - 1 ) + 2 * (fe - 1));
350 return 6 * (stoi(mod) - 1 ) + 2 * (fe - 1); // probably wrong offset, TOCHECK
351 }
352 else if(sp_str == "3"){
353 ATH_MSG_DEBUG( "return phi = " << 6 * (stoi(mod) - 1 ) + 2 * (fe - 1) + 1);
354 return 6 * (stoi(mod) - 1 ) + 2 * (fe - 1) + 1; // probably wrong offset, TOCHECK
355 }
356 else{
357 ATH_MSG_WARNING("Bad input for phi_module,return -9999 ");
358 return -9999;
359 }
360 }
361 else if (spchain[2] == "L01" &&
362 (spchain.at(5) == "SP2" || spchain.at(5) == "SP4")) {
363 // barrel vertical large combined rings (quad modules), disk 2
364 std::string sp_str(1, spchain.at(5)[2]); // SP=2 and SP=4 alternate in phi
365 if(sp_str == "2"){
366 return 2 * (stoi(mod) - 1 ) ; // probably wrong offset, TODO need to revisit
367 }
368 else if(sp_str == "4"){
369 return 2 * (stoi(mod) - 1 ) + 1; // probably wrong offset, TODO need to revisit
370 }
371 else{
372 ATH_MSG_WARNING("Bad input for phi_module,return -9999 ");
373 return -9999;
374 }
375 }
376 //barrel inclined rings
377 else if(ld == 3 || ld == 5 || ld ==7){ //OB inclined rings, disks 3, 5, 7
378 std::string phi_str = mod.substr(2,2);
379 int phi = std::stoi(phi_str)-1;
380 return phi;
381 }
382 else if(ld == 1){ //end-cap intermediate rings, inner system, disk 1 - triplets: one module per FE /!\ 0-17
383 std::string sp_str(1, spchain.at(5)[2]); // SP=2 and SP=4 alternate in phi
384 if(sp_str == "1"){
385 return 6 * (stoi(mod) - 1 ) + 2 * (fe - 1) ; // probably wrong offset, TODO need to revisit
386 }
387 else if(sp_str == "2"){
388 return 6 * (stoi(mod) - 1 ) + 2 * (fe - 1) + 1; // probably wrong offset, TODO need to revisit
389 }
390 else{
391 ATH_MSG_WARNING("Bad input for phi_module,return -9999 ");
392 return -9999;
393 }
394 }
395 else if(ld == 2){ // end-cap rings, inner system, layer 2 // 0-19
396 std::string sp_str(1, spchain.at(5)[2]); // SP=1 and SP=2 alternate in phi
397 if(sp_str == "1"){
398 return 2 * (stoi(mod) - 1 ) ; // probably wrong offset, TODO need to revisit
399 }
400 else if(sp_str == "2"){
401 return 2 * (stoi(mod) - 1 ) + 1; // probably wrong offset, TODO need to revisit
402 }
403 }
404 else if(ld == 4 || ld == 6 || ld ==8){ //Outer EC disks 4, 6, 8
405 std::string phi_str = mod.substr(2,2);
406 int phi = std::stoi(phi_str) - 1;
407 return phi;
408 }
409 else{
410 ATH_MSG_WARNING("Bad input for phi_module,return -9999 ");
411 return -9999;
412 }
413 }
414 return -9999;
415}
416
417
418int ITkPixelCsvWaferIdAlg::eta_module(const std::vector<std::string>& spchain, const std::string& mod, int fe) const {
419 int b_ec = barrel_ec(spchain);
420 int ld = layer_disk(spchain);
421 int side = (spchain[4] == "A") ? 1 : -1; // A for side pos, C for side neg
422
423 if( b_ec == 0 ){ // flat barrel
424 if(ld ==0){ //triplets, one front-end is considered as one module
425 return side * (3 * (std::stoi(mod) -1) + fe );
426 }
427 else if(ld == 1){
428 return side * std::stoi(mod);
429 }
430 else if(ld < 5){
431 std::string eta_str(1, mod[4]);
432 int eta = std::stoi(eta_str);
433 return side * eta;
434 }
435 else{
436 ATH_MSG_WARNING("Bad layer for flat barrel: " << ld);
437 return -9999;
438 }
439 }
440 //barrel rings and end caps - all considered as disks
441 else{
442 if(spchain[2] == "L01"){ // barrel vertical small and large combined rings, disk 0
443 std::string eta_str = (spchain.at(3)).substr(1,2);
444 return std::stoi(eta_str)-1;
445 }
446 else if(ld == 3 || ld == 5 || ld ==7){ //OB inclined rings, disks 3, 5, 7
447 std::string eta_str = (spchain.at(3)).substr(1,2);
448 return std::stoi(eta_str) - 1 ;
449 }
450 else if(ld == 1){ //end-cap rings, inner system, disk 1 (L05) - triplets: one module per FE
451 std::string eta_str = (spchain.at(3)).substr(1,2);
452 return std::stoi(eta_str) - 1;
453 }
454 else if(ld == 2){ // end-cap rings, inner system, disk 2 - eta from 15 to 22
455 std::string eta_str = (spchain.at(3)).substr(1,2);
456 return std::stoi(eta_str) + 14 ;
457 }
458 else if(ld == 4 || ld == 6 || ld ==8){ //Outer EC disks 4, 6, 8
459 std::string eta_str = (spchain.at(3)).substr(1,2);
460 return std::stoi(eta_str) - 1 ;
461 }
462 else{
463 ATH_MSG_WARNING("Bad input for eta_module,return -9999 ");
464 return -9999;
465 }
466 }
467 return -9999;
468}
469
470
471int ITkPixelCsvWaferIdAlg::feID(const std::vector<std::string>& spchain, int fe) const {
472 int b_ec = barrel_ec(spchain);
473 int ld = layer_disk(spchain);
474 if(ld ==0 || (ld == 1 && std::abs(b_ec) == 2 ) ){ //triplets
475 return 0;
476 }
477 else{ // quads
478 return fe-1;
479 }
480
481}
482
483
484std::bitset<32> ITkPixelCsvWaferIdAlg::onlineId(const std::vector<std::string>& spchain, const std::string& mod, int fe, bool legacy) const {
485 // onlineID = chipID (4b) chipID ON/OFF (1b) RD53C/BCID (1b)
486 // we don't need this function for the moment but it is still evolving
487 std::bitset<32> febits(0);
488 int ld = layer_disk(spchain);
489 int fe_id = feID(spchain, fe);
490 int b_ec = barrel_ec(spchain);
491 int etamod = eta_module(spchain, mod, fe);
492
493 //these bits encode the merging scheme of modules
494 if( b_ec == 0 ){ // barrel
495 if(ld == 1 || ld ==2 ){ //L1, L2 flat, 4 to 2 merging
496 if(fe_id < 2){
497 febits = legacy ? std::bitset<32>(0x30000000) : std::bitset<32>(0x10000000) ;
498 }
499 else{
500 febits = legacy ? std::bitset<32>(0xC0000000) : std::bitset<32>(0x20000000) ;
501 }
502 }
503 if(ld == 3 || ld == 4 ){ //L3, L4 flat, 4 to 1 merging
504 febits = legacy ? std::bitset<32>(0xF0000000) : std::bitset<32>(0x30000000) ;
505 }
506 }
507 else{
508 if(ld == 3){ // Barrel ring L2
509 if(fe_id < 2){
510 febits = legacy ? std::bitset<32>(0x30000000) : std::bitset<32>(0x10000000) ;
511 }
512 else{
513 febits = legacy ? std::bitset<32>(0xC0000000) : std::bitset<32>(0x20000000) ;
514 }
515 }
516 if(ld == 5 || ld ==7){ // Barrel rings L3, L4
517 febits = legacy ? std::bitset<32>(0xF0000000) : std::bitset<32>(0x30000000) ;
518 }
519 if(ld == 4 && etamod < 5){ // first half of EC L2
520 if(fe_id < 2){
521 febits = legacy ? std::bitset<32>(0x30000000) : std::bitset<32>(0x10000000) ;
522 }
523 else{
524 febits = legacy ? std::bitset<32>(0xC0000000) : std::bitset<32>(0x20000000) ;
525 }
526 }
527 if(ld == 6){ // EC L3
528 if(fe_id < 2){
529 febits = legacy ? std::bitset<32>(0x30000000) : std::bitset<32>(0x10000000) ;
530 }
531 else{
532 febits = legacy ? std::bitset<32>(0xC0000000) : std::bitset<32>(0x20000000) ;
533 }
534 }
535 if(ld == 8 && etamod < 7){ // EC L4, 1-7
536 febits = legacy ? std::bitset<32>(0xF0000000) : std::bitset<32>(0x30000000) ;
537 }
538 if(ld == 8 && etamod >= 7){ // EC L4, 8-9
539 if(fe_id < 2){
540 febits = legacy ? std::bitset<32>(0x30000000) : std::bitset<32>(0x10000000) ;
541 }
542 else{
543 febits = legacy ? std::bitset<32>(0xC0000000) : std::bitset<32>(0x20000000) ;
544 }
545 }
546 }
547 //add the chip ID ON/OFF (1b, set to 1) and BCID (1b, set to 0) bits
548 febits |= std::bitset<32>("00000010000000000000000000000000");
549 return febits;
550}
551
552
553std::vector<int> ITkPixelCsvWaferIdAlg::DmaBuffer() const {
554 std::vector<int> dmaNumbers;
555 dmaNumbers.reserve(m_rows.size());
556
557 size_t i = 0;
558 while (i < m_rows.size()) {
559 const std::string& card = m_rows[i].flx_card_device;
560 size_t j = i;
561 unsigned int minFiber = std::numeric_limits<unsigned int>::max();
562 for (; j < m_rows.size() ; ++j) {
563 if(m_rows[j].flx_card_device != card){
564 continue;
565 }
566 if (m_rows[j].fiber > 0 && m_rows[j].fiber < minFiber){
567 minFiber = m_rows[j].fiber;
568 }
569 }
570
571 if (minFiber == std::numeric_limits<unsigned int>::max()) {
572 // no valid fiber found in this block, assign 9
573 for (size_t k = i; k < j; ++k){
574 dmaNumbers.push_back(9);
575 }
576 i = j;
577 continue;
578 }
579
580 // assign DMA groups based on minFiber, groups of 3 fibers -> DMA 0..3
581 for (size_t k = i; k < j; ++k) {
582 int dma = 0;
583 if (m_rows[k].fiber >= minFiber) {
584 const int offset = static_cast<int>(m_rows[k].fiber) - static_cast<int>(minFiber);
585 // 3 fibers per DMA buffer except for L0 flat barrel (4 lanes FE --> 2 fibers)
586 int b_ec = barrel_ec(parseSPChain(m_rows[k].spChain));
587 int ld = layer_disk(parseSPChain(m_rows[k].spChain));
588 if(b_ec == 0 && ld ==0){
589 dma = offset / 2;
590 }
591 else{
592 dma = offset / 3;
593 }
594 }
595 if (dma < 0){
596 ATH_MSG_WARNING("Assigned DMA buffer goes negative: " << dma);
597 }
598 if (dma > 3){
599 ATH_MSG_WARNING("Assigned DMA buffer goes higher than 3: for card "
600 << card << " ; nDMAs =" << dma << ", line " << k );
601
602 }
603 dmaNumbers.push_back(std::move(dma));
604 }
605 i = j;
606 }
607 return dmaNumbers;
608}
609
610
611std::bitset<32> ITkPixelCsvWaferIdAlg::sourceID(const std::vector<std::string>& spchain, const std::string& mod, int fe, const std::string& flx, const unsigned int dma) const {
612 // ((subdetector ID) << 16) |((FELIX card ID) << 8) | ((FELIX device ID) << 7) | ((DMA buffer number) << 5)
613
614 int b_ec = barrel_ec(spchain);
615 int ld = layer_disk(spchain);
616 int etamod = eta_module(spchain, mod, fe);
617
618 std::bitset<32> b(0);
619 std::bitset<32> subdet = subDetID(b_ec, ld, etamod);
620 subdet <<= 16 ; //shift left by 16 bits
621
622 bitcheck(subdet, 16, 23, "SourceID : SubDetectorID " );
623
624 std::vector<std::string> flx_card_device = splitFLX_card_device(flx);
625 auto hostIndex = flxHost((unsigned int) std::stoi(flx_card_device[0]));
626 std::bitset<32> flx_host = std::bitset<32>(hostIndex.first);
627 flx_host <<= 8; //shift left by 8 bits
628 bitcheck(flx_host, 8, 15, "SourceID : FELIX host " );
629
630 std::bitset<32> flxCard = std::bitset<32>(hostIndex.second);
631 flxCard <<= 5; //shift left by 5 bits
632 bitcheck(flxCard, 5, 5, "SourceID : FELIX card " );
633
634 std::bitset<32> flxDev = std::bitset<32>(std::stoi(flx_card_device[1]) - 1 );
635 flxDev <<= 4; //shift left by 6 bits
636 bitcheck(flxDev, 4, 4, "SourceID : card device " );
637
638 std::bitset<32> dma_b = std::bitset<32>(dma);
639 //dma_b <<= 4; //shift left by 4 bits
640 bitcheck(dma_b, 0, 1, "SourceID : DMA buffer index " );
641
642 b = subdet | flx_host | flxCard | flxDev | dma_b;
643 return b;
644}
645
646
647
648std::vector<std::string> ITkPixelCsvWaferIdAlg::splitFLX_card_device(const std::string& s) const {
649 std::vector<std::string> fields;
650 std::stringstream ss(s);
651 std::string field;
652
653 while (std::getline(ss, field, '.')) {
654 fields.push_back(field);
655 }
656 if (fields.size() !=2){
657 ATH_MSG_ERROR("Wrong FLX_card_device input: " << s);
658 }
659 if (fields[1] !="1" && fields[1] !="2" ){
660 ATH_MSG_ERROR("Wrong FLX device input: " << fields[1]);
661 }
662 return fields;
663}
664
665
666std::bitset<32> ITkPixelCsvWaferIdAlg::subDetID(int barrel_endcap, int layer_disk, int eta) const {
667 if(barrel_endcap == 0){
668 if(layer_disk < 2){
669 if(eta > 0 ){
670 return std::bitset<32>(0xa1); // Inner barrel A
671 }
672 else{
673 return std::bitset<32>(0xa2); // Inner barrel C
674 }
675 }
676 else{
677 if(eta > 0){
678 return std::bitset<32>(0xa3); // Outer Barrel A
679 }
680 else{
681 return std::bitset<32>(0xa4); // Outer Barrel C
682 }
683 }
684 }
685 else if(barrel_endcap == 2){
686 if(layer_disk == 0 || (layer_disk == 2 && eta < 15)){
687 return std::bitset<32>(0xa1); // Inner barrel A
688 }
689 else if(layer_disk == 3 || layer_disk == 5 || layer_disk == 7){
690 return std::bitset<32>(0xa3); // Outer barrel A
691 }
692 else if(layer_disk == 1 || (layer_disk == 2 || eta >=15 ) ){
693 return std::bitset<32>(0xa5); // Inner end-cap A
694 }
695 else if(layer_disk == 4 || layer_disk == 6 || layer_disk == 8){
696 return std::bitset<32>(0xa7); // Outer end-cap A
697 }
698 else{
699 ATH_MSG_ERROR("Wrong barrel_endcap / layer_disk / eta_mod values ");
700 ATH_MSG_ERROR("return subDetectorID =0 " );
701 return std::bitset<32>(0);
702 }
703 }
704 else if(barrel_endcap == -2){
705 if(layer_disk == 0 || (layer_disk == 2 && eta < 15)){
706 return std::bitset<32>(0xa2); // Inner barrel C
707 }
708 else if(layer_disk == 3 || layer_disk == 5 || layer_disk == 7){
709 return std::bitset<32>(0xa4); // Outer barrel C
710 }
711 else if(layer_disk == 1 || (layer_disk == 2 || eta >=15 ) ){
712 return std::bitset<32>(0xa6); // Inner end-cap C
713 }
714 else if(layer_disk == 4 || layer_disk == 6 || layer_disk == 8){
715 return std::bitset<32>(0xa8); // Outer end-cap C
716 }
717 else{
718 ATH_MSG_ERROR("Wrong barrel_endcap / layer_disk / eta_mod values ");
719 ATH_MSG_ERROR("return subDetectorID =0 " );
720 return std::bitset<32>(0);
721 }
722 }
723 else{
724 ATH_MSG_ERROR("Wrong barrel_endcap value: " << barrel_endcap);
725 ATH_MSG_ERROR("return subDetectorID =0 " );
726 return std::bitset<32>(0);
727 }
728
729}
730
731
732const StatusCode ITkPixelCsvWaferIdAlg::sanityCheck(std::string s, bool legacy) const {
733
734 if(legacy){
735 ATH_MSG_INFO("Using old format");
736 }
737
738 std::ifstream fcheck(s);
739 if (!fcheck.good()) {
740 ATH_MSG_FATAL("Could not open output file: " << s);
741 return StatusCode::FAILURE;
742 }
743
744 // Read all rows, fill a vector with the full info
745
746 std::string line;
747 bool firstLine = true;
748 std::vector < OutputCsvRow > rowVec;
749 while (std::getline(fcheck, line)) {
750 if (line.empty()) {
751 continue;
752 }
753 if (firstLine) {
754 firstLine = false;
755 continue;
756 }
757 const std::vector<std::string> fields = splitCsvLine(line);
758 if (fields.size() < 6) {
759 ATH_MSG_WARNING("Skipping malformed Chips CSV line: " << line);
760 continue;
761 }
762 OutputCsvRow row;
763
764 const auto parseHex = [](const std::string& value) -> unsigned int {
765 std::istringstream iss(value);
766 iss >> std::hex;
767 unsigned int parsed = 0;
768 iss >> parsed;
769 return parsed;
770 };
771
772 row.detResId = std::bitset<32>(parseHex(fields[0]));
773 row.tdetResId = std::bitset<32>(parseHex(fields[1]));
774 row.card_dev = fields[2];
775 row.fiber = parseHex(fields[3]);
776 row.dma = std::stoi(fields[4]);
777 row.sourceId = std::bitset<32>(parseHex(fields[5]));
778 rowVec.push_back(std::move(row));
779 line = "";
780 }
781
782 // Now, perform the checks
783 size_t i = 0;
784 std::vector<std::string > cards;
785 while (i < rowVec.size()) {
786 const std::string& card = rowVec[i].card_dev;
787 if(std::find(cards.begin(), cards.end(), card) != cards.end()) {
788 continue; // already checked that FELIX device
789 }
790 cards.push_back(card);
791
792
793 std::map < int, float> fiber_links_map ;
794 std::map < int, int> fiber_dma_map ;
795 int dma_nfiber[4] = {};
796
797 size_t j = i;
798 for (; j < rowVec.size() ; ++j) {
799 if(rowVec[j].card_dev != card){
800 continue;
801 }
802
803 fiber_dma_map[rowVec[j].fiber] = rowVec[j].dma ;
804 // 1. Check that there are <= 12 fibers for one device
805 if(rowVec[j].fiber > 12){
806 ATH_MSG_WARNING("Sanity check of file " << s << " : Bad number of fibers, line: " << j );
807 ATH_MSG_WARNING("Nfiber = " << rowVec[j].fiber);
808 }
809 // Keep it around in case it's needed at some point - format is still evolving
810 /*
811 if(legacy){
812 if( (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0xf0000000) ){
813 fiber_links_map[rowVec[j].fiber] += 0.25;
814 }
815 else if( (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0xc0000000) ||
816 (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0x30000000)) {
817 fiber_links_map[rowVec[j].fiber] += 0.5;
818 }
819 else if( (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0x00000000)) {
820 fiber_links_map[rowVec[j].fiber] += 1;
821 }
822 else{
823 ATH_MSG_WARNING("Sanity check of file " << s << " : Bad Chip ID value in DetResID, line: " << j );
824 }
825 }
826 else{
827 if( (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0x30000000) ){
828 fiber_links_map[rowVec[j].fiber] += 0.25;
829 }
830 else if( (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0x20000000) ||
831 (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0x10000000)) {
832 fiber_links_map[rowVec[j].fiber] += 0.5;
833 }
834 else if( (rowVec[j].detResId & std::bitset<32>(0xf0000000)) == std::bitset<32>(0x00000000)) {
835 fiber_links_map[rowVec[j].fiber] += 1;
836 }
837 else{
838 ATH_MSG_WARNING("Sanity check of file " << s << " : Bad Chip ID value in DetResID, line: " << j );
839 }
840 }
841 */
842 }
843
844 // 2. Check that there are <= 6 lpGBT links per fiber
845 for ( const auto & p : fiber_links_map ) {
846 if(ceilf(p.second) != p.second){
847 ATH_MSG_WARNING("Sanity check of file " << s << " : Card.device = "
848 << card << " ; Fiber " << p.first << "N links = " << p.second );
849 }
850 if( p.second > 6){
851 ATH_MSG_WARNING("More than 6 physical lpGBT links, file " << s << " : Card.device = "
852 << card << " ; Fiber " << p.first << " ; N links = " << p.second );
853 }
854 }
855 // 3. Check that there are <= 3 fibers per DMA buffer
856
857 for ( const auto & p : fiber_dma_map ) {
858
859 if( p.second > 3){
860 ATH_MSG_WARNING("DMA buffer index higher than 3, file " << s << " : Card.device = "
861 << card << " ; DMA " << p.second << " ; fiber = " << p.first );
862 continue;
863 }
864 dma_nfiber[p.second] ++;
865 }
866 for (std::size_t g = 0; g < std::size(dma_nfiber); ++g) {
867 if(dma_nfiber[g] > 3){
868 ATH_MSG_WARNING("More than 3 fibers, file " << s << " : Card.device = "
869 << card << " ; DMA " << g << " ; N fibers = " << dma_nfiber[g] );
870 }
871 }
872 i = j;
873 }
874
875 fcheck.close();
876 return StatusCode::SUCCESS;
877
878}
879
880
881
882
883void ITkPixelCsvWaferIdAlg::bitcheck(std::bitset<32> b, uint32_t lsb_lim, uint32_t msb_lim , std::string_view s) const {
884
885 uint32_t x = static_cast<uint32_t> (b.to_ulong());
886 if(x!=0){
887 uint32_t lsb_used = std::countr_zero(x);
888 uint32_t msb_used = std::bit_width(x) - 1;
889
890 if( (msb_used > msb_lim) || (lsb_used < lsb_lim) ){
891 ATH_MSG_WARNING("Bits used for this ID (" << s << ") are not correctly set");
892 ATH_MSG_WARNING(" MSB used = " << msb_used << " MSB allowed = " << msb_lim);
893 ATH_MSG_WARNING(" LSB used = " << lsb_used << " LSB allowed = " << lsb_lim);
894 ATH_MSG_WARNING("Full bitset = " << b.to_string());
895 }
896 }
897}
898
899
900std::pair <unsigned int, unsigned int> ITkPixelCsvWaferIdAlg::flxHost(unsigned int card) const {
901 auto it1 = std::find_if(m_felix_rows.begin(), m_felix_rows.end(),
902 [card](const FelixCsvRow& p) {
903 return (p.card1 == card);
904 });
905 auto it2 = std::find_if(m_felix_rows.begin(), m_felix_rows.end(),
906 [card](const FelixCsvRow& p) {
907 return (p.card2 == card);
908 });
909 auto it = (it1 != m_felix_rows.end()) ? it1 : ( (it2 != m_felix_rows.end()) ? it2 : m_felix_rows.end());
910 unsigned int Ncard = (it1 != m_felix_rows.end()) ? 0 : ( (it2 != m_felix_rows.end()) ? 1 : 0 );
911 if (it != m_felix_rows.end()) {
912 std::size_t index = it - m_felix_rows.begin();
913 std::string s= m_felix_rows[index].host;
914 //Ex: pc-tdq-ro-pix-is-a-15, need to return 15
915 std::size_t pos = s.rfind('-');
916 return (pos == std::string::npos) ? std::pair <unsigned int, unsigned int>(0,0) : std::pair <unsigned int, unsigned int>(std::stoi(s.substr(pos + 1)), Ncard);
917 }
918 else{
919 ATH_MSG_WARNING("Couldn't find a host for card number " << card << ", returning (0, 0)");
920 return std::pair <unsigned int, unsigned int>(0, 0);
921 }
922}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(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::vector< std::string > splitFLX_card_device(const std::string &s) const
static std::vector< std::string > splitCsvLine(const std::string &line)
void bitcheck(std::bitset< 32 > b, uint32_t lsb_lim, uint32_t msb_lim, std::string_view s="") const
std::vector< int > DmaBuffer() const
std::pair< unsigned int, unsigned int > flxHost(unsigned int card) const
Gaudi::Property< std::string > m_FelixCardFile
const StatusCode sanityCheck(std::string s, bool legacy=false) const
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
std::bitset< 32 > onlineId(const std::vector< std::string > &spchain, const std::string &mod, int fe, bool legacy=false) const
std::vector< FelixCsvRow > m_felix_rows
int barrel_ec(const std::vector< std::string > &spchain) const
std::tuple< Identifier, int, std::bitset< 32 > > waferId(const CsvRow &row) const
std::bitset< 32 > subDetID(int barrel_endcap, int layer_disk, int eta) const
std::bitset< 32 > sourceID(const std::vector< std::string > &spchain, const std::string &mod, int fe, const std::string &flx, const unsigned int dma) 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)
Definition index.py:1