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
23
24
25namespace
26{
27constexpr int SCT_HitIndex{1};
28}
29
30
31namespace InDetDD
32{
33
34namespace ITk
35{
36
38 SiCommonItems *commonItems,
39 WaferTree *waferTree)
40 : AthMessaging("StripGmxInterface"),
41 m_detectorManager(detectorManager),
42 m_commonItems(commonItems),
43 m_waferTree(waferTree)
44{}
45
46
47int StripGmxInterface::sensorId(std::map<std::string, int> &index) const
48{
49 //
50 // Return the Simulation HitID (nothing to do with "ATLAS Identifiers" aka "Offline Identifiers"
51
52 int hitIdOfWafer = SiHitIdHelper::GetHelper()->buildHitId(SCT_HitIndex,
53 index["barrel_endcap"],
54 index["layer_wheel"],
55 index["eta_module"],
56 index["phi_module"],
57 index["side"]);
58
59 ATH_MSG_DEBUG("Index list: " << index["barrel_endcap"] << " " << index["layer_wheel"] << " "
60 << index["eta_module"] << " " << index["phi_module"] << " " << index["side"]);
61 ATH_MSG_DEBUG("hitIdOfWafer = " << std::hex << hitIdOfWafer << std::dec);
62 ATH_MSG_DEBUG(" bec = " << SiHitIdHelper::GetHelper()->getBarrelEndcap(hitIdOfWafer)
63 << " lay = " << SiHitIdHelper::GetHelper()->getLayerDisk(hitIdOfWafer)
64 << " eta = " << SiHitIdHelper::GetHelper()->getEtaModule(hitIdOfWafer)
65 << " phi = " << SiHitIdHelper::GetHelper()->getPhiModule(hitIdOfWafer)
66 << " side = " << SiHitIdHelper::GetHelper()->getSide(hitIdOfWafer));
67 return hitIdOfWafer;
68}
69
70int StripGmxInterface::splitSensorId(std::map<std::string, int> &index,
71 std::pair<std::string, int> &extraIndex,
72 std::map<std::string, int> &updatedIndex ) const
73{
74 //
75 // Return the Simulation HitID (nothing to do with "ATLAS Identifiers" aka "Offline Identifiers"
76
77 if (extraIndex.first != "eta_module") {
78 ATH_MSG_FATAL("Base Identifier: " << index["barrel_endcap"] << " " << index["layer_wheel"] << " "
79 << index["eta_module"] << " " << index["phi_module"] << " " << index["side"]);
80 ATH_MSG_FATAL("Attempting to split "<< extraIndex.second);
81 ATH_MSG_FATAL("Only splitting of eta_module supported for ITk strips!!!");
82 return -1;
83 }
84
85 //add the required amount to the requested field
86 updatedIndex = index;
87 updatedIndex[extraIndex.first] += extraIndex.second;
88
89 int hitIdOfWafer = SiHitIdHelper::GetHelper()->buildHitId(SCT_HitIndex,
90 index["barrel_endcap"],
91 index["layer_wheel"],
92 index["eta_module"] + extraIndex.second,
93 index["phi_module"],
94 index["side"]);
95
96 ATH_MSG_DEBUG("Index list: " << index["barrel_endcap"] << " " << index["layer_wheel"] << " "
97 << index["eta_module"] + extraIndex.second << " " << index["phi_module"] << " " << index["side"]);
98 ATH_MSG_DEBUG("hitIdOfWafer = " << std::hex << hitIdOfWafer << std::dec);
99 ATH_MSG_DEBUG(" bec = " << SiHitIdHelper::GetHelper()->getBarrelEndcap(hitIdOfWafer)
100 << " lay = " << SiHitIdHelper::GetHelper()->getLayerDisk(hitIdOfWafer)
101 << " eta = " << SiHitIdHelper::GetHelper()->getEtaModule(hitIdOfWafer)
102 << " phi = " << SiHitIdHelper::GetHelper()->getPhiModule(hitIdOfWafer)
103 << " side = " << SiHitIdHelper::GetHelper()->getSide(hitIdOfWafer));
104 return hitIdOfWafer;
105}
106
107
108void StripGmxInterface::addSensorType(const std::string& clas,
109 const std::string& typeName,
110 const std::map<std::string, std::string>& parameters)
111{
112 ATH_MSG_DEBUG("addSensorType called for class " << clas << ", typeName " << typeName);
113
114 if (clas == "SiStripBox") {
115 makeSiStripBox(typeName, parameters);
116 } else if (clas == "StereoAnnulus") {
117 makeStereoAnnulus(typeName, parameters);
118 } else { // To-do: add "Annulus"
119 ATH_MSG_ERROR("addSensorType: unrecognised sensor class: " << clas);
120 ATH_MSG_ERROR("No sensor design created");
121 }
122}
123
124
125void StripGmxInterface::makeSiStripBox(const std::string &typeName,
126 const std::map<std::string, std::string> &parameters)
127{
128 //
129 // Get all parameters.
130 //
131 SiDetectorDesign::Axis stripDirection;
132 SiDetectorDesign::Axis fieldDirection;
133 double thickness{0.320};
134 int readoutSide{1};
136 int nRows{1};
137 double pitch{0.080};
138 int nStrips{1280}; // Per row
139 double length{25.0};
140
141 std::string carrierString;
142 getParameter(typeName, parameters, "carrierType", carrierString);
143 if (carrierString == "electrons") {
144 carrier = InDetDD::electrons;
145 } else if (carrierString == "holes") {
146 carrier = InDetDD::holes;
147 } else {
148 throw GaudiException("Parameter carrierType should be electrons or holes for " + typeName,
149 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
150 }
151
152 std::string readoutSideString;
153 getParameter(typeName, parameters, "readoutSide", readoutSideString);
154 if (readoutSideString == "+") {
155 readoutSide = 1;
156 } else if (readoutSideString == "-") {
157 readoutSide = -1;
158 } else {
159 throw GaudiException("Parameter readoutSide should be + or - for " + typeName,
160 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
161 }
162
163 std::string fieldDirectionString;
164 getParameter(typeName, parameters, "fieldDirection", fieldDirectionString);
165 if (fieldDirectionString == "x") {
166 fieldDirection = SiDetectorDesign::xAxis;
167 } else if (fieldDirectionString == "y") {
168 fieldDirection = SiDetectorDesign::yAxis;
169 } else if (fieldDirectionString == "z") {
170 fieldDirection = SiDetectorDesign::zAxis;
171 } else {
172 throw GaudiException("Parameter fieldDirection should be x, y, or z for " + typeName,
173 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
174 }
175
176 std::string stripDirectionString;
177 getParameter(typeName, parameters, "stripDirection", stripDirectionString);
178 if (stripDirectionString == "x") {
179 stripDirection = SiDetectorDesign::xAxis;
180 } else if (stripDirectionString == "y") {
181 stripDirection = SiDetectorDesign::yAxis;
182 } else if (stripDirectionString == "z") {
183 stripDirection = SiDetectorDesign::zAxis;
184 } else {
185 throw GaudiException("Parameter stripDirection should be x, y, or z for " + typeName,
186 "StripGmxInterface::makeSiStripBox", StatusCode::FAILURE);
187 }
188
189 getParameter(typeName, parameters, "thickness", thickness);
190 getParameter(typeName, parameters, "nRows", nRows);
191 getParameter(typeName, parameters, "nStrips", nStrips);
192 getParameter(typeName, parameters, "pitch", pitch);
193 getParameter(typeName, parameters, "stripLength", length);
194
195 //At the moment, we'd only ever want StripBarrel for this detector type, so throw a WARNING if it differs
196 //However, in future this may be different, so implementing the functionality to set this anyway
198 int detectorTypeEnum = 0;
199 if (checkParameter(typeName, parameters, "detectorType", detectorTypeEnum)) {
200 if (detectorTypeEnum == 4) detectorType = InDetDD::StripBarrel;
201 else ATH_MSG_WARNING("Non-strip barrel type set for strip box DetectorElement - is this intended?");
202 }
203
204
205 //
206 // Make Sensor Design and add to DetectorManager
207 //
208
209 int splitLevel{};
210 if (checkParameter(typeName, parameters, "splitLevel", splitLevel)) {
211 // start from middle of first strip row
212 double initZShift = length * (-static_cast<double>(splitLevel) * 0.5 + 0.5);
213
214 // now, the "Mother"...
215 // This is a container for all the other designs, to allow navigation
216 // between the different rows on a simulated sensor in the HITS
217 auto motherDesign = std::make_unique<StripBoxDesign>(stripDirection,
218 fieldDirection,
219 thickness,
220 readoutSide,
221 carrier,
222 nRows,
223 nStrips,
224 pitch,
225 length,
226 detectorType);
227
228 for (int i = 0; i< splitLevel; i++) {
229 for (int side : {0,1}) { //need different additional shift transform per side...
230 int sign = (side == 0) ? 1 : -1; //...because shift in different direction per side
231 double zShift = sign * (initZShift + (i * length));
232
233 auto design = std::make_unique<StripBoxDesign>(stripDirection,
234 fieldDirection,
235 thickness,
236 readoutSide,
237 carrier,
238 1, //single row
239 nStrips,
240 pitch,
241 length,
242 detectorType,
243 zShift);
244
245 design->setMother(motherDesign.get());
246 motherDesign->addChildDesign(i,design.get());
247
248 std::string splitName = typeName + "_" + std::to_string(i) + "_" + std::to_string(side);
249 m_geometryMap[splitName] = m_detectorManager->addDesign(std::move(design));
250 }
251 }
252
253 // Add to map for addSensor routine
254 m_motherMap[typeName] = motherDesign.get();
255 m_detectorManager->addMotherDesign(std::move(motherDesign));
256 } else { // no split level
257 auto design = std::make_unique<StripBoxDesign>(stripDirection,
258 fieldDirection,
259 thickness,
260 readoutSide,
261 carrier,
262 nRows,
263 nStrips,
264 pitch,
265 length,
266 detectorType);
267
268 // Add to map for addSensor routine
269 m_geometryMap[typeName] = design.get();
270 m_detectorManager->addDesign(std::move(design));
271 }
272}
273
274
275void StripGmxInterface::makeStereoAnnulus(const std::string &typeName,
276 const std::map<std::string, std::string> &parameters)
277{
278 //
279 // Get all parameters.
280 //
281 int readoutSide{1};
282 SiDetectorDesign::Axis fieldDirection;
283 SiDetectorDesign::Axis stripDirection;
285 double thickness{0.320};
286 double stereoAngle{0.020};
287 double centreR{500.};
288 int nRows{1};
289 std::vector <int> nStrips;
290 std::vector<double> phiPitch;
291 std::vector<double> startR;
292 std::vector<double> endR;
293 bool usePC{false}; // initialise to false
294
295 std::string carrierString;
296 getParameter(typeName, parameters, "carrierType", carrierString);
297 if (carrierString == "electrons") {
298 carrier = InDetDD::electrons;
299 } else if (carrierString == "holes") {
300 carrier = InDetDD::holes;
301 } else {
302 throw GaudiException("Parameter carrierType should be electrons or holes for " + typeName,
303 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
304 }
305
306 std::string readoutSideString;
307 getParameter(typeName, parameters, "readoutSide", readoutSideString);
308 if (readoutSideString == "+") {
309 readoutSide = 1;
310 } else if (readoutSideString == "-") {
311 readoutSide = -1;
312 } else {
313 throw GaudiException("Parameter readoutSide should be + or - for " + typeName,
314 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
315 }
316
317 std::string fieldDirectionString;
318 getParameter(typeName, parameters, "fieldDirection", fieldDirectionString);
319 if (fieldDirectionString == "x") {
320 fieldDirection = SiDetectorDesign::xAxis;
321 } else if (fieldDirectionString == "y") {
322 fieldDirection = SiDetectorDesign::yAxis;
323 } else if (fieldDirectionString == "z") {
324 fieldDirection = SiDetectorDesign::zAxis;
325 } else {
326 throw GaudiException("Parameter fieldDirection should be x, y, or z for " + typeName,
327 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
328 }
329
330 std::string stripDirectionString;
331 getParameter(typeName, parameters, "stripDirection", stripDirectionString);
332 if (stripDirectionString == "x") {
333 stripDirection = SiDetectorDesign::xAxis;
334 } else if (stripDirectionString == "y") {
335 stripDirection = SiDetectorDesign::yAxis;
336 } else if (stripDirectionString == "z") {
337 stripDirection = SiDetectorDesign::zAxis;
338 } else {
339 throw GaudiException("Parameter stripDirection should be x, y, or z for " + typeName,
340 "StripGmxInterface::makeStereoAnnulus", StatusCode::FAILURE);
341 }
342
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["barrel_endcap"],
495 updatedIndex["layer_wheel"],
496 updatedIndex["phi_module"],
497 updatedIndex["eta_module"],
498 updatedIndex["side"]);
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["barrel_endcap"] == 0) { // only barrel-type have side dependence
521 splitTypeName += "_" + std::to_string(updatedIndex["side"]);
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["barrel_endcap"],
539 updatedIndex["layer_wheel"],
540 updatedIndex["eta_module"],
541 updatedIndex["phi_module"],
542 updatedIndex["side"],
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["barrel_endcap"],
566 index["layer_wheel"],
567 index["phi_module"],
568 index["eta_module"],
569 index["side"]);
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["barrel_endcap"],
605 index["layer_wheel"],
606 index["eta_module"],
607 index["phi_module"],
608 index["side"],
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["barrel_endcap"],
636 index["layer_wheel"],
637 index["phi_module"],
638 index["eta_module"],
639 index["side"]);
640 break;
641 case 1:
642 id = sctIdHelper->wafer_id(index["barrel_endcap"],
643 index["layer_wheel"],
644 index["phi_module"],
645 index["eta_module"],
646 0);
647 break;
648 case 2:
649 id = sctIdHelper->wafer_id(index["barrel_endcap"],
650 index["layer_wheel"],
651 0,
652 0,
653 0);
654 break;
655 case 3:
656 id = sctIdHelper->wafer_id(index["barrel_endcap"],
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["barrel_endcap"],
692 updatedIndex["layer_wheel"],
693 updatedIndex["phi_module"],
694 updatedIndex["eta_module"],
695 updatedIndex["side"]);
696 break;
697 case 1:
698 id = sctIdHelper->wafer_id(updatedIndex["barrel_endcap"],
699 updatedIndex["layer_wheel"],
700 updatedIndex["phi_module"],
701 updatedIndex["eta_module"],
702 0);
703 break;
704 case 2:
705 id = sctIdHelper->wafer_id(updatedIndex["barrel_endcap"],
706 updatedIndex["layer_wheel"],
707 0,
708 0,
709 0);
710 break;
711 case 3:
712 id = sctIdHelper->wafer_id(updatedIndex["barrel_endcap"],
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{"barrel_endcap","layer_wheel","phi_module","eta_module","side"};
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 for (const auto&[fullPhysVolInfoString, fullPhysVolPointer] : mapFPV){
778 //find the name of the corresponding detector design type
779 size_t startRG = fullPhysVolInfoString.find("RG_");
780 if(startRG==std::string::npos){
781 ATH_MSG_DEBUG("GeoFullPhysVol "<<fullPhysVolInfoString<<" does not have the expected format. Skipping");
782 continue;
783 }
784 std::string typeName = fullPhysVolInfoString.substr(startRG);
785 std::map<std::string, int> index;
786 for (const std::string & field:fields){
787 size_t first = fullPhysVolInfoString.find(field+"_");
788 size_t last = fullPhysVolInfoString.find('_',first+field.size()+1);//start looking only after end of first delimiter (plus 1 for the "_" appended) ends
789 if(first==std::string::npos || last==std::string::npos){
790 ATH_MSG_DEBUG("Could not extract "<<field<<" from "<<fullPhysVolInfoString<<". Skipping");
791 continue;
792 }
793 std::string strNew = fullPhysVolInfoString.substr(first+field.size()+1,last-(first+field.size()+1));
794 index[field] = std::stoi(strNew);
795 }
796 //now check if we need to split
797 size_t splitPos = fullPhysVolInfoString.find("split_");
798 if(splitPos!=std::string::npos){
799 size_t last = fullPhysVolInfoString.find('_',splitPos+6);//"split_" is 6 characters
800 std::string strNew = fullPhysVolInfoString.substr(splitPos+6,last-(splitPos+6));
801 int splitLevel = std::stoi(strNew);
802 for(int i=0;i<splitLevel;i++){
803 std::string field = "eta_module";//eventually specify in Xml the field to split in?
804 std::pair<std::string,int> extraIndex(field,i);
805 addSplitSensor(typeName,index,extraIndex,0,fullPhysVolPointer,splitLevel);
806 }
807 }
808 else addSensor(typeName,index,0,fullPhysVolPointer);
809 }
810}
811
812} // namespace ITk
813} // 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(const std::string &node, const std::string &tag, const std::string &tag2node="", const std::string &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.
bool is_valid() const
Check if id is in a valid state.
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.
Definition index.py:1