ATLAS Offline Software
Loading...
Searching...
No Matches
StripGmxInterface.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "StripGmxInterface.h"
6
8#include <GaudiKernel/GaudiException.h>
16
20#include <GeoModelRead/ReadGeoModel.h>
21#include <GeoModelKernel/GeoFullPhysVol.h>
22#include <optional>
23
24
25
26namespace
27{
28 constexpr int SCT_HitIndex{1};
29 const std::string becStr{"barrel_endcap"};
30 const std::string layerStr{"layer_wheel"};
31 const std::string etaStr{"eta_module"};
32 const std::string phiStr{"phi_module"};
33 const std::string sideStr{"side"};
34 //
35 std::optional<InDetDD::SiDetectorDesign::Axis>
36 direction(std::string_view axisStr){
37 if (axisStr == "x") {
39 }
40 if (axisStr == "y") {
42 }
43 if (axisStr == "z") {
45 }
46 return std::nullopt;
47 }
48}
49
50
51namespace InDetDD
52{
53
54namespace ITk
55{
56
58 SiCommonItems *commonItems,
59 WaferTree *waferTree)
60 : AthMessaging("StripGmxInterface"),
61 m_detectorManager(detectorManager),
62 m_commonItems(commonItems),
63 m_waferTree(waferTree)
64{}
65
66
67int StripGmxInterface::sensorId(std::map<std::string, int> &index) const
68{
69 //
70 // Return the Simulation HitID (nothing to do with "ATLAS Identifiers" aka "Offline Identifiers"
71
72 int hitIdOfWafer = SiHitIdHelper::GetHelper()->buildHitId(SCT_HitIndex,
73 index[becStr],
74 index[layerStr],
75 index[etaStr],
76 index[phiStr],
77 index[sideStr]);
78
79 ATH_MSG_DEBUG("Index list: " << index[becStr] << " " << index[layerStr] << " "
80 << index[etaStr] << " " << index[phiStr] << " " << index[sideStr]);
81 ATH_MSG_DEBUG("hitIdOfWafer = " << std::hex << hitIdOfWafer << std::dec);
82 ATH_MSG_DEBUG(" bec = " << SiHitIdHelper::GetHelper()->getBarrelEndcap(hitIdOfWafer)
83 << " lay = " << SiHitIdHelper::GetHelper()->getLayerDisk(hitIdOfWafer)
84 << " eta = " << SiHitIdHelper::GetHelper()->getEtaModule(hitIdOfWafer)
85 << " phi = " << SiHitIdHelper::GetHelper()->getPhiModule(hitIdOfWafer)
86 << " side = " << SiHitIdHelper::GetHelper()->getSide(hitIdOfWafer));
87 return hitIdOfWafer;
88}
89
90int StripGmxInterface::splitSensorId(std::map<std::string, int> &index,
91 std::pair<std::string, int> &extraIndex,
92 std::map<std::string, int> &updatedIndex ) const
93{
94 //
95 // Return the Simulation HitID (nothing to do with "ATLAS Identifiers" aka "Offline Identifiers"
96
97 if (extraIndex.first != etaStr) {
98 ATH_MSG_FATAL("Base Identifier: " << index[becStr] << " " << index[layerStr] << " "
99 << index[etaStr] << " " << index[phiStr] << " " << index[sideStr]);
100 ATH_MSG_FATAL("Attempting to split "<< extraIndex.second);
101 ATH_MSG_FATAL("Only splitting of eta_module supported for ITk strips!!!");
102 return -1;
103 }
104
105 //add the required amount to the requested field
106 updatedIndex = index;
107 updatedIndex[extraIndex.first] += extraIndex.second;
108
109 int hitIdOfWafer = SiHitIdHelper::GetHelper()->buildHitId(SCT_HitIndex,
110 index[becStr],
111 index[layerStr],
112 index[etaStr] + extraIndex.second,
113 index[phiStr],
114 index[sideStr]);
115
116 ATH_MSG_DEBUG("Index list: " << index[becStr] << " " << index[layerStr] << " "
117 << index[etaStr] + extraIndex.second << " " << index[phiStr] << " " << index[sideStr]);
118 ATH_MSG_DEBUG("hitIdOfWafer = " << std::hex << hitIdOfWafer << std::dec);
119 ATH_MSG_DEBUG(" bec = " << SiHitIdHelper::GetHelper()->getBarrelEndcap(hitIdOfWafer)
120 << " lay = " << SiHitIdHelper::GetHelper()->getLayerDisk(hitIdOfWafer)
121 << " eta = " << SiHitIdHelper::GetHelper()->getEtaModule(hitIdOfWafer)
122 << " phi = " << SiHitIdHelper::GetHelper()->getPhiModule(hitIdOfWafer)
123 << " side = " << SiHitIdHelper::GetHelper()->getSide(hitIdOfWafer));
124 return hitIdOfWafer;
125}
126
127
128void StripGmxInterface::addSensorType(const std::string& clas,
129 const std::string& typeName,
130 const std::map<std::string, std::string>& parameters)
131{
132 ATH_MSG_DEBUG("addSensorType called for class " << clas << ", typeName " << typeName);
133
134 if (clas == "SiStripBox") {
135 makeSiStripBox(typeName, parameters);
136 } else if (clas == "StereoAnnulus") {
137 makeStereoAnnulus(typeName, parameters);
138 } else { // To-do: add "Annulus"
139 ATH_MSG_ERROR("addSensorType: unrecognised sensor class: " << clas);
140 ATH_MSG_ERROR("No sensor design created");
141 }
142}
143
144
145void StripGmxInterface::makeSiStripBox(const std::string &typeName,
146 const std::map<std::string, std::string> &parameters)
147{
148 //
149 // Get all parameters.
150 //
151
152 double thickness{0.320};
153 int readoutSide{1};
155 int nRows{1};
156 double pitch{0.080};
157 int nStrips{1280}; // Per row
158 double length{25.0};
159
160 std::string carrierString;
161 getParameter(typeName, parameters, "carrierType", carrierString);
162 if (carrierString == "electrons") {
163 carrier = InDetDD::electrons;
164 } else if (carrierString == "holes") {
165 carrier = InDetDD::holes;
166 } else {
167 throw GaudiException("Parameter carrierType should be electrons or holes for " + typeName,
168 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
169 }
170
171 std::string readoutSideString;
172 getParameter(typeName, parameters, "readoutSide", readoutSideString);
173 if (readoutSideString == "+") {
174 readoutSide = 1;
175 } else if (readoutSideString == "-") {
176 readoutSide = -1;
177 } else {
178 throw GaudiException("Parameter readoutSide should be + or - for " + typeName,
179 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
180 }
181
182 std::string fieldDirectionString;
183 getParameter(typeName, parameters, "fieldDirection", fieldDirectionString);
184 auto fieldDirectionOptional = direction(fieldDirectionString);
185 if (!fieldDirectionOptional){
186 throw GaudiException("Parameter fieldDirection should be x, y, or z for " + typeName,
187 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
188 }
189
190 std::string stripDirectionString;
191 getParameter(typeName, parameters, "stripDirection", stripDirectionString);
192 auto stripDirectionOptional = direction(stripDirectionString);
193 if (!stripDirectionOptional){
194 throw GaudiException("Parameter stripDirection should be x, y, or z for " + typeName,
195 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
196 }
197 const auto stripDirection = *stripDirectionOptional;
198 const auto fieldDirection = *fieldDirectionOptional;
199 getParameter(typeName, parameters, "thickness", thickness);
200 getParameter(typeName, parameters, "nRows", nRows);
201 getParameter(typeName, parameters, "nStrips", nStrips);
202 getParameter(typeName, parameters, "pitch", pitch);
203 getParameter(typeName, parameters, "stripLength", length);
204
205 //At the moment, we'd only ever want StripBarrel for this detector type, so throw a WARNING if it differs
206 //However, in future this may be different, so implementing the functionality to set this anyway
208 int detectorTypeEnum = 0;
209 if (checkParameter(typeName, parameters, "detectorType", detectorTypeEnum)) {
210 if (detectorTypeEnum == 4) detectorType = InDetDD::StripBarrel;
211 else ATH_MSG_WARNING("Non-strip barrel type set for strip box DetectorElement - is this intended?");
212 }
213
214
215 //
216 // Make Sensor Design and add to DetectorManager
217 //
218
219 int splitLevel{};
220 if (checkParameter(typeName, parameters, "splitLevel", splitLevel)) {
221 // start from middle of first strip row
222 double initZShift = length * (-static_cast<double>(splitLevel) * 0.5 + 0.5);
223
224 // now, the "Mother"...
225 // This is a container for all the other designs, to allow navigation
226 // between the different rows on a simulated sensor in the HITS
227 auto motherDesign = std::make_unique<StripBoxDesign>(stripDirection,
228 fieldDirection,
229 thickness,
230 readoutSide,
231 carrier,
232 nRows,
233 nStrips,
234 pitch,
235 length,
236 detectorType);
237
238 for (int i = 0; i< splitLevel; i++) {
239 for (int side : {0,1}) { //need different additional shift transform per side...
240 int sign = (side == 0) ? 1 : -1; //...because shift in different direction per side
241 double zShift = sign * (initZShift + (i * length));
242
243 auto design = std::make_unique<StripBoxDesign>(stripDirection,
244 fieldDirection,
245 thickness,
246 readoutSide,
247 carrier,
248 1, //single row
249 nStrips,
250 pitch,
251 length,
252 detectorType,
253 zShift);
254
255 design->setMother(motherDesign.get());
256 motherDesign->addChildDesign(i,design.get());
257
258 std::string splitName = typeName + "_" + std::to_string(i) + "_" + std::to_string(side);
259 m_geometryMap[splitName] = m_detectorManager->addDesign(std::move(design));
260 }
261 }
262
263 // Add to map for addSensor routine
264 m_motherMap[typeName] = motherDesign.get();
265 m_detectorManager->addMotherDesign(std::move(motherDesign));
266 } else { // no split level
267 auto design = std::make_unique<StripBoxDesign>(stripDirection,
268 fieldDirection,
269 thickness,
270 readoutSide,
271 carrier,
272 nRows,
273 nStrips,
274 pitch,
275 length,
276 detectorType);
277
278 // Add to map for addSensor routine
279 m_geometryMap[typeName] = design.get();
280 m_detectorManager->addDesign(std::move(design));
281 }
282}
283
284
285void StripGmxInterface::makeStereoAnnulus(const std::string &typeName,
286 const std::map<std::string, std::string> &parameters)
287{
288 //
289 // Get all parameters.
290 //
291 int readoutSide{1};
292
294 double thickness{0.320};
295 double stereoAngle{0.020};
296 double centreR{500.};
297 int nRows{1};
298 std::vector <int> nStrips;
299 std::vector<double> phiPitch;
300 std::vector<double> startR;
301 std::vector<double> endR;
302 bool usePC{false}; // initialise to false
303
304 std::string carrierString;
305 getParameter(typeName, parameters, "carrierType", carrierString);
306 if (carrierString == "electrons") {
307 carrier = InDetDD::electrons;
308 } else if (carrierString == "holes") {
309 carrier = InDetDD::holes;
310 } else {
311 throw GaudiException("Parameter carrierType should be electrons or holes for " + typeName,
312 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
313 }
314
315 std::string readoutSideString;
316 getParameter(typeName, parameters, "readoutSide", readoutSideString);
317 if (readoutSideString == "+") {
318 readoutSide = 1;
319 } else if (readoutSideString == "-") {
320 readoutSide = -1;
321 } else {
322 throw GaudiException("Parameter readoutSide should be + or - for " + typeName,
323 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
324 }
325
326 std::string fieldDirectionString;
327 getParameter(typeName, parameters, "fieldDirection", fieldDirectionString);
328 auto fieldDirectionOptional = direction(fieldDirectionString);
329 if (!fieldDirectionOptional){
330 throw GaudiException("Parameter fieldDirection should be x, y, or z for " + typeName,
331 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
332 }
333 const auto fieldDirection = *fieldDirectionOptional;
334 //
335 std::string stripDirectionString;
336 getParameter(typeName, parameters, "stripDirection", stripDirectionString);
337 auto stripDirectionOptional = direction(stripDirectionString);
338 if (!stripDirectionOptional){
339 throw GaudiException("Parameter stripDirection should be x, y, or z for " + typeName,
340 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
341 }
342 const auto stripDirection = *stripDirectionOptional;
343 getParameter(typeName, parameters, "thickness", thickness);
344 getParameter(typeName, parameters, "stereoAngle", stereoAngle);
345 getParameter(typeName, parameters, "centreR", centreR);
346 getParameter(typeName, parameters, "nRows", nRows);
347
348 getParameters(typeName, parameters, "nStrips", nStrips);
349 if (nStrips.size() != static_cast<size_t>(nRows)) {
350 throw GaudiException("Wrong number of nStrips " + std::to_string(nStrips.size()) + " " + typeName,
351 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
352 }
353
354 getParameters(typeName, parameters, "phiPitch", phiPitch);
355 if (phiPitch.size() != static_cast<size_t>(nRows)) {
356 throw GaudiException("Wrong number of pitches " + std::to_string(phiPitch.size()) + " " + typeName,
357 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
358 }
359
360 getParameters(typeName, parameters, "startR", startR);
361 if (startR.size() != static_cast<size_t>(nRows)) {
362 throw GaudiException("Wrong number of startRs " + std::to_string(startR.size()) + " " + typeName,
363 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
364 }
365
366 getParameters(typeName, parameters, "endR", endR);
367 if (endR.size() != static_cast<size_t>(nRows)) {
368 throw GaudiException("Wrong number of endRs " + std::to_string(endR.size()) + " " + typeName,
369 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
370 }
371
372 if (checkParameter(typeName, parameters, "usePC", usePC)) ATH_MSG_INFO("Using polar co-ordinates for strip stereo annulus modules");
373
374
375 //At the moment, we'd only ever want StripEndcap for this detector type, so throw a WARNING if it differs
376 //However, in future this may be different, so implementing the functionality to set this anyway
378 int detectorTypeEnum = 0;
379 if (checkParameter(typeName, parameters, "detectorType", detectorTypeEnum)) {
380 if (detectorTypeEnum == 5) detectorType = InDetDD::StripEndcap;
381 else ATH_MSG_WARNING("Non-strip endcap type set for strip annulus DetectorElement - is this intended?");
382 }
383
384 //
385 // Make Sensor Design and add it to the DetectorManager
386 //
387 std::vector<int> singleRowStrips;
388 std::vector<double> singleRowPitch;
389 std::vector<double> singleRowMinR;
390 std::vector<double> singleRowMaxR;
391
392 int splitLevel{};
393 if (checkParameter(typeName, parameters, "splitLevel", splitLevel)) {
394 // now the mother...
395 auto motherDesign = std::make_unique<StripStereoAnnulusDesign>(stripDirection,
396 fieldDirection,
397 thickness,
398 readoutSide,
399 carrier,
400 nRows,
401 nStrips,
402 phiPitch,
403 startR,
404 endR,
405 stereoAngle,
406 centreR,
407 usePC,
408 detectorType);
409
410 for (int i = 0; i < splitLevel; i++) {
411 singleRowStrips.clear();
412 singleRowPitch.clear();
413 singleRowMinR.clear();
414 singleRowMaxR.clear();
415
416 singleRowStrips.push_back(nStrips[i]);
417 singleRowPitch.push_back(phiPitch[i]);
418 singleRowMinR.push_back(startR[i]);
419 singleRowMaxR.push_back(endR[i]);
420 //"shift" radius for correcting local<->global transforms
421 //centreR remains the relevant radius for bounds/stereo calculations
422 //since the strip frame is defined per wafer not per row
423 double thisCentreR = (singleRowMinR[0] + singleRowMaxR[0] ) *0.5;
424
425 auto design = std::make_unique<StripStereoAnnulusDesign>(stripDirection,
426 fieldDirection,
427 thickness,
428 readoutSide,
429 carrier,
430 1,//this design represents a single row by definition
431 singleRowStrips,
432 singleRowPitch,
433 singleRowMinR,
434 singleRowMaxR,
435 stereoAngle,
436 thisCentreR,
437 centreR,
438 usePC,
439 detectorType);
440
441 // Add to map for addSensor routine
442 std::string splitName = typeName + "_" + std::to_string(i);
443 design->setMother(motherDesign.get());
444 motherDesign->addChildDesign(i,design.get());
445
446 m_geometryMap[splitName] = design.get();
447 m_detectorManager->addDesign(std::move(design));
448
449 }
450
451 // finally, declare to the manager (now becomes const)
452 m_motherMap[typeName] = motherDesign.get();
453 m_detectorManager->addMotherDesign(std::move(motherDesign));
454
455 } else {
456 auto design = std::make_unique<StripStereoAnnulusDesign>(stripDirection,
457 fieldDirection,
458 thickness,
459 readoutSide,
460 carrier,
461 nRows,
462 nStrips,
463 phiPitch,
464 startR,
465 endR,
466 stereoAngle,
467 centreR,
468 usePC,
469 detectorType);
470
471 m_geometryMap[typeName] = design.get();
472 m_detectorManager->addDesign(std::move(design));
473 }
474}
475
476void StripGmxInterface::addSplitSensor(const std::string& typeName,
477 std::map<std::string, int> &index,
478 std::pair<std::string, int> &extraIndex,
479 int /* hitIdOfWafer */,
480 GeoVFullPhysVol *fpv,
481 int /* splitLevel */)
482{
483 std::map<std::string, int> updatedIndex;
484 splitSensorId(index,extraIndex,updatedIndex);
485 int splitIndex = extraIndex.second;
486 //
487 // Get the ATLAS "Offline" wafer identifier
488 //
489 const SCT_ID *sctIdHelper = dynamic_cast<const SCT_ID *> (m_commonItems->getIdHelper());
490 if (not sctIdHelper){
491 ATH_MSG_ERROR("Failed dynamic cast to SCT_ID in StripGmxInterface::addSplitSensor");
492 return;
493 }
494 Identifier id = sctIdHelper->wafer_id(updatedIndex[becStr],
495 updatedIndex[layerStr],
496 updatedIndex[phiStr],
497 updatedIndex[etaStr],
498 updatedIndex[sideStr]);
499 IdentifierHash hashId = sctIdHelper->wafer_hash(id);
500 //
501 // Now do our best to check if this is a valid id. If either the gmx file is wrong, or the xml file
502 // defining the allowed id's is wrong, you can get disallowed id's. These cause a crash later
503 // if allowed through. To do the check, we ask for the hash-id of this id. Invalid ids give a
504 // special invalid hash-id (0xFFFFFFFF). But we don't exit the run, to help debug things quicker.
505 //
506 if (!hashId.is_valid()) {
507 ATH_MSG_ERROR("Invalid id for sensitive wafer " << typeName << " volume with indices");
508 for (const auto& [key, value] : index) {
509 msg() << MSG::ERROR << key << " = " << value << "; ";
510 }
511 msg() << MSG::ERROR << endmsg;
512 ATH_MSG_ERROR("Refusing to make it into a sensitive element. Incompatible gmx and identifier-xml files.");
513 return;
514 }
515
516 //
517 // Create the detector element and add to the DetectorManager
518 //
519 std::string splitTypeName = typeName + "_" + std::to_string(splitIndex);
520 if (updatedIndex[becStr] == 0) { // only barrel-type have side dependence
521 splitTypeName += "_" + std::to_string(updatedIndex[sideStr]);
522 }
523
524 auto it = m_geometryMap.find(splitTypeName);
525 if(it == m_geometryMap.end() || it->second == nullptr) {
526 ATH_MSG_ERROR("addSplitSensor: Error: Readout sensor type " << typeName << " not found.");
527 throw std::runtime_error("readout sensor type " + typeName + " not found.");
528 }
529 const SiDetectorDesign *design = it->second;
530
531 m_detectorManager->addDetectorElement(new SiDetectorElement(id, design, fpv, m_commonItems));
532
533 //
534 // Build up a map-structure for numerology
535 //
536 Wafer wafer((unsigned int) hashId);
537 std::string errorMessage("");
538 if (!m_waferTree->add(updatedIndex[becStr],
539 updatedIndex[layerStr],
540 updatedIndex[etaStr],
541 updatedIndex[phiStr],
542 updatedIndex[sideStr],
543 wafer,
544 errorMessage)) {
545 ATH_MSG_ERROR(errorMessage);
546 }
547
548 return;
549}
550
551
552void StripGmxInterface::addSensor(const std::string& typeName,
553 std::map<std::string, int> &index,
554 int /* sensitiveId */,
555 GeoVFullPhysVol *fpv)
556{
557 //
558 // Get the ATLAS "Offline" wafer identifier
559 //
560 const SCT_ID *sctIdHelper = dynamic_cast<const SCT_ID *> (m_commonItems->getIdHelper());
561 if (not sctIdHelper){
562 ATH_MSG_ERROR("StripGmxInterface::addSensor: ID helper pointer could not be cast to SCT_ID *");
563 return;
564 }
565 Identifier id = sctIdHelper->wafer_id(index[becStr],
566 index[layerStr],
567 index[phiStr],
568 index[etaStr],
569 index[sideStr]);
570 IdentifierHash hashId = sctIdHelper->wafer_hash(id);
571 //
572 // Now do our best to check if this is a valid id. If either the gmx file is wrong, or the xml file
573 // defining the allowed id's is wrong, you can get disallowed id's. These cause a crash later
574 // if allowed through. To do the check, we ask for the hash-id of this id. Invalid ids give a
575 // special invalid hash-id (0xFFFFFFFF). But we don't exit the run, to help debug things quicker.
576 //
577 if (!hashId.is_valid()) {
578 ATH_MSG_ERROR("Invalid id for sensitive module " << typeName << " volume with indices");
579 for (const auto& [key, value] : index) {
580 msg() << MSG::ERROR << key << " = " << value << "; ";
581 }
582 msg() << MSG::ERROR << endmsg;
583 ATH_MSG_ERROR("Refusing to make it into a sensitive element. Incompatible gmx and identifier-xml files.");
584 return;
585 }
586
587 //
588 // Create the detector element and add to the DetectorManager
589 //
590 auto it = m_geometryMap.find(typeName);
591 if(it == m_geometryMap.end() || it->second == nullptr) {
592 ATH_MSG_ERROR("addSensor: Error: Readout sensor type " << typeName << " not found.");
593 throw std::runtime_error("readout sensor type " + typeName + " not found.");
594 }
595 const SiDetectorDesign *design = it->second;
596
597 m_detectorManager->addDetectorElement(new SiDetectorElement(id, design, fpv, m_commonItems));
598
599 //
600 // Build up a map-structure for numerology
601 //
602 Wafer wafer((unsigned int) hashId);
603 std::string errorMessage("");
604 if (!m_waferTree->add(index[becStr],
605 index[layerStr],
606 index[etaStr],
607 index[phiStr],
608 index[sideStr],
609 wafer,
610 errorMessage)) {
611 ATH_MSG_ERROR(errorMessage);
612 }
613
614 return;
615}
616
617
619 std::map<std::string, int> &index,
620 GeoVFullPhysVol *fpv,
621 GeoAlignableTransform *transform)
622{
623 ATH_MSG_DEBUG("addAlignable called");
624 //
625 // Get the offline-id appropriate to the level (0 = wafer, 1 = module, 2 = wheel/cylinder, 3 = part, i.e barrel or an endcap)
626 //
627 const SCT_ID *sctIdHelper = dynamic_cast<const SCT_ID *> (m_commonItems->getIdHelper());
628 if (not sctIdHelper){
629 ATH_MSG_ERROR("Failed dynamic_cast to SCT_ID in StripGmxInterface::addAlignable");
630 return;
631 }
632 Identifier id;
633 switch (level) {
634 case 0:
635 id = sctIdHelper->wafer_id(index[becStr],
636 index[layerStr],
637 index[phiStr],
638 index[etaStr],
639 index[sideStr]);
640 break;
641 case 1:
642 id = sctIdHelper->wafer_id(index[becStr],
643 index[layerStr],
644 index[phiStr],
645 index[etaStr],
646 0);
647 break;
648 case 2:
649 id = sctIdHelper->wafer_id(index[becStr],
650 index[layerStr],
651 0,
652 0,
653 0);
654 break;
655 case 3:
656 id = sctIdHelper->wafer_id(index[becStr],
657 0,
658 0,
659 0,
660 0);
661 break;
662 default:
663 throw GaudiException("Unknown level " + std::to_string(level) + " for alignment in addAlignable",
664 "StripGmxInterface::addAlignable", StatusCode::FAILURE);
665 break;
666 }
667 m_detectorManager->addAlignableTransform(level, id, transform, fpv);
668}
669
671 std::map<std::string, int> &index,
672 std::pair<std::string, int> &extraIndex,
673 GeoVFullPhysVol *fpv,
674 GeoAlignableTransform *transform)
675{
676 ATH_MSG_DEBUG("addSplitAlignable called");
677 //
678 // Get the offline-id appropriate to the level (0 = wafer, 1 = module, 2 = wheel/cylinder, 3 = part, i.e barrel or an endcap)
679 //
680 std::map<std::string, int> updatedIndex;
681 splitSensorId(index,extraIndex,updatedIndex);
682
683 const SCT_ID *sctIdHelper = dynamic_cast<const SCT_ID *> (m_commonItems->getIdHelper());
684 if (not sctIdHelper){
685 ATH_MSG_ERROR("Failed dynamic_cast to SCT_ID in StripGmxInterface::addSplitAlignable");
686 return;
687 }
688 Identifier id;
689 switch (level) {
690 case 0:
691 id = sctIdHelper->wafer_id(updatedIndex[becStr],
692 updatedIndex[layerStr],
693 updatedIndex[phiStr],
694 updatedIndex[etaStr],
695 updatedIndex[sideStr]);
696 break;
697 case 1:
698 id = sctIdHelper->wafer_id(updatedIndex[becStr],
699 updatedIndex[layerStr],
700 updatedIndex[phiStr],
701 updatedIndex[etaStr],
702 0);
703 break;
704 case 2:
705 id = sctIdHelper->wafer_id(updatedIndex[becStr],
706 updatedIndex[layerStr],
707 0,
708 0,
709 0);
710 break;
711 case 3:
712 id = sctIdHelper->wafer_id(updatedIndex[becStr],
713 0,
714 0,
715 0,
716 0);
717 break;
718 default:
719 throw GaudiException("Unknown level " + std::to_string(level) + " for alignment in addSplitAlignable",
720 "StripGmxInterface::addSplitAlignable", StatusCode::FAILURE);
721 break;
722 }
723 m_detectorManager->addAlignableTransform(level, id, transform, fpv);
724}
725
726void StripGmxInterface::buildReadoutGeometryFromSqlite(IRDBAccessSvc * rdbAccessSvc,GeoModelIO::ReadGeoModel* sqlreader){
727
728 IRDBRecordset_ptr stereoAnnulus = rdbAccessSvc->getRecordsetPtr("StereoAnnulus","");
729 const std::array<std::string,13> stereoAnnulusParamNames{"thickness","carrierType","readoutSide","fieldDirection","stripDirection","stereoAngle","centreR","nRows","splitLevel","nStrips","phiPitch","startR","endR"};
730
731 if(stereoAnnulus->size() !=0){
732 for (unsigned int iR =0;iR<stereoAnnulus->size();iR++){
733 std::map<std::string,std::string> stereoAnnulusMap;
734 for(const std::string& paramName:stereoAnnulusParamNames){
735 stereoAnnulusMap[paramName] = (*stereoAnnulus)[iR]->getString(paramName);
736 }
737 std::string stereoAnnulusName = (*stereoAnnulus)[iR]->getString("SensorType");
738 makeStereoAnnulus(stereoAnnulusName,stereoAnnulusMap);
739 }
740 }
741 else ATH_MSG_WARNING("Could not retrieve StereoAnnulus table");
742
743 IRDBRecordset_ptr stripBox = rdbAccessSvc->getRecordsetPtr("SiStripBox","");
744 const std::array<std::string,10> stripBoxParamNames{"thickness","carrierType","readoutSide","fieldDirection","stripDirection","nRows","stripLength","splitLevel","nStrips","pitch"};
745
746 if(stripBox->size() !=0){
747 for (unsigned int iR =0;iR<stripBox->size();iR++){
748 std::map<std::string,std::string> stripBoxMap;
749 for(const std::string& paramName:stripBoxParamNames){
750 std::string paramValue = (*stripBox)[iR]->getString(paramName);
751 stripBoxMap[paramName] = std::move(paramValue);
752 }
753 std::string stripBoxName = (*stripBox)[iR]->getString("SensorType");
754 makeSiStripBox(stripBoxName,stripBoxMap);
755 }
756 }
757 else ATH_MSG_WARNING("Could not retrieve SiStripBox table");
758
759 //Now, loop over the FullPhysVols and create the SiDetectorElements (including splitting where needed)
760 //lots of string parsing...
761 const std::array<std::string,5> fields{becStr,layerStr,phiStr,etaStr,sideStr};
762 //First, find which name the tables are in the file under (depends upon the plugin used to create the input file)
763 //sort these in order of precedence - ITkPlugin, then ITkStripPlugin, then GeoModelXMLPlugin
764 const std::array<std::string,3> publishers{"ITk","ITkStrip","GeoModelXML"};
765 //The below is a map of string keys which will contain all the Identifier/DetElement relevant info, and the associated FullPhysVol
766 // (once filled from the published table in the SQLite)
767 std::map<std::string, GeoFullPhysVol*> mapFPV;
768 for (auto & iPub : publishers){
769 //setting the "checkTable" option to true, so that an empty map will be returned if not found and we can try then next one
770 mapFPV = sqlreader->getPublishedNodes<std::string, GeoFullPhysVol*>(iPub,true);
771 if (!mapFPV.empty()) {
772 ATH_MSG_DEBUG("Using FPV tables from publisher "<<iPub);
773 break;
774 }
775 }
776 if (mapFPV.empty()) ATH_MSG_ERROR("Could not find any FPV tables under the expected names: "<<publishers);
777 std::pair<std::string, int> extraIndex{etaStr, 0}; // eventually specify in XML the field to split in?
778 for (const auto&[fullPhysVolInfoString, fullPhysVolPointer] : mapFPV){
779 //find the name of the corresponding detector design type
780 size_t startRG = fullPhysVolInfoString.find("RG_");
781 if(startRG==std::string::npos){
782 ATH_MSG_DEBUG("GeoFullPhysVol "<<fullPhysVolInfoString<<" does not have the expected format. Skipping");
783 continue;
784 }
785 std::string typeName = fullPhysVolInfoString.substr(startRG);
786 std::map<std::string, int> index;
787 for (const std::string & field:fields){
788 size_t first = fullPhysVolInfoString.find(field+"_");
789 size_t last = fullPhysVolInfoString.find('_',first+field.size()+1);//start looking only after end of first delimiter (plus 1 for the "_" appended) ends
790 if(first==std::string::npos || last==std::string::npos){
791 ATH_MSG_DEBUG("Could not extract "<<field<<" from "<<fullPhysVolInfoString<<". Skipping");
792 continue;
793 }
794 std::string strNew = fullPhysVolInfoString.substr(first+field.size()+1,last-(first+field.size()+1));
795 index[field] = std::stoi(strNew);
796 }
797 //now check if we need to split
798 size_t splitPos = fullPhysVolInfoString.find("split_");
799
800 if(splitPos!=std::string::npos){
801 size_t last = fullPhysVolInfoString.find('_',splitPos+6);//"split_" is 6 characters
802 std::string strNew = fullPhysVolInfoString.substr(splitPos+6,last-(splitPos+6));
803 int splitLevel = std::stoi(strNew);
804 for(int i=0;i<splitLevel;i++){
805 extraIndex.second = i;
806 addSplitSensor(typeName,index,extraIndex,0,fullPhysVolPointer,splitLevel);
807 }
808 }
809 else addSensor(typeName,index,0,fullPhysVolPointer);
810 }
811}
812
813} // namespace ITk
814} // namespace InDetDD
#define endmsg
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double length(const pvec &v)
Definition of the abstract IRDBAccessSvc interface.
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
int sign(int a)
MsgStream & msg() const
The standard message stream.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
IRDBAccessSvc is an abstract interface to the athena service that provides the following functionalit...
virtual IRDBRecordset_ptr getRecordsetPtr(std::string_view node, std::string_view tag, std::string_view tag2node="", std::string_view connName="ATLASDD")=0
Provides access to the Recordset object containing HVS-tagged data.
virtual unsigned int size() const =0
This is a "hash" representation of an Identifier.
constexpr bool is_valid() const
void addSplitSensor(const std::string &typeName, std::map< std::string, int > &index, std::pair< std::string, int > &extraIndex, int sequentialId, GeoVFullPhysVol *fpv, int splitLevel) override final
void addSensor(const std::string &typeName, std::map< std::string, int > &index, int sequentialId, GeoVFullPhysVol *fpv) override final
void buildReadoutGeometryFromSqlite(IRDBAccessSvc *rdbAccessSvc, GeoModelIO::ReadGeoModel *sqlreader)
virtual int splitSensorId(std::map< std::string, int > &index, std::pair< std::string, int > &extraIndex, std::map< std::string, int > &updatedIndex) const override final
std::map< std::string, const SCT_ModuleSideDesign * > m_motherMap
void makeStereoAnnulus(const std::string &typeName, const std::map< std::string, std::string > &parameters)
virtual void addSplitAlignable(int level, std::map< std::string, int > &index, std::pair< std::string, int > &extraIndex, GeoVFullPhysVol *fpv, GeoAlignableTransform *transform) override final
void makeSiStripBox(const std::string &typeName, const std::map< std::string, std::string > &parameters)
std::map< std::string, const SiDetectorDesign * > m_geometryMap
SCT_DetectorManager * m_detectorManager
StripGmxInterface(SCT_DetectorManager *detectorManager, SiCommonItems *commonItems, WaferTree *waferTree)
virtual void addSensorType(const std::string &clas, const std::string &typeName, const std::map< std::string, std::string > &parameters) override final
virtual int sensorId(std::map< std::string, int > &index) const override final
virtual void addAlignable(int level, std::map< std::string, int > &index, GeoVFullPhysVol *fpv, GeoAlignableTransform *transform) override final
Dedicated detector manager extending the functionality of the SiDetectorManager with dedicated SCT in...
Helper class to concentrate common items, such as the pointer to the IdHelper, the lorentzAngle tool ...
Base class for the detector design classes for Pixel and SCT.
Class to hold geometrical description of a silicon detector element.
This is an Identifier helper class for the SCT subdetector.
Definition SCT_ID.h:68
IdentifierHash wafer_hash(const Identifier &wafer_id) const
wafer hash from id - optimized
Definition SCT_ID.h:487
Identifier wafer_id(int barrel_ec, int layer_disk, int phi_module, int eta_module, int side) const
For a single side of module.
Definition SCT_ID.h:459
int buildHitId(const int, const int, const int, const int, const int, const int) const
static const SiHitIdHelper * GetHelper()
Message Stream Member.
const Amg::Vector3D & direction() const
Method to retrieve the direction at the Intersection.
Definition index.py:1