ATLAS Offline Software
Loading...
Searching...
No Matches
ChamberAssembleTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
12
13#include "Acts/Geometry/CuboidVolumeBounds.hpp"
14#include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
15#include "Acts/Surfaces/RectangleBounds.hpp"
16#include "Acts/Surfaces/TrapezoidBounds.hpp"
17#include "Acts/Surfaces/PlaneSurface.hpp"
18#include "Acts/Geometry/Volume.hpp"
19#include "Acts/Surfaces/detail/PlanarHelper.hpp"
20
21#include "GeoModelHelpers/TransformToStringConverter.h"
22#include "GeoModelKernel/GeoDefinitions.h"
23
25
26#include <sstream>
27
28
29using namespace Acts::UnitLiterals;
30using namespace Acts::PlanarHelper;
31
32namespace MuonGMR4{
33
37
39 return re->idHelperSvc()->toStringDetEl(re->identify());
40}
41std::string toString(const ChamberPtr& ch) {
42 return ch->identString();
43}
46 Acts::SurfaceBoundFactory& surfBoundSet){
47 if (volBounds.type() == Acts::VolumeBounds::BoundsType::eCuboid) {
48 return surfBoundSet.makeBounds<Acts::RectangleBounds>(halfXlowY(volBounds), halfY(volBounds));
49 } else if (volBounds.type() == Acts::VolumeBounds::BoundsType::eTrapezoid) {
50 return surfBoundSet.makeBounds<Acts::TrapezoidBounds>(halfXlowY(volBounds) , halfXhighY(volBounds) , halfY(volBounds));
51 }
52 return nullptr;
53}
54template <typename ReObjType>
57 const std::vector<ReObjType>& constituents,
58 const Acts::Transform3& toCenter,
59 Acts::VolumeBoundFactory& volBoundSet,
60 Acts::SurfaceBoundFactory& surfBoundSet,
61 const double margin) const
62 requires (Acts::PointerConcept<ReObjType>){
63 const Acts::GeometryContext tgContext{gctx.context()};
64 TrapezoidBoundsExpander expandBounds{toCenter};
65 expandBounds.setMargin(margin);
66 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Construct a new bounding box from "<<typeid(ReObjType).name()
67 <<" spanning over "<<constituents.size()<<" elements, align trf: "
68 <<Amg::toString(toCenter));
69 for (const auto& element : constituents) {
70 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Append new element "<<toString(element));
71 if constexpr(std::is_base_of_v<MuonReadoutElement, Acts::RemovePointer_t<ReObjType>>) {
72 expandBounds.expand(tgContext, *element, volBoundSet);
73 } else {
74 expandBounds.expand(tgContext, *element);
75 }
76 }
77 auto volBounds = expandBounds.makeBounds(volBoundSet);
78 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Box centered "
79 <<Amg::toString(expandBounds.boxMidPoint())<<" "<<(*volBounds));
80 return std::make_tuple(expandBounds.boxMidPoint(), volBounds,
81 surfaceBounds(*volBounds, surfBoundSet));
82}
83
85 ATH_CHECK(m_idHelperSvc.retrieve());
87 auto mdtStationIndex = [this] (const std::string& stName) {
88 return m_idHelperSvc->hasMDT() ? m_idHelperSvc->mdtIdHelper().stationNameIndex(stName) : -1;
89 };
90 auto tgcStationIndex = [this] (const std::string& stName) {
91 return m_idHelperSvc->hasTGC() ? m_idHelperSvc->tgcIdHelper().stationNameIndex(stName) : -1;
92 };
93
94 const std::unordered_set<int> stIndicesEM{mdtStationIndex("EML"), mdtStationIndex("EMS"),
95 tgcStationIndex("T1E"), tgcStationIndex("T1F"),
96 tgcStationIndex("T2E"), tgcStationIndex("T2F"),
97 tgcStationIndex("T3E"), tgcStationIndex("T3F")};
98
99
100 std::unordered_set<Identifier> BIS78_ids{};
101 auto fillBIS78 = [&BIS78_ids, this](const MuonIdHelper& idHelper) {
102 const int BIS = idHelper.stationNameIndex("BIS");
103 std::copy_if(idHelper.detectorElement_begin(), idHelper.detectorElement_end(), std::inserter(BIS78_ids, BIS78_ids.end()),
104 [&](const Identifier& detId){
105 int stEta = idHelper.stationEta(detId);
106 if (m_isRun4) {
107 stEta = std::abs(stEta);
108 }
109 return stEta >= 7 && idHelper.stationName(detId) == BIS;
110 });
111 };
112 if (m_idHelperSvc->hasMDT()) {
113 fillBIS78(m_idHelperSvc->mdtIdHelper());
114 }
115 if (m_idHelperSvc->hasRPC()) {
116 fillBIS78(m_idHelperSvc->rpcIdHelper());
117 }
118
119 std::vector<MuonReadoutElement*> allReadOutEles = mgr.getAllReadoutElements();
120
121 std::vector<chamberArgs> envelopeCandidates{};
122
124 for (const MuonReadoutElement* readOutEle : allReadOutEles) {
125 std::vector<chamberArgs>::iterator exist = std::ranges::find_if(envelopeCandidates,
126 [this, readOutEle, &stIndicesEM](const chamberArgs& args){
127 const MuonReadoutElement* refEle = args.detEles.front();
128 const Identifier refId = refEle->identify();
129 const Identifier testId = readOutEle->identify();
132 if (Acts::copySign(1, refEle->stationEta()) *
133 Acts::copySign(1, readOutEle->stationEta()) < 0) {
134 return false;
135 }
137 if (m_idHelperSvc->sector(testId) != m_idHelperSvc->sector(refId)) {
138 return false;
139 }
140 if (stIndicesEM.count(readOutEle->stationName()) &&
141 stIndicesEM.count(refEle->stationName())) {
142 return true;
143 }
144 // /// Summarize all readout element in the same sector & layer
146 return readOutEle->chamberIndex() == refEle->chamberIndex();
147 });
149 if (exist == envelopeCandidates.end()) {
150 ATH_MSG_VERBOSE(__func__<<" () "<<__LINE__<<" - Open envelope "<<(envelopeCandidates.size()+1)
151 <<" for "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
152 <<", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
153 <<", chIdx: "<<Muon::MuonStationIndex::chName(readOutEle->chamberIndex()));
154 envelopeCandidates.emplace_back().detEles.push_back(readOutEle);
155 } else {
156 ATH_MSG_VERBOSE(__func__<<" () "<<__LINE__<<" - Attach "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
157 <<", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
158 <<", chIdx: "<<Muon::MuonStationIndex::chName(readOutEle->chamberIndex())<<" to envelope "
159 <<(std::distance(envelopeCandidates.begin(), exist) + 1)<<". ");
160 exist->detEles.push_back(readOutEle);
161 }
162 }
164 ActsTrk::GeometryContext gctx{};
165
166
167 Acts::VolumeBoundFactory volBoundSet{};
168 Acts::SurfaceBoundFactory surfBoundSet{};
169 unsigned candId{0};
170 for (chamberArgs& candidate : envelopeCandidates) {
171 std::unordered_set<Identifier> reIds{};
172
173 ATH_MSG_DEBUG(__func__<<" () "<<__LINE__<<" - New envelope candidate ");
176 sectorArgs.id = (++candId);
177 using namespace Muon::MuonStationIndex;
178 std::vector<std::vector<const MuonReadoutElement*>> chamberElements{};
179 if (toStationIndex(candidate.detEles.front()->chamberIndex()) != StIndex::EI) {
181 std::map<PVConstLink, std::vector<const MuonReadoutElement*>> stationMap{};
183 for (const MuonReadoutElement* re : candidate.detEles) {
186 if (BIS78_ids.count(re->identify())) {
187 stationMap[re->getMaterialGeom()].push_back(re);
188 } else {
189 stationMap[re->getMaterialGeom()->getParent()].push_back(re);
190 }
191 }
192 for (auto& [parent, stationEles ]: stationMap){
193 chamberElements.push_back(std::move(stationEles));
194 }
195 } else {
198 std::vector<std::vector<const MuonReadoutElement*>> endcapEles(2);
199
200 for (const MuonReadoutElement* sortMe : candidate.detEles){
201 if (sortMe->detectorType() == ActsTrk::DetectorType::Tgc) {
202 endcapEles.emplace_back(1, sortMe);
203 } else {
204 endcapEles[sortMe->detectorType() == ActsTrk::DetectorType::sTgc ||
205 sortMe->detectorType() == ActsTrk::DetectorType::Mm].push_back(sortMe);
206 }
207 }
208 for (auto& stationEles : endcapEles) {
209 if (!stationEles.empty()) {
210 chamberElements.push_back(std::move(stationEles));
211 }
212 }
213 }
214
215 for (auto& detEles: chamberElements) {
216 const MuonReadoutElement* refEle = detEles.front();
217 const Acts::Transform3 toChambCentre = refEle->globalToLocalTransform(gctx);
218 ATH_MSG_DEBUG(__func__<<" () "<<__LINE__<<" - New chamber candidate "<<m_idHelperSvc->toStringChamber(refEle->identify()));
219 const auto[chamberCentre, chamberBox, planeBounds] = boundingBox(gctx, detEles, toChambCentre, volBoundSet,
220 surfBoundSet, 0.1*Gaudi::Units::cm);
221 chamberArgs chambArgs{};
222 chambArgs.detEles = std::move(detEles);
223 chambArgs.bounds = chamberBox;
224 chambArgs.placement = std::make_unique<ActsTrk::VolumePlacement>(*refEle, chamberCentre);
225 auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Transform3::Identity(), planeBounds);
226 chambArgs.placement->connectCenterSurface(surface);
227 chambArgs.surface = surface;
228 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
229 for (const MuonReadoutElement* re : newChamber->readoutEles()) {
230 reIds.insert(re->identify());
231 mgr.getReadoutElement(re->identify())->setChamberLink(newChamber);
232 ATH_MSG_VERBOSE(__func__<<" () "<<__LINE__<<" - Chamber element: "<<m_idHelperSvc->toStringDetEl(re->identify()));
233
234 }
235 ATH_MSG_DEBUG(__func__<<" () "<<__LINE__<<" - Created new chamber: "<<(*newChamber));
236 }
237 if (sectorArgs.chambers.empty()) {
238 continue;
239 }
240 std::ranges::sort(sectorArgs.chambers, [](const SpectrometerSector::ChamberPtr& a,
242 return (*a) < (*b);
243 });
244
245 const Acts::Transform3 toCenter = sectorArgs.chambers.front()->globalToLocalTransform(gctx);
246 const auto [envelopeCentre, envelopeBox, envelopePlane] = boundingBox(gctx, sectorArgs.chambers, toCenter,
247 volBoundSet, surfBoundSet, 2.* Gaudi::Units::cm);
248
249 sectorArgs.bounds = envelopeBox;
250 sectorArgs.localToGlobalTrf = make_intrusive<GeoAlignableTransform>(toCenter.inverse() * envelopeCentre);
252 sectorArgs.placement = std::make_unique<ActsTrk::VolumePlacement>(ActsTrk::DetectorType::Csc,
253 sectorArgs.localToGlobalTrf);
254
255 auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Transform3::Identity(), envelopePlane);
256 sectorArgs.placement->connectCenterSurface(surface);
257 sectorArgs.surface = surface ;
258 const Acts::Transform3 globalToSector = sectorArgs.placement->globalToLocalTransform(gctx.context());
259
261 for (auto & chamber : sectorArgs.chambers){
262 // split by readout elements - MDT multilayers and trigger chambers for the sector
263 for (auto & RE : chamber->readoutEles()){
264 // get the center of the element in the sector frame
265 const Acts::Transform3& chamberToGlobal{RE->localToGlobalTransform(gctx)};
266 const Amg::Vector3D origin = (globalToSector * chamberToGlobal).translation();
267 // and then add the bounds of the element - this is technology dependent
268 sectorArgs.detectorLocs.emplace_back(origin, RE, BoundsExpander::makeBounds(*RE, volBoundSet));
269 }
270 }
272 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
273
274 for (const Identifier& chId : reIds) {
275 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
276 }
277 mgr.addSpectrometerSector(std::move(newSector));
278 }
279 return StatusCode::SUCCESS;
280}
281
282}
const std::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_VERBOSE(x,...)
static Double_t a
@ BIS
Definition RegSelEnums.h:11
Acts::GeometryContext context() const
static std::shared_ptr< Acts::VolumeBounds > makeBounds(const MuonGMR4::MuonReadoutElement &readoutElement, Acts::VolumeBoundFactory &boundFactory)
Crate volume bounds that enclose the readout element from the central localToGlobalTransform.
const Acts::Transform3 & boxMidPoint() const
Returns the transform from the nominal volume center to the middle point to all seen vertices.
std::shared_ptr< const Acts::PlanarBounds > SurfBoundPtr_t
Abrivation of the surface bounds.
std::tuple< Acts::Transform3, VolBoundPtr_t, SurfBoundPtr_t > TrfWithBounds
Abrivation of the volume transform together with a set of volume & surface bounds.
Acts::VolumeBounds VolBounds_t
Abrivation of the volume bounds.
virtual StatusCode buildReadOutElements(MuonDetectorManager &mgr) override final
TrfWithBounds boundingBox(const ActsTrk::GeometryContext &gctx, const std::vector< ReObjType > &constituents, const Acts::Transform3 &globToLoc, Acts::VolumeBoundFactory &volBoundSet, Acts::SurfaceBoundFactory &surfBoundSet, const double margin) const
builds the bounding box trapezoidal volume bounds from the set of readout elements Returns a pair of ...
std::shared_ptr< VolBounds_t > VolBoundPtr_t
Abrivation of the Volume bound ptr.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
static SurfBoundPtr_t surfaceBounds(const VolBounds_t &volBounds, Acts::SurfaceBoundFactory &surfBoundSet)
Construct surface bounds which measure equal sizes in halfXlow/halfXhigh & halfY as the parsed volume...
Chamber represent the volume enclosing a muon station.
Definition Chamber.h:29
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
Acts::Transform3 globalToLocalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the global ATLAS coordinate system into the local coordinate system o...
GeoModel::TransientConstSharedPtr< Chamber > ChamberPtr
virtual std::shared_ptr< Acts::VolumeBounds > makeBounds(Acts::VolumeBoundFactory &factory) override final
void setMargin(const double margin)
Apply an extra margin to all four bound dimensions.
virtual void expand(const Acts::GeometryContext &tgContext, const Acts::Volume &volume) override final
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW).
@ Csc
Thin gap champers.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 1 > Vector3D
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
double halfY(const Acts::VolumeBounds &bounds)
Returns the half-Y length for the parsed volume bounds (Trapezoid/ Cuboid).
Chamber::defineArgs chamberArgs
std::string toString(const MuonGMR4::MuonReadoutElement *re)
ChamberAssembleTool::VolBoundPtr_t VolBoundPtr_t
SpectrometerSector::ChamberPtr ChamberPtr
double halfXhighY(const Acts::VolumeBounds &bounds)
Returns the half-Y length @ posiive Y for the parsed volume bounds (Trapezoid/ Cuboid).
double halfXlowY(const Acts::VolumeBounds &bounds)
Returns the half-X length @ negative Y for the parsed volume bounds (Trapezoid/ Cuboid).
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
const std::string & chName(ChIndex index)
convert ChIndex into a string
unsigned id
Unique Identifier integer of the sector.