ATLAS Offline Software
Loading...
Searching...
No Matches
MuonStationBuilderImpl.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
7
10
11#include <fstream>
12#include <map>
13#include <memory>
14
16#include "GeoModelKernel/GeoBox.h"
17#include "GeoModelKernel/GeoCons.h"
18#include "GeoModelKernel/GeoPara.h"
19#include "GeoModelKernel/GeoPgon.h"
20#include "GeoModelKernel/GeoShape.h"
21#include "GeoModelKernel/GeoShapeIntersection.h"
22#include "GeoModelKernel/GeoShapeShift.h"
23#include "GeoModelKernel/GeoShapeSubtraction.h"
24#include "GeoModelKernel/GeoShapeUnion.h"
25#include "GeoModelKernel/GeoTrap.h"
26#include "GeoModelKernel/GeoTrd.h"
27#include "GeoModelKernel/GeoTube.h"
28#include "GeoModelKernel/GeoTubs.h"
29#include "GeoModelKernel/GeoVolumeCursor.h"
45#include "TrkGeometry/Layer.h"
62
63
64namespace Muon{
66
67// constructor
69 const std::string& n,
70 const IInterface* p)
71 : AthAlgTool(t, n, p) {}
72
73// Athena standard methods
74// initialize
76 // Retrieve the tracking volume helper
77 // -------------------------------------------------
79 ATH_MSG_INFO("Retrieved tool " << m_trackingVolumeHelper);
80
81 // Retrieve muon station builder tool
82 // -------------------------------------------------
84 ATH_MSG_INFO("Retrieved tool " << m_muonStationTypeBuilder);
85
86 // if no muon materials are declared, take default ones
87
88 // default material properties
89 m_muonMaterial = Trk::Material(10e10, 10e10, 0., 0., 0.);
90
91 ATH_MSG_INFO(" initialize() successful");
92
93 ATH_CHECK(m_idHelperSvc.retrieve());
94
95 return StatusCode::SUCCESS;
96}
97
100
101 DetachedVolVec translatedStations{};
102
103 // retrieve muon station branches from GeoModel tree
104 std::vector<std::pair<const GeoVPhysVol*, std::vector<GMInfo>>> stations = retrieveGMsensitive(muonMgr);
105
106 for (const auto& mstation : stations) {
107 // build prototype
108 std::unique_ptr<Trk::DetachedTrackingVolume> msType = buildDetachedTrackingVolumeType(muonMgr, mstation.first,
109 mstation.second[0]);
110 if (!msType) {
111 continue;
112 }
113 // clone prototype
114 std::string name = mstation.first->getLogVol()->getName();
115 // NSW prototypes built at position
116 if (name.substr(0, 4) == "sTGC" || name.substr(0, 2) == "MM") {
117 for (unsigned int i = 0; i < mstation.second.size(); i++) {
118 std::string sName = name.substr(name.find('-') + 1);
119 Identifier nswId = m_muonStationTypeBuilder->identifyNSW(sName, mstation.second[i].first);
120 // clone station from prototype
121 Amg::Transform3D trdef(mstation.second[i].first *
122 mstation.second[0].first.inverse());
123 std::unique_ptr<Trk::DetachedTrackingVolume> newStat{msType->clone(name, trdef)};
124 // identify layer representation
125 Trk::Layer* layer = (newStat->layerRepresentation());
126 layer->setLayerType(nswId.get_identifier32().get_compact());
127 // identify layers
128 identifyNSWLayers(*newStat, nswId);
129 // collect
130 translatedStations.push_back(std::move(newStat));
131 } // end clone NSW stations
132 } else {
133 for (auto gminfo : mstation.second) {
134 // clone station from prototype
135 std::unique_ptr<Trk::DetachedTrackingVolume> newStat{msType->clone(name, gminfo.first)};
136 // identify layer representation
137 Trk::Layer* layer = newStat->layerRepresentation();
138 int eta{0}, phi{0};
139 Identifier stId = resolveId(name, gminfo, eta, phi, muonMgr);
140 layer->setLayerType(stId.get_identifier32().get_compact());
141 // glue components
142 glueComponents(newStat.get());
143 // identify layers
144 identifyLayers(newStat.get(), stId, eta, phi, muonMgr);
145 // collect
146 translatedStations.push_back(std::move(newStat));
147 } // end clone non-NSW
148 }
149 } // end loop over prototypes
150
151 ATH_MSG_DEBUG( "returns " << translatedStations.size() << " stations");
152 return translatedStations;
153}
154
156 Trk::TrackingVolumeArray* volArray = stat->trackingVolume()->confinedVolumes();
157 if (!volArray || volArray->arrayObjectsNumber() <= 1) {
158 return;
159 }
160
161 std::span<Trk::TrackingVolume* const> components = volArray->arrayObjects();
162 const Trk::BinUtility* binUtilityX = volArray->binUtility();
163 const Trk::CuboidVolumeBounds* cubVolBounds = dynamic_cast<const Trk::CuboidVolumeBounds*>(&(components[0]->volumeBounds()));
164
165 // identify 'lower' and 'upper' boundary surface
168
169 // rectangular station in x ordering (MDT barrel)
170 if (cubVolBounds && binUtilityX) {
173 }
174
175 if (low >= 0 && up >= 0) {
176 // glue volumes
177 for (unsigned int i = 0; i < components.size() - 1; ++i) {
178 m_trackingVolumeHelper->glueTrackingVolumes(*(components[i]), up, *(components[i + 1]), low);
179 }
180 }
181
182
183}
184
186 Trk::DetachedTrackingVolume* station, Identifier /*stationID*/, int eta,
187 int phi, const MuonGM::MuonDetectorManager* muonMgr) const {
188 ATH_MSG_VERBOSE(name() << " identifying layers ");
189
190 const std::string stationName = station->trackingVolume()->volumeName();
191 ATH_MSG_VERBOSE(" in station " << station->name());
192 const std::string stationStr = stationName.substr(0, 3);
193 bool is_valid{false};
194 if (m_idHelperSvc->hasCSC() && stationStr[0] == 'C') {
196 const Identifier readout_id = muonMgr->cscIdHelper()->channelID(
197 stationStr, cscEtaSt, phi + 1, 1, 1, 0, 1, is_valid);
198 const MuonGM::CscReadoutElement* cscRE =
199 is_valid ? muonMgr->getCscReadoutElement(readout_id) : nullptr;
200 if (!cscRE) {
201 const Identifier backup_id = muonMgr->cscIdHelper()->channelID(
202 stationStr, cscEtaSt, phi + 1, 2, 1, 0, 1, is_valid);
203 cscRE =
204 is_valid ? muonMgr->getCscReadoutElement(backup_id) : nullptr;
205 }
206 if (cscRE) {
207 for (int gasgap = 0; gasgap < cscRE->Ngasgaps(); gasgap++) {
208 Identifier idi = m_idHelperSvc->cscIdHelper().channelID(
209 cscRE->identify(), cscRE->ChamberLayer(), gasgap + 1, 0, 1,
210 is_valid);
211 if (!is_valid)
212 continue;
213 const auto *stripSurf = dynamic_cast<const Trk::PlaneSurface*>(&(cscRE->surface(idi)));
214 const Amg::Vector3D& gpi = stripSurf->center();
215 Trk::TrackingVolume* assocVol =
216 station->trackingVolume()->associatedSubVolume(gpi);
217 Trk::Layer* assocLay = nullptr;
218 if (assocVol)
219 assocLay = assocVol->associatedLayer(gpi);
220 unsigned int iD = idi.get_identifier32().get_compact();
221 if (assocVol && assocLay) {
222 assocLay->setLayerType(iD);
223 }
224 if (assocLay) {
225 assocLay->setRef((assocLay->surfaceRepresentation().transform().inverse() *gpi)[1]);
226 }
227 }
228 } else {
229 ATH_MSG_DEBUG("cscRE not found:" << stationName << "," << eta << ","
230 << phi);
231 }
232 } else if (stationStr[0] == 'T') {
233 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
234 int st = 7;
235 if (stationStr == "T1F") {
236 st = 0;
237 } else if (stationStr == "T1E") {
238 st = 1;
239 } else if (stationStr == "T2F") {
240 st = 2;
241 } else if (stationStr == "T2E") {
242 st = 3;
243 } else if (stationStr == "T3F") {
244 st = 4;
245 } else if (stationStr == "T3E") {
246 st = 5;
247 } else if (stationStr == "T4F") {
248 st = 6;
249 }
250
251 const int stationName =
254 const int stationEta =
256 auto getReadout = [stationName, stationEta, muonMgr, &idHelper](int phi) {
257 const int stationPhi = phi + 1;
258 bool is_valid{false};
259 const Identifier id = idHelper.elementID(stationName, stationEta, stationPhi, is_valid);
260 return is_valid ? muonMgr->getTgcReadoutElement(id) : nullptr;
261 };
262 const MuonGM::TgcReadoutElement* tgc = getReadout(phi - 1);
263
264 if (!tgc || !(station->trackingVolume()->inside(tgc->center(), 0.))) {
265 unsigned int phit = 0;
266
267 while (phit < 48) {
268 const MuonGM::TgcReadoutElement* tgct = getReadout(phit);
269 if (tgct &&
270 station->trackingVolume()->inside(tgct->center(), 0.)) {
271 tgc = tgct;
272 phi = phit;
273 // update station identity
274 Identifier oldId(station->layerRepresentation()->layerType());
275 int stationName = idHelper.stationName(oldId);
276 int stationEta = idHelper.stationEta(oldId);
277 Identifier stId = idHelper.channelID(stationName, stationEta, phi,
278 1,1,1, is_valid);
281 break;
282 }
283 phit++;
284 }
285 }
286
287 if (tgc) {
288 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
289 int etaSt = tgc->getStationEta();
290 int phiSt = tgc->getStationPhi();
291
292 bool validId{false};
293 Identifier wireId = idHelper.channelID(stationStr, etaSt, phiSt, 1, 0, 1, validId);
294 if (!validId) {
295 ATH_MSG_ERROR("invalid TGC channel:" << wireId);
296 }
297 const Amg::Vector3D gp = tgc->channelPos(wireId);
298 Trk::TrackingVolume* assocVol =
299 station->trackingVolume()->associatedSubVolume(gp);
300 if (!assocVol)
301 ATH_MSG_DEBUG("wrong tgcROE?" << stationStr << "," << etaSt
302 << "," << phiSt);
303 if (assocVol && assocVol->confinedLayers()) {
304 std::span<Trk::Layer* const> layers =
305 assocVol->confinedLayers()->arrayObjects();
306
307 for (unsigned int il = 0; il < layers.size(); il++) {
308 wireId = idHelper.channelID(stationStr, etaSt, phiSt, il + 1, 1, 1, validId);
309 if (!validId) {
310 ATH_MSG_ERROR("invalid TGC channel:" << wireId);
311 layers[il]->setLayerType(1);
312 } else {
313 unsigned int id = wireId.get_identifier32().get_compact();
314 layers[il]->setLayerType(id);
315 // validation
316 Identifier checkId(layers[il]->layerType());
317 const auto *stripSurf = dynamic_cast<const Trk::PlaneSurface*>(&(tgc->surface(checkId)));
318 if ((layers[il]->surfaceRepresentation().transform().inverse() * stripSurf->center()).mag() > 0.001)
319 ATH_MSG_DEBUG("TGC strip plane shifted:"<< st << "," << eta << "," << phi
320 << ":"<< layers[il]->surfaceRepresentation().transform().inverse() * stripSurf->center());
321 }
322 }
323 }
324 } else {
325 ATH_MSG_WARNING(name() << "tgcROE not found for :" << stationName
326 << "," << eta << "," << phi);
327 }
328 } else if (m_idHelperSvc->hasMDT() &&
329 (stationName[0] == 'B' || stationName[0] == 'E')) {
330 // recalculate id
331 Identifier stId(station->layerRepresentation()->layerType());
332 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
333 const int nameIndex = idHelper.stationNameIndex(stationName.substr(0, 3));
334 if (station->trackingVolume()->confinedVolumes()) {
335 std::span<Trk::TrackingVolume* const> cVols =
337 for (auto* cVol : cVols) {
338 if (cVol->confinedLayers()) {
339 std::span<Trk::Layer* const> cLays = cVol->confinedLayers()->arrayObjects();
340 const MuonGM::MdtReadoutElement* mdtROE = nullptr;
341 bool is_valid{false};
342
343 for (auto* cLay : cLays) {
344 Identifier id(cLay->layerType());
345 if (id.get_compact() > 0 && m_idHelperSvc->isMdt(id)) {
346 Identifier newId = idHelper.channelID(nameIndex, eta, phi,
347 idHelper.multilayer(id),
348 idHelper.tubeLayer(id),
349 idHelper.tube(id),
350 is_valid);
351 if (!mdtROE) {
352 mdtROE = is_valid ? muonMgr->getMdtReadoutElement(newId) : nullptr;
353 }
354 unsigned int newid = newId.get_identifier32().get_compact();
355 cLay->setLayerType(newid);
356 // check reference position
357 if (mdtROE) {
358 double ref = cLay->getRef();
359 // double loc = mdtROE->localROPos(newId)[2]; //
360 // this does not take into account ROE shift wrt
361 // TG station/layer
362 double loc = (cLay->surfaceRepresentation().transform().inverse() * mdtROE->tubePos(newId))[1];
363 if (std::abs(ref) > 10e6) {
364 double sign = (ref > 0.) ? 1. : -1.;
365 int dec = int(ref / 1e5);
366 ref = ref - dec * 1e5 -
367 0.5 * (sign + 1) * 1e5;
368 if (std::abs(ref - loc) > 0.001) { // re-pack
369 cLay->setRef(loc + dec * 1e5 + 0.5 * (sign + 1) * 1e5);
370 }
371 } else if (std::abs(ref - loc) > 0.001) {
372 cLay->setRef(loc);
373 }
374 }
375 }
376 }
377 }
378 if (!cVol->confinedArbitraryLayers().empty()) {
379 Trk::ArraySpan<Trk::Layer* const> cLays = cVol->confinedArbitraryLayers();
380 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
381 for (auto* cLay : cLays) {
382 Identifier id(cLay->layerType());
383 bool is_valid{false};
384 if (m_idHelperSvc->hasRPC() && id.get_compact() > 0 && m_idHelperSvc->isRpc(id)) {
385 Identifier newId = idHelper.channelID(nameIndex, eta, phi,
386 idHelper.doubletR(id), idHelper.doubletZ(id),
387 idHelper.doubletPhi(id), idHelper.gasGap(id),
388 1, idHelper.strip(id),
389 is_valid);
390 int newid = newId.get_identifier32().get_compact();
391 cLay->setLayerType(newid);
392 }
393 }
394 }
395 }
396 }
397 }
398 // by now, all the layers should be identified - verify
399 if (station->trackingVolume()->confinedVolumes()) {
400 std::span<Trk::TrackingVolume* const> cVols =
402 for (auto* cVol : cVols) {
403 if (cVol->confinedLayers()) {
404 std::span<Trk::Layer* const> cLays =
405 cVol->confinedLayers()->arrayObjects();
406 for (unsigned int il = 0; il < cLays.size(); il++) {
407 Identifier id(cLays[il]->layerType());
408 if (id == 1)
409 ATH_MSG_DEBUG(station->name()
410 << "," << cVol->volumeName()
411 << ", unidentified active layer:" << il);
412 else if (id != 0)
413 checkLayerId("check layer in " + station->name() +
414 " subvolume " + cVol->volumeName(),
415 muonMgr, id, cLays[il]);
416 }
417 }
418 if (!cVol->confinedArbitraryLayers().empty()) {
420 cVol->confinedArbitraryLayers();
421 for (unsigned int il = 0; il < cLays.size(); il++) {
422 Identifier id(cLays[il]->layerType());
423 if (id == 1)
424 ATH_MSG_DEBUG(station->name()
425 << "," << cVol->volumeName()
426 << ", unidentified active layer:" << il);
427 else if (id != 0)
428 checkLayerId("check arbitrary layer in " +
429 station->name() + " subvolume " +
430 cVol->volumeName(),
431 muonMgr, id, cLays[il]);
432 }
433 }
434 }
435 }
436 if (station->trackingVolume()->confinedLayers()) {
437 std::span<Trk::Layer* const> cLays =
439 for (unsigned int il = 0; il < cLays.size(); il++) {
440 Identifier id(cLays[il]->layerType());
441 if (id == 1)
442 ATH_MSG_DEBUG(station->name()
443 << "," << station->name()
444 << ", unidentified active layer:" << il);
445 else if (id != 0)
446 checkLayerId("check confined layer in " + station->name(),
447 muonMgr, id, cLays[il]);
448 }
449 }
450 // end identification check
451}
452
454 const Identifier& id) const {
455
456
457 if (!station.trackingVolume()->confinedLayers()) return;
458 std::span<Trk::Layer* const> lays = station.trackingVolume()->confinedLayers()->arrayObjects();
459 const bool isStgc{station.name().substr(0, 4) == "sTGC"};
460 const bool isMm{station.name().substr(0, 2) == "MM"};
461 if (!isMm && !isStgc) return;
462 for (unsigned int il = 0; il < lays.size(); il++) {
463 if (isStgc) {
464 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
465 const Identifier lid = idHelper.channelID(id, idHelper.multilayer(id), il + 1, 2, 1);
466 lays[il]->setLayerType(lid.get_identifier32().get_compact());
467
468 } else if (isMm) {
469 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
470 const Identifier lid = idHelper.channelID(id, idHelper.multilayer(id), il + 1, 1);
471 lays[il]->setLayerType(lid.get_identifier32().get_compact());
472 }
473 }
474}
475
477 const Amg::Transform3D& transf,
478 const MuonGM::MuonDetectorManager* muonMgr) const {
479 ATH_MSG_VERBOSE(name() << " identifying prototype ");
480
481 const std::string& stationName = station.volumeName();
482 ATH_MSG_VERBOSE(" for station " << stationName);
483 const std::string stationNameShort = stationName.substr(0, 3);
484 const char stationFirstChar = stationName[0];
485 bool is_valid{false};
486
487 if (m_idHelperSvc->hasMDT() && (stationFirstChar == 'B' || stationFirstChar == 'E')) {
488 // MDT
489 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
490 const int nameIndex = idHelper.stationNameIndex(stationNameShort);
491 for (int multi = 1; multi <= 2; ++multi) {
492 const Identifier ele_id = idHelper.channelID(nameIndex, eta, phi, multi, 1, 1, is_valid);
493 if (!is_valid) {
494 continue;
495 }
496 const MuonGM::MdtReadoutElement* multilayer = muonMgr->getMdtReadoutElement(ele_id);
497 if (!multilayer) {
498 continue;
499 }
500 Trk::TrackingVolume* assocVol = station.associatedSubVolume(transf.inverse() * multilayer->center());
501 if (!assocVol) {
502 ATH_MSG_WARNING("valid multilayer outside station:" << stationName);
503 continue;
504 }
505 int nLayers = multilayer->getNLayers();
506 for (int layer = 1; layer <= nLayers; ++layer) {
507 Identifier id = idHelper.channelID(nameIndex, eta, phi, multi, layer, 1, is_valid);
508 if (!is_valid) {
509 continue;
510 }
511 // retrieve associated layer
512 Trk::Layer* assocLay = assocVol->associatedLayer(transf.inverse() * multilayer->tubePos(id));
513 if (assocLay) {
514 assocLay->setLayerType(id.get_identifier32().get_compact());
515 }
516 }
517 }
518
519 // RPC ?
520 Trk::BinnedArray<Trk::TrackingVolume>* confinedVolumes = station.confinedVolumes();
521 if (confinedVolumes) {
522 std::span<Trk::TrackingVolume* const> vols = confinedVolumes->arrayObjects();
523 for (auto* vol : vols) {
524 if (!m_idHelperSvc->hasRPC() || vol->volumeName() != "RPC") {
525 break;
526 }
527
528 // for active layers do a search of associated ROE
529 Trk::ArraySpan<Trk::Layer* const> layers = vol->confinedArbitraryLayers();
530 int nameIndex = m_idHelperSvc->rpcIdHelper().stationNameIndex(stationNameShort);
532 if (stationNameShort == "BME" || stationNameShort == "BMG") {
533 continue;
534 }
535 // the following checks are not necessarily needed, since
536 // calling channelID with check=true would catch them
537 // However, since these validity checks are slow, let's
538 // manually skip the obvious non-existant ones
539 //
540 // only BOG7/8 and BMS2/4 have doubletZ=3, the remaing BOG
541 // and BOF4 have doubletZ=1
542 int doubletZMax = 2;
543 if (stationNameShort.find("BMS") != std::string::npos && (std::abs(eta) == 2 || std::abs(eta) == 4)) {
544 doubletZMax = 3;
545 }
546 else if (stationNameShort.find("BOG") != std::string::npos) {
547 if (std::abs(eta) == 7 || std::abs(eta) == 8) {
548 doubletZMax = 3;
549 } else {
550 doubletZMax = 1;
551 }
552 } else if (stationNameShort.find("BOF") != std::string::npos && std::abs(eta) == 4){
553 doubletZMax = 1;
554 }
555 // all BOL/BOS and BOF1 have doubletR=1
556 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
557 for (int doubletR = 1; doubletR <= 2; ++doubletR) {
558 bool isValid{false};
559 const Identifier stationId = idHelper.elementID(nameIndex, eta, phi, doubletR, isValid);
560 if (!isValid) {
561 continue;
562 }
563 for (int doubletZ = 1; doubletZ <= doubletZMax; ++doubletZ) {
564 for (int doubletPhi = 1; doubletPhi <= 2; doubletPhi++) {
565
566 const Identifier id = idHelper.channelID(stationId, doubletZ, doubletPhi,
567 1, 0, 1, isValid);
568 if (!isValid) {
569 continue;
570 }
571 const MuonGM::RpcReadoutElement* rpc = muonMgr->getRpcReadoutElement(id);
572 if (!rpc) {
573 continue;
574 }
575 for (int gasGap = 1; gasGap <= rpc->numberOfLayers(); ++gasGap) {
576
577 Identifier etaId = idHelper.channelID(id, doubletZ, doubletPhi,
578 gasGap, 0, 1, isValid);
579
580 const Amg::Vector3D stripLocPos = transf.inverse() * rpc->stripPos(etaId);
581 for (auto* layer : layers) {
582 if (layer->layerType() == 0 ||
583 !layer->surfaceRepresentation().isOnSurface(stripLocPos, false, 0.5* layer->thickness())){
584 continue;
585 }
586 const Amg::Vector3D locPos1 =layer->surfaceRepresentation().transform().inverse() * stripLocPos;
587 const Amg::Vector3D locPos2 = rpc->surface(etaId).transform().inverse() * rpc->stripPos(etaId);
588
589 double swap = (std::abs(locPos1[1] - locPos2[0]) > 0.001) ? 20000. : 0.;
590
591 layer->setLayerType(etaId.get_identifier32().get_compact());
592
593
594 const Amg::Vector3D locPos = layer->surfaceRepresentation().transform() *
595 transf.inverse() * rpc->surface(etaId).center();
596 layer->setRef(swap + locPos[0]);
597
598 }
599 }
600 }
601 }
602 }
603 }
604 }
605 }
606
607 // by now, all the layers should be identified - verify
608 if (station.confinedVolumes()) {
609 std::span<Trk::TrackingVolume* const> cVols = station.confinedVolumes()->arrayObjects();
610 for (auto* cVol : cVols) {
611 if (cVol->confinedLayers()) {
612 std::span<Trk::Layer* const> cLays = cVol->confinedLayers()->arrayObjects();
613 for (unsigned int il = 0; il < cLays.size(); il++) {
614 Identifier id(cLays[il]->layerType());
615 if (id == 1) {
616 ATH_MSG_DEBUG(station.volumeName()<< "," << cVol->volumeName() << ", unidentified active layer:" << il);
617 }
618 }
619 }
620 if (!cVol->confinedArbitraryLayers().empty()) {
621 Trk::ArraySpan<Trk::Layer* const> cLays = cVol->confinedArbitraryLayers();
622 for (unsigned int il = 0; il < cLays.size(); il++) {
623 Identifier id(cLays[il]->layerType());
624 if (id == 1) {
625 ATH_MSG_DEBUG(station.volumeName() << "," << cVol->volumeName() << ", unidentified active layer:" << il);
626 }
627 }
628 }
629 }
630 }
631 if (station.confinedLayers()) {
632 std::span<Trk::Layer* const> cLays = station.confinedLayers()->arrayObjects();
633 for (unsigned int il = 0; il < cLays.size(); il++) {
634 Identifier id(cLays[il]->layerType());
635 if (id == 1) {
636 ATH_MSG_DEBUG(station.volumeName() << ", unidentified active layer:" << il);
637 }
638 }
639 }
640 // end identification check
641}
642
643void MuonStationBuilderImpl::getNSWStationsForTranslation(const GeoVPhysVol* pv, const std::string& name,
644 const Amg::Transform3D& transform,
645 std::vector<std::pair<std::pair<const GeoLogVol*, Trk::MaterialProperties*>,
646 std::vector<Amg::Transform3D>>>& vols,
647 std::vector<std::string>& volNames) const {
648 // special code to get the Sensitive volume of the sTGC and MM (so the gas
649 // volume) throught the Frame
650
651 // subcomponents
652 unsigned int nc = pv->getNChildVols();
653 ATH_MSG_DEBUG("getNSWStationsForTranslation from:"
654 << pv->getLogVol()->getName() << ","
655 << pv->getLogVol()->getMaterial()->getName()
656 << ", looping over " << nc << " children");
657
658 for (unsigned int ic = 0; ic < nc; ic++) {
659 Amg::Transform3D transf = pv->getXToChildVol(ic);
660 const GeoVPhysVol* cv = pv->getChildVol(ic);
661 const GeoLogVol* clv = cv->getLogVol();
662 std::string childName = clv->getName();
663 ATH_MSG_DEBUG("getNSWStationsForTranslation child " << childName);
664
665 if (childName.empty()) {
666 childName = "Spacer";
667 }
668 if (childName.size() > 9 && childName.substr(childName.size() - 9, 9) == "Sensitive") {
669 childName += std::to_string(ic);
670 }
671
672 std::string cName = childName.compare(0, 3, "NSW") == 0 || childName.compare(0, 8, "NewSmall") == 0
673 ? name : name + childName;
674 ATH_MSG_VERBOSE("child number,name,position:" << ic << ":" << clv->getName() << ":"<< Amg::toString(transform * transf));
675
676 if (!cv->getNChildVols()) {
677 bool found = false;
678 for (unsigned int is = 0; is < vols.size(); is++) {
679 if (cName == volNames[is]) {
680 if (std::abs((transform * transf).translation().perp() -
681 vols[is].second.front().translation().perp()) <
682 1.) {
683 found = true;
684 // order transforms to position prototype at phi=0/
685 // 0.125 pi
686 double phiTr = (transform * transf).translation().phi();
687 if (phiTr > -0.001 && phiTr < 0.4) {
688 vols[is].second.insert(vols[is].second.begin(),
689 transform * transf);
690 } else
691 vols[is].second.push_back(transform * transf);
693 "clone?"
694 << clv->getName() << ","
695 << (transform * transf).translation().perp() << ","
696 << (transform * transf).translation().z() << ","
697 << phiTr);
698
699 break;
700 }
701 }
702 }
703 if (!found) {
704 std::vector<Amg::Transform3D> volTr;
705 volTr.push_back(transform * transf);
706 // divide mother material ? seems strange - check !
707 // double scale = 1.; // 1./nc;
708 double thick = 2 * m_muonStationTypeBuilder->get_x_size(pv);
709 if (pv->getLogVol()->getMaterial()->getName() != "Ether" &&
710 (childName == "MM_Frame" || childName == "sTGC_Frame")) {
711 Trk::MaterialProperties matComb(0., 10.e10, 10.e10, 13.,
712 26., 0.);
714 pv->getLogVol()->getMaterial());
715 matComb.addMaterial(newMat, thick / newMat.x0());
716 ATH_MSG_VERBOSE(" use mother volume thickness, x0: "
717 << matComb.thickness() << ", "
718 << matComb.x0()
719 << " mat: " << matComb.thicknessInX0());
721 new Trk::MaterialProperties(matComb);
722 // store mother volume (and not child = Frame)
723 std::pair<const GeoLogVol*, Trk::MaterialProperties*> cpair(
724 pv->getLogVol(), nMat);
725 vols.emplace_back(cpair, volTr);
726 // store extensive name
727 volNames.push_back(cName);
728 ATH_MSG_VERBOSE("new NSW station volume added:"
729 << cName << ", "
730 << clv->getMaterial()->getName() << ", "
731 << volTr.back().translation().z() << ", "
732 << volTr.back().translation().phi()
733 << " mat: " << matComb.thicknessInX0());
734 }
735 // printInfo(cv);
736 }
737 } else {
738 getNSWStationsForTranslation(cv, cName, transform * transf, vols,
739 volNames);
740 }
741 }
742}
743
744std::vector<std::pair<const GeoVPhysVol*, std::vector<GMInfo>>>
746
747 // a single loop over GM tree to retrieve all necessary information
748
749 std::vector<std::pair<const GeoVPhysVol*,
750 std::vector<GMInfo>>> sensitive;
751
752 const GeoVPhysVol* top = muonMgr->getTreeTop(0);
753
754
755 // NSW stations first to avoid double-counting
756 const GeoVPhysVol* sTGC_top = Trk::GMTreeBrowser::findTopBranch(top, "sTGC_1");
757 const GeoVPhysVol* MM_top = Trk::GMTreeBrowser::findTopBranch(top, "MM_1");
758 if (sTGC_top && sTGC_top != top) {
759 ATH_MSG_DEBUG("sTGC GeoModel branch found:" << sTGC_top->getLogVol()->getName());
760 GeoVolumeCursor vol(sTGC_top);
761 while (!vol.atEnd()) {
762 const GeoVPhysVol* cv = vol.getVolume();
763 const std::string& vname = cv->getLogVol()->getName();
764 if (vname.find("sTGC_1") == std::string::npos) {
765 vol.next();
766 continue;
767 }
768 std::vector<std::pair<const GeoVPhysVol*,
769 std::vector<GMInfo>>>::iterator it =
770 sensitive.begin();
771 while (it < sensitive.end()) {
772 if (vname == (*it).first->getLogVol()->getName() &&
773 m_gmBrowser.compareGeoVolumes(cv, (*it).first, 1.e-3) == 0)
774 break;
775 ++it;
776 }
777
778 if (it == sensitive.end()) {
779 std::vector<std::pair<Amg::Transform3D, int>> cloneList;
780 cloneList.emplace_back(vol.getTransform(), 0);
781 sensitive.emplace_back(cv, cloneList);
782 } else {
783 Amg::Transform3D transf = vol.getTransform();
784 // order transforms to position prototype at phi=0/ 0.125 pi
785 double phiTr = transf.translation().phi();
786 if (phiTr > -0.001 && phiTr < 0.4)
787 (*it).second.insert((*it).second.begin(),
788 std::make_pair(vol.getTransform(), 0));
789 else
790 (*it).second.emplace_back(vol.getTransform(), 0);
791 }
792 vol.next();
793 }
794 }
795
796 if (MM_top && MM_top != top) {
797 ATH_MSG_DEBUG("MM GeoModel branch found:" << MM_top->getLogVol()->getName());
798 GeoVolumeCursor vol(MM_top);
799 while (!vol.atEnd()) {
800 const GeoVPhysVol* cv = vol.getVolume();
801 const std::string& vname = cv->getLogVol()->getName();
802 if (vname.find("MM_1") == std::string::npos) {
803 vol.next();
804 continue;
805 }
806 std::vector<std::pair<const GeoVPhysVol*,
807 std::vector<GMInfo>>>::iterator it =
808 sensitive.begin();
809 while (it < sensitive.end()) {
810 if (vname == (*it).first->getLogVol()->getName() &&
811 m_gmBrowser.compareGeoVolumes(cv, (*it).first, 1.e-3) == 0)
812 break;
813 ++it;
814 }
815
816 if (it == sensitive.end()) {
817 std::vector<std::pair<Amg::Transform3D, int>> cloneList;
818 cloneList.emplace_back(vol.getTransform(), 0);
819 sensitive.emplace_back(cv, cloneList);
820 } else {
821 Amg::Transform3D transf = vol.getTransform();
822 // order transforms to position prototype at phi=0/ 0.125 pi
823 double phiTr = transf.translation().phi();
824 if (phiTr > -0.001 && phiTr < 0.4)
825 (*it).second.insert((*it).second.begin(), std::make_pair(vol.getTransform(), 0));
826 else
827 (*it).second.emplace_back(vol.getTransform(), 0);
828 }
829 vol.next();
830 }
831 }
832
833 GeoVolumeCursor vol(top);
834 while (!vol.atEnd()) {
835 const GeoVPhysVol* cv = &(*(vol.getVolume()));
836 const std::string& vname = cv->getLogVol()->getName();
837 if (vname.find("Station") == std::string::npos &&
838 vname.find("MM_1") == std::string::npos &&
839 vname.find("sTGC_1") == std::string::npos) {
840 vol.next();
841 continue;
842 }
843
844 // TGC stations retrieved at level-1
845 if (vname.substr(0, 1) == "T") {
846
847 for (const auto&[tv, tvTrf] : geoGetVolumes(cv)) {
848 const GeoLogVol* tlv = tv->getLogVol();
849 const Amg::Transform3D transform = vol.getTransform() * tvTrf;
850 const std::string& tgc_name = tlv->getName();
851
852 std::vector<std::pair<const GeoVPhysVol*,
853 std::vector<GMInfo>>>::iterator it =
854 sensitive.begin();
855 while (it < sensitive.end()) {
856 if (tgc_name == (*it).first->getLogVol()->getName() &&
857 m_gmBrowser.compareGeoVolumes(tv, (*it).first, 1.e-3) ==
858 0)
859 break;
860 ++it;
861 }
862
863 if (it == sensitive.end()) {
864 std::vector<std::pair<Amg::Transform3D, int>> cloneList;
865 cloneList.emplace_back(transform, vol.getId().value());
866 sensitive.emplace_back(tv, cloneList);
867 } else {
868 Amg::Transform3D transf = transform;
869 // order transforms to position prototype at phi=0/ 0.125 pi
870 double phiTr = transf.translation().phi();
871 if (phiTr > -0.001 && phiTr < 0.4) {
872 (*it).second.insert((*it).second.begin(),
873 std::make_pair(transform, vol.getId().value()));
874 }
875 else {
876 (*it).second.emplace_back(transform, vol.getId().value());
877 }
878 }
879
880 } // end loop over TGC
881
882 } else {
883
884 std::vector<std::pair<const GeoVPhysVol*,
885 std::vector<GMInfo>>>::iterator it =
886 sensitive.begin();
887 while (it < sensitive.end()) {
888 if (vname == (*it).first->getLogVol()->getName() &&
889 m_gmBrowser.compareGeoVolumes(cv, (*it).first, 1.e-3) == 0)
890 break;
891 ++it;
892 }
893
894 if (it == sensitive.end()) {
895 std::vector<std::pair<Amg::Transform3D, int>> cloneList;
896 cloneList.emplace_back(vol.getTransform(), vol.getId().value());
897 sensitive.emplace_back(cv, cloneList);
898 } else {
899 Amg::Transform3D transf = vol.getTransform();
900 // order transforms to position prototype at phi=0/ 0.125 pi
901 double phiTr = transf.translation().phi();
902 if (phiTr > -0.001 && phiTr < 0.4) {
903 (*it).second.insert((*it).second.begin(),
904 std::make_pair(vol.getTransform(), vol.getId().value()));
905 }
906 else {
907 (*it).second.emplace_back(vol.getTransform(), vol.getId().value());
908 }
909 }
910 } // end non-TGC
911 vol.next();
912 }
913
914 ATH_MSG_DEBUG("Number of muon station types in GeoModel tree:" << sensitive.size());
915
916 return sensitive;
917}
918
919std::unique_ptr<Trk::DetachedTrackingVolume>
921 const GeoVPhysVol* cv,
922 const GMInfo& gmInfo) const {
923 const GeoLogVol* clv = cv->getLogVol();
924 const std::string& vname = clv->getName();
925 ATH_MSG_DEBUG(name() << " building station prototype for " << cv->getLogVol()->getName());
928
929 std::unique_ptr<Trk::DetachedTrackingVolume> typeStat{};
930
931 if (vname.substr(0, 4) == "sTGC" || vname.substr(0, 2) == "MM") {
932 std::string sName = vname.substr(vname.find('-') + 1);
933 Identifier nswId = m_muonStationTypeBuilder->identifyNSW(sName, gmInfo.first);
934
935 if (vname.substr(0, 4) == "sTGC" && m_idHelperSvc->issTgc(nswId)) {
936 return m_muonStationTypeBuilder->process_sTGC(nswId, cv, gmInfo.first);
937 } else if (vname.substr(0, 2) == "MM" && m_idHelperSvc->isMM(nswId)) {
938 return m_muonStationTypeBuilder->process_MM(nswId, cv, gmInfo.first);
939 }
940 }
941
942 if (!m_buildBarrel && vname.compare(0, 1, "B") == 0)
943 return typeStat;
944 if (!m_buildEndcap && vname.compare(0, 1, "E") == 0)
945 return typeStat;
946 if (!m_buildCsc && vname.compare(0, 1, "C") == 0)
947 return typeStat;
948 if (!m_buildTgc && vname.compare(0, 1, "T") == 0)
949 return typeStat;
950
951 int etaphi = gmInfo.second; // retrieve eta/phi indexes
952 int sign = (etaphi < 0) ? -1 : 1;
953 etaphi = sign * etaphi;
954 int is_mirr = etaphi / 1000;
955 etaphi = etaphi - is_mirr * 1000;
956 int eta = etaphi / 100;
957 int phi = etaphi - eta * 100;
958 eta = eta * sign;
959 const MuonGM::MuonStation* gmStation = muonMgr->getMuonStation(vname.substr(0, 3), eta, phi);
960 if (!gmStation) {
961 gmStation = muonMgr->getMuonStation(vname.substr(0, 4), eta, phi);
962 }
963 // assembly ?
964 if (!gmStation) {
965 int etaphi = gmInfo.second; // retrieve eta/phi indexes
966 int a_etaphi = static_cast<int>(etaphi / 100000);
967 int sideC = static_cast<int>(a_etaphi / 10000);
968 a_etaphi -= sideC * 10000;
969 is_mirr = static_cast<int>(a_etaphi / 1000);
970 a_etaphi -= is_mirr * 1000;
971 eta = static_cast<int>(a_etaphi / 100);
972 phi = a_etaphi - eta * 100;
973 if (sideC)
974 eta *= -1;
975 gmStation = muonMgr->getMuonStation(vname.substr(0, 3), eta, phi);
976 }
977 //
978 std::string stname = (vname.compare(0, 1, "T") == 0) ? vname : (clv->getName()).substr(0, vname.size() - 8);
979 //
980 if (stname.compare(0, 1, "B") == 0 && eta < 0) {
981 stname = (clv->getName()).substr(0, vname.size() - 8) + "-";
982 }
983 ATH_MSG_VERBOSE(" new station type " << stname << "," << clv->getShape()->type());
984 ATH_MSG_VERBOSE(" prototype built from eta, phi:" << eta << "," << phi);
985
986 if (stname.compare(0, 2, "CS") == 0 || stname.compare(0, 1, "T") == 0) {
987
988 if (stname.compare(0, 2, "CS") == 0) {
989 auto csc_station = m_muonStationTypeBuilder->processCscStation(cv, stname, cache);
990 // create layer representation
991 auto layerRepr = m_muonStationTypeBuilder->createLayerRepresentation(*csc_station);
992 // create prototype as detached tracking volume
993 auto layerVec = std ::make_unique<std::vector<Trk::Layer*>>(Muon::release(layerRepr.second));
994 typeStat = std::make_unique<Trk::DetachedTrackingVolume>(stname, std::move(csc_station),
995 std::move(layerRepr.first), std::move(layerVec));
996 } else {
997 std::unique_ptr<Trk::TrackingVolume> tgc_station{m_muonStationTypeBuilder->processTgcStation(cv, cache)};
998 // create layer representation
999 auto layerRepr = m_muonStationTypeBuilder->createLayerRepresentation(*tgc_station);
1000 // create prototype as detached tracking volume
1001 auto layerVec = std ::make_unique<std::vector<Trk::Layer*>>(Muon::release(layerRepr.second));
1002 typeStat = std::make_unique<Trk::DetachedTrackingVolume>(stname, std::move(tgc_station),
1003 std::move(layerRepr.first), std::move(layerVec));
1004 }
1005
1006 } else {
1007 const GeoShape* shapeS = clv->getShape();
1008 while (shapeS->type() != "Trd") {
1009 if (shapeS->type() == "Shift") {
1010 const GeoShapeShift* shift = dynamic_cast<const GeoShapeShift*>(shapeS);
1011 shapeS = shift->getOp();
1012 } else if (shapeS->type() == "Subtraction") {
1013 const GeoShapeSubtraction* sub = dynamic_cast<const GeoShapeSubtraction*>(shapeS);
1014 shapeS = sub->getOpA();
1015 } else if (shapeS->type() == "Union") {
1016 const GeoShapeUnion* uni = dynamic_cast<const GeoShapeUnion*>(shapeS);
1017 shapeS = uni->getOpA();
1018 } else {
1019 ATH_MSG_WARNING("unexpected station shape ? "<< shapeS->type() << ", station not built");
1020 break;
1021 }
1022 }
1023 const GeoTrd* trd = dynamic_cast<const GeoTrd*>(shapeS);
1024
1025 double halfX1{0.}, halfX2{0.}, halfY1{0.}, halfY2{0.}, halfZ{0.};
1026 if (trd) {
1027 //
1028 halfX1 = trd->getXHalfLength1();
1029 halfX2 = trd->getXHalfLength2();
1030 halfY1 = trd->getYHalfLength1();
1031 halfY2 = trd->getYHalfLength2();
1032 halfZ = trd->getZHalfLength();
1033
1034 // define enveloping volume
1035 std::unique_ptr<Trk::TrackingVolumeArray> confinedVolumes{};
1036 std::vector<std::unique_ptr<Trk::Layer>> confinedLayers{};
1037 std::unique_ptr<Trk::Volume> envelope;
1038 std::string shape = "Trd";
1039 if (halfX1 == halfX2 && halfY1 == halfY2)
1040 shape = "Box";
1041 if (shape == "Box") {
1042 auto envBounds = std::make_shared<Trk::CuboidVolumeBounds>(halfX1, halfY1, halfZ);
1043 // station components
1044 confinedVolumes = m_muonStationTypeBuilder->processBoxStationComponents(cv, *envBounds, cache);
1045 if (!confinedVolumes) {
1046 confinedLayers = m_muonStationTypeBuilder->processBoxComponentsArbitrary(cv, *envBounds, cache);
1047 }
1048 // enveloping volume
1049 envelope = std::make_unique<Trk::Volume>(nullptr, std::move(envBounds));
1050 } else if (shape == "Trd") {
1051 std::unique_ptr<Trk::TrapezoidVolumeBounds> envBounds{};
1052 Amg::Transform3D transf{Amg::Transform3D::Identity()};
1053 if (halfY1 == halfY2) {
1054 envBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(halfX1, halfX2, halfY1, halfZ);
1055 ATH_MSG_VERBOSE("CAUTION!!!: this trapezoid volume does not require XY -> YZ switch");
1056 }
1057 if (halfY1 != halfY2 && halfX1 == halfX2) {
1058 transf = Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2);
1059 envBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(halfY1, halfY2, halfZ, halfX1);
1060 }
1061 if (halfX1 != halfX2 && halfY1 != halfY2) {
1062 ATH_MSG_WARNING("station envelope arbitrary trapezoid?"<< stname);
1063 }
1064 if (envBounds) {
1065 // station components
1066 confinedVolumes = m_muonStationTypeBuilder->processTrdStationComponents(cv, *envBounds, cache);
1067 // enveloping volume
1068 envelope = std::make_unique<Trk::Volume>(makeTransform(transf), std::move(envBounds));
1069 }
1070 }
1071
1072 if (envelope) {
1073 // ready to build the station prototype
1074 std::unique_ptr<Trk::TrackingVolume> newType{};
1075 if (!confinedLayers.empty()) {
1076 auto confinedLayerPtr = std::make_unique<std::vector<Trk::Layer*>>(Muon::release(confinedLayers));
1077 newType = std::make_unique<Trk::TrackingVolume>(*envelope, m_muonMaterial, std::move(confinedLayerPtr), stname);
1078 } else {
1079 newType = std::make_unique<Trk::TrackingVolume>(*envelope, m_muonMaterial, nullptr, std::move(confinedVolumes), stname);
1080 }
1081
1082
1083 // identify prototype
1084 if ((stname.compare(0, 1, "B") == 0 || stname.compare(0, 1, "E") == 0))
1085 identifyPrototype(*newType, eta, phi, gmStation->getTransform(), muonMgr);
1086
1087 // create layer representation
1088 auto layerRepr = m_muonStationTypeBuilder->createLayerRepresentation(*newType);
1089
1090 // create prototype as detached tracking volume
1091 auto layerVec = std::make_unique<std::vector<Trk::Layer*>>(Muon::release(layerRepr.second));
1092 typeStat = std::make_unique<Trk::DetachedTrackingVolume>(stname, std::move(newType),
1093 std::move(layerRepr.first),
1094 std::move(layerVec));
1095 }
1096 }
1097 } // end new station type
1098
1099 ATH_MSG_DEBUG(" station prototype built for " << vname);
1100
1102 return typeStat;
1103}
1104
1105Identifier MuonStationBuilderImpl::resolveId(const std::string& vname, const GMInfo& gm_info, int& eta, int& phi,
1106 const MuonGM::MuonDetectorManager* muonMgr) const {
1107
1108 Identifier stId(0);
1109
1110 int etaphi = gm_info.second; // retrieve eta/phi indexes
1111 int sign = (etaphi < 0) ? -1 : 1;
1112 etaphi = sign * etaphi;
1113 int is_mirr = etaphi / 1000;
1114 etaphi = etaphi - is_mirr * 1000;
1115 eta = etaphi / 100;
1116 phi = etaphi - eta * 100;
1117 eta = eta * sign;
1118 const MuonGM::MuonStation* gmStation =
1119 muonMgr->getMuonStation(vname.substr(0, 3), eta, phi);
1120 // try to retrieve
1121 if (!gmStation) {
1122 gmStation = muonMgr->getMuonStation(vname.substr(0, 4), eta, phi);
1123 }
1124 // assembly ?
1125 if (!gmStation) {
1126 int etaphi = gm_info.second; // retrieve eta/phi indexes
1127 int a_etaphi = static_cast<int>(etaphi / 100000);
1128 int sideC = static_cast<int>(a_etaphi / 10000);
1129 a_etaphi -= sideC * 10000;
1130 is_mirr = static_cast<int>(a_etaphi / 1000);
1131 a_etaphi -= is_mirr * 1000;
1132 eta = static_cast<int>(a_etaphi / 100);
1133 phi = a_etaphi - eta * 100;
1134 if (sideC)
1135 eta *= -1;
1136 gmStation = muonMgr->getMuonStation(vname.substr(0, 3), eta, phi);
1137 }
1138 //
1139 if (!gmStation)
1140 ATH_MSG_WARNING("Muon station not found! " << vname << "," << eta << ","
1141 << phi);
1142
1143 std::string stName;
1144 if (vname.compare(0, 1, "T") == 0 || vname.compare(0, 1, "C") == 0) {
1145 stName = vname.substr(0, 4);
1146 } else {
1147 stName = (vname.substr(0, vname.size() - 8));
1148 if (stName.compare(0, 1, "B") == 0 && eta < 0) {
1149 stName = vname.substr(0, vname.size() - 8) + "-";
1150 }
1151 }
1152 if (!gmStation)
1153 return stId;
1154 Amg::Transform3D transf = gmStation->getTransform();
1155 bool is_valid{false};
1156 if (m_idHelperSvc->hasCSC() && stName.compare(0, 1, "C") == 0) {
1157 stId = m_idHelperSvc->cscIdHelper().elementID(vname.substr(0, 3), eta,
1158 phi, is_valid);
1159 }
1160 // adjust eta,phi
1161 if (vname.compare(0, 1, "C") == 0) {
1162 eta = 1;
1163 if (transf.translation().z() < 0)
1164 eta = 0;
1165 double phic = transf.translation().phi() + 0.1;
1166 phi =
1167 static_cast<int>(phic < 0 ? 4 * phic / M_PI + 8 : 4 * phic / M_PI);
1168 }
1169 if (vname.compare(0, 1, "T") == 0) {
1170 bool az = true;
1171 std::string sub = vname.substr(7, 2);
1172 if (transf.translation().z() < 0)
1173 az = false;
1174 if (sub == "01")
1175 eta = az ? 5 : 4;
1176 else if (sub == "02")
1177 eta = az ? 5 : 4;
1178 else if (sub == "03")
1179 eta = az ? 6 : 3;
1180 else if (sub == "04")
1181 eta = az ? 7 : 2;
1182 else if (sub == "05")
1183 eta = az ? 8 : 1;
1184 else if (sub == "06")
1185 eta = az ? 5 : 4;
1186 else if (sub == "07")
1187 eta = az ? 5 : 4;
1188 else if (sub == "08")
1189 eta = az ? 6 : 3;
1190 else if (sub == "09")
1191 eta = az ? 7 : 2;
1192 else if (sub == "10")
1193 eta = az ? 8 : 1;
1194 else if (sub == "11")
1195 eta = az ? 9 : 0;
1196 else if (sub == "12")
1197 eta = az ? 5 : 4;
1198 else if (sub == "13")
1199 eta = az ? 5 : 4;
1200 else if (sub == "14")
1201 eta = az ? 6 : 3;
1202 else if (sub == "15")
1203 eta = az ? 7 : 2;
1204 else if (sub == "16")
1205 eta = az ? 8 : 1;
1206 else if (sub == "17")
1207 eta = az ? 9 : 0;
1208 else if (sub == "18")
1209 eta = az ? 5 : 4;
1210 else if (sub == "19")
1211 eta = az ? 5 : 4;
1212 else if (sub == "20")
1213 eta = az ? 5 : 4;
1214 else if (sub == "21")
1215 eta = az ? 5 : 4;
1216 else if (sub == "22")
1217 eta = az ? 5 : 4;
1218 }
1219 if (m_idHelperSvc->hasTGC() && stName[0] == 'T') {
1220 int etaSt = eta - 4;
1221 if (eta < 5)
1222 etaSt = eta - 5;
1223 double phic = transf.translation().phi();
1224 if (vname.compare(2, 1, "E") == 0 && vname.compare(0, 3, "T4E") != 0)
1225 phi = static_cast<int>(phic < 0 ? 24 * phic / M_PI + 48
1226 : 24 * phic / M_PI);
1227 else
1228 phi = static_cast<int>(phic < 0 ? 12 * phic / M_PI + 24
1229 : 12 * phic / M_PI);
1230 phi++;
1231 stId = m_idHelperSvc->tgcIdHelper().elementID(vname.substr(0, 3), etaSt,
1232 phi, is_valid);
1233 } else if (m_idHelperSvc->hasRPC() && stName.compare(0, 3, "BML") == 0) {
1234 stId = m_idHelperSvc->rpcIdHelper().elementID(vname.substr(0, 3), eta,
1235 phi, 1, is_valid);
1236 } else if (m_idHelperSvc->hasMDT() && stName.compare(0, 1, "C") != 0) {
1237 stId = m_idHelperSvc->mdtIdHelper().elementID(vname.substr(0, 3), eta,
1238 phi, is_valid);
1239 }
1240 if (!is_valid || !stId.get_compact()) {
1241 ATH_MSG_DEBUG("identifier of the station not found:"
1242 << vname << "," << eta << "," << phi);
1243 if (!stId.get_compact())
1244 return Identifier(0);
1245 }
1246 return stId;
1247}
1248
1249void MuonStationBuilderImpl::checkLayerId(std::string_view comment, const MuonGM::MuonDetectorManager* muonMgr,
1250 Identifier id, const Trk::Layer* lay) const {
1251
1252 // RE
1253 if (m_idHelperSvc->isMdt(id)) {
1254 const MuonGM::MdtReadoutElement* mdtRE = muonMgr->getMdtReadoutElement(id);
1255 constexpr double tol = 0.5*Gaudi::Units::mm;
1256 if (mdtRE && !lay->surfaceRepresentation().isOnSurface(mdtRE->transform(id).translation(), tol, tol)) {
1257 ATH_MSG_DEBUG(__FILE__<<":"<<__LINE__<<" "<<comment << ":tube(id) "
1258 <<m_idHelperSvc->toString(id)<<" "<<Amg::toString(mdtRE->transform(id).translation())
1259 <<" not on surface:"<<lay->surfaceRepresentation()<<std::endl<<
1260 " "<<Amg::toString(lay->surfaceRepresentation().transform().inverse()*(mdtRE->transform(id).translation())) );
1261 }
1262 } else if (m_idHelperSvc->isRpc(id)) {
1263 const MuonGM::RpcReadoutElement* rpcRE = muonMgr->getRpcReadoutElement(id);
1264 Amg::Transform3D trid = rpcRE->transform(id);
1265 Amg::Transform3D check_layer_identity = lay->surfaceRepresentation().transform().inverse() * trid;
1266 if (!Amg::doesNotDeform(check_layer_identity)) {
1267 ATH_MSG_DEBUG(__FILE__<<":"<<__LINE__<<" "<<comment<<" "<<Amg::toString(check_layer_identity));
1268 }
1269
1270 } else if (m_idHelperSvc->isTgc(id)) {
1271 const Amg::Transform3D trid = muonMgr->getTgcReadoutElement(id)->transform(id);
1272 Amg::Transform3D check_layer_identity = lay->surfaceRepresentation().transform().inverse() * trid;
1273 if (!Amg::doesNotDeform(check_layer_identity)) {
1274 ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" "<<comment <<" "<<Amg::toString(check_layer_identity));
1275 }
1276 }
1277}
1278}
const boost::regex ref(r_ef)
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar perp() const
perp method - perpendicular length
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
void swap(DataVector< T > &a, DataVector< T > &b)
See DataVector<T, BASE>::swap().
Visitor to process all volumes under a GeoModel node.
GeoVolumeVec_t geoGetVolumes(const GeoGraphNode *node, int depthLimit=1, int sizeHint=20)
Return the child volumes and associated transforms.
int sign(int a)
@ top
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Identifier channelID(int stationName, int stationEta, int stationPhi, int chamberLayer, int wireLayer, int measuresPhi, int strip) const
value_type get_compact() const
Get the compact id.
value_type get_compact() const
Get the compact id.
Identifier32 get_identifier32() const
Get the 32-bit version Identifier, will be invalid if >32 bits needed.
int multilayer(const Identifier &id) const
Access to components of the ID.
int tube(const Identifier &id) const
int tubeLayer(const Identifier &id) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int tubeLayer, int tube) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
int multilayer(const Identifier &id) const
Amg::Vector3D tubePos(const Identifier &id) const
Returns the global position of the given tube.
int getNLayers() const
Returns the number of tube layers inside the multilayer.
virtual const Amg::Transform3D & transform(const Identifier &id) const override final
Return local to global transform associated with this identifier.
virtual const Amg::Vector3D & center(const Identifier &) const override final
Return the center of the surface associated with this identifier In the case of silicon it returns th...
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
virtual const Amg::Vector3D & center() const override
Return the center of the element.
virtual const Amg::Transform3D & transform() const override
Return local to global transform.
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const RpcReadoutElement * getRpcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
static constexpr int NCscStEtaOffset
Identifier <-> AMDB conversion constants in use.
const MdtReadoutElement * getMdtReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const MuonStation * getMuonStation(const std::string &stName, int eta, int phi) const
const TgcReadoutElement * getTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const CscReadoutElement * getCscReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
Identifier identify() const override final
Returns the ATLAS Identifier of the MuonReadOutElement.
Amg::Transform3D getTransform() const
An RpcReadoutElement corresponds to a single RPC module; therefore typicaly a barrel muon station con...
virtual int numberOfLayers(bool measphi=true) const override final
number of layers in phi/eta projection, same for eta/phi planes
A TgcReadoutElement corresponds to a single TGC chamber; therefore typically a TGC station contains s...
Amg::Vector3D channelPos(const Identifier &id) const
Returns the position of the active channel (wireGang or strip)
int stationNameIndex(const std::string &name) const
int stationEta(const Identifier &id) const
int stationName(const Identifier &id) const
void identifyLayers(Trk::DetachedTrackingVolume *, Identifier, int, int, const MuonGM::MuonDetectorManager *) const
Trk::Material m_muonMaterial
the material
void identifyNSWLayers(Trk::DetachedTrackingVolume &station, const Identifier &id) const
virtual StatusCode initialize() override
Gaudi::Property< bool > m_buildEndcap
void checkLayerId(std::string_view comment, const MuonGM::MuonDetectorManager *muonMgr, Identifier id, const Trk::Layer *lay) const
void identifyPrototype(Trk::TrackingVolume &station, int eta, int phi, const Amg::Transform3D &transf, const MuonGM::MuonDetectorManager *muonMgr) const
ToolHandle< Muon::MuonStationTypeBuilder > m_muonStationTypeBuilder
Helper Tool to create TrackingVolume Arrays.
DetachedVolVec buildDetachedTrackingVolumesImpl(const MuonGM::MuonDetectorManager *muonMgr, bool blend=false) const
void glueComponents(Trk::DetachedTrackingVolume *) const
Identifier resolveId(const std::string &vname, const GMInfo &gm_info, int &eta, int &phi, const MuonGM::MuonDetectorManager *muonMgr) const
std::pair< Amg::Transform3D, int > GMInfo
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
std::vector< std::unique_ptr< Trk::DetachedTrackingVolume > > DetachedVolVec
std::unique_ptr< Trk::DetachedTrackingVolume > buildDetachedTrackingVolumeType(const MuonGM::MuonDetectorManager *muonMgr, const GeoVPhysVol *gv, const GMInfo &info) const
ToolHandle< Trk::ITrackingVolumeHelper > m_trackingVolumeHelper
Helper Tool to create TrackingVolumes.
std::vector< std::pair< const GeoVPhysVol *, std::vector< GMInfo > > > retrieveGMsensitive(const MuonGM::MuonDetectorManager *muonMgr) const
MuonStationBuilderImpl(const std::string &, const std::string &, const IInterface *)
Gaudi::Property< bool > m_buildBarrel
void getNSWStationsForTranslation(const GeoVPhysVol *pv, const std::string &name, const Amg::Transform3D &, std::vector< std::pair< std::pair< const GeoLogVol *, Trk::MaterialProperties * >, std::vector< Amg::Transform3D > > > &vols, std::vector< std::string > &volNames) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int doubletR, int doubletZ, int doubletPhi, int gasGap, int measuresPhi, int strip) const
int gasGap(const Identifier &id) const override
get the hashes
Identifier elementID(int stationName, int stationEta, int stationPhi, int doubletR) const
int doubletPhi(const Identifier &id) const
int doubletR(const Identifier &id) const
int strip(const Identifier &id) const
int doubletZ(const Identifier &id) const
Identifier elementID(int stationName, int stationEta, int stationPhi) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int gasGap, int isStrip, int channel) const
A generic symmetric BinUtility, for fully symmetric binning in terms of binning grid and binning type...
Definition BinUtility.h:39
Binned Array for avoiding map searches/.
Definition BinnedArray.h:36
virtual const BinUtility * binUtility() const =0
Return the BinUtility.
virtual unsigned int arrayObjectsNumber() const =0
Number of Entries in the Array.
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
Bounds for a cubical Volume, the decomposeToSurfaces method creates a vector of 6 surfaces:
Base Class for a navigation object (active/passive) in the Tracking realm.
const std::string & name() const
returns the Name
const Layer * layerRepresentation() const
returns layer representation
const TrackingVolume * trackingVolume() const
returns the TrackingVolume
static const GeoVPhysVol * findTopBranch(const GeoVPhysVol *gv, std::string_view name)
search of top branch : returns mother volume for children matching name
static Material convert(const GeoMaterial *gm)
Single conversion , input type GeoMaterial - output type Trk::MaterialProperties.
Base Class for a Detector Layer in the Tracking realm.
Definition Layer.h:72
int layerType() const
get the Layer coding
virtual const Surface & surfaceRepresentation() const =0
Transforms the layer into a Surface representation for extrapolation.
void setRef(double)
set the reference measure
void setLayerType(int identifier)
set the Layer coding
Material with information about thickness of material.
float thicknessInX0() const
Return the radiationlength fraction.
void addMaterial(const Material &mp, float dInX0)
Material averaging.
float x0() const
Return the radiation length.
float thickness() const
Return the thickness in mm.
A common object to be contained by.
Definition Material.h:117
float x0() const
Definition Material.h:227
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
virtual bool isOnSurface(const Amg::Vector3D &glopo, const BoundaryCheck &bchk=true, double tol1=0., double tol2=0.) const
This method returns true if the GlobalPosition is on the Surface for both, within or without check of...
Definition Surface.cxx:123
const Amg::Vector3D & center() const
Returns the center position of the Surface.
Full Volume description used in Tracking, it inherits from Volume to get the geometrical structure,...
const LayerArray * confinedLayers() const
Return the subLayer array.
const Layer * associatedLayer(const Amg::Vector3D &gp) const
Return the associated Layer.
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
const TrackingVolume * associatedSubVolume(const Amg::Vector3D &gp) const
Return the associated sub Volume, returns THIS if no subVolume exists.
const std::string & volumeName() const
Returns the VolumeName - for debug reason, might be depreciated later.
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition Volume.cxx:72
int multilayer(const Identifier &id) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channelType, int channel) const
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
bool doesNotDeform(const Amg::Transform3D &trans)
Checks whether the linear part of the transformation rotates or stetches any of the basis vectors.
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
Amg::Transform3D getRotateY3D(double angle)
get a rotation transformation around Y-axis
const std::string & stName(StIndex index)
convert StIndex into a string
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
std::unique_ptr< Amg::Transform3D > makeTransform(const Amg::Transform3D &trf)
MuonStationBuilderImpl::GMInfo GMInfo
std::vector< ObjType * > release(std::vector< std::unique_ptr< ObjType > > &objVec)
std::span< T > ArraySpan
BoundarySurfaceFace
Enum to describe the position of the BoundarySurface respectively to the frame orientatin of the volu...
BinnedArray< TrackingVolume > TrackingVolumeArray
simply for the eye