ATLAS Offline Software
Loading...
Searching...
No Matches
MuonGMR4::ChamberAssembleTool Class Reference

Assembly tool to produce the Acts envolpe volumes around the muon stations & also to construct the spectrometer envelope volumes. More...

#include <ChamberAssembleTool.h>

Inheritance diagram for MuonGMR4::ChamberAssembleTool:
Collaboration diagram for MuonGMR4::ChamberAssembleTool:

Public Types

using VolBounds_t = Acts::VolumeBounds
 Abrivation of the volume bounds.
using VolBoundPtr_t = std::shared_ptr<VolBounds_t>
 Abrivation of the Volume bound ptr.
using SurfBoundPtr_t = std::shared_ptr<const Acts::PlanarBounds>
 Abrivation of the surface bounds.
using TrfWithBounds = std::tuple<Acts::Transform3, VolBoundPtr_t, SurfBoundPtr_t>
 Abrivation of the volume transform together with a set of volume & surface bounds.

Public Member Functions

virtual StatusCode buildReadOutElements (MuonDetectorManager &mgr) override final

Private Types

using ChamberPtr = SpectrometerSector::ChamberPtr

Private Member Functions

template<typename ReObjType>
requires (Acts::PointerConcept<ReObjType>)
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 the volume bounds & the transformation to center the volume

Static Private Member Functions

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 bounds.

Private Attributes

ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc {this, "IdHelperSvc", "Muon::MuonIdHelperSvc/MuonIdHelperSvc"}
Gaudi::Property< bool > m_isRun4 {this, "run4Layout", false}
 Toggling whether the layout is a R3 or R4 layout.

Detailed Description

Assembly tool to produce the Acts envolpe volumes around the muon stations & also to construct the spectrometer envelope volumes.

Definition at line 27 of file ChamberAssembleTool.h.

Member Typedef Documentation

◆ ChamberPtr

◆ SurfBoundPtr_t

using MuonGMR4::ChamberAssembleTool::SurfBoundPtr_t = std::shared_ptr<const Acts::PlanarBounds>

Abrivation of the surface bounds.

Definition at line 39 of file ChamberAssembleTool.h.

◆ TrfWithBounds

Abrivation of the volume transform together with a set of volume & surface bounds.

Definition at line 41 of file ChamberAssembleTool.h.

◆ VolBoundPtr_t

Abrivation of the Volume bound ptr.

Definition at line 37 of file ChamberAssembleTool.h.

◆ VolBounds_t

using MuonGMR4::ChamberAssembleTool::VolBounds_t = Acts::VolumeBounds

Abrivation of the volume bounds.

Definition at line 35 of file ChamberAssembleTool.h.

Member Function Documentation

◆ boundingBox()

template<typename ReObjType>
requires (Acts::PointerConcept<ReObjType>)
ChamberAssembleTool::TrfWithBounds MuonGMR4::ChamberAssembleTool::boundingBox ( const ActsTrk::GeometryContext & gctx,
const std::vector< ReObjType > & constituents,
const Acts::Transform3 & globToLoc,
Acts::VolumeBoundFactory & volBoundSet,
Acts::SurfaceBoundFactory & surfBoundSet,
const double margin ) const
private

builds the bounding box trapezoidal volume bounds from the set of readout elements Returns a pair of the volume bounds & the transformation to center the volume

Parameters
gctxGeometry context holding the alignment & global transformations
constituentsList of readout elements around which the bounding box shall be built
globToLocTransformation to go from the global -> local chamber's frame
volBoundSetFactory to create the volume bounds & share them across equivalent volumes
surfBoundSetFactory to create the surface bounds representing the material surfaces & share them across mutliple surfaces
marginExtra margin by which the returned volume bounds are enlarged

Definition at line 56 of file ChamberAssembleTool.cxx.

62 {
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}
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_VERBOSE(x,...)
Acts::GeometryContext context() const
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...
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
std::string toString(const MuonGMR4::MuonReadoutElement *re)

◆ buildReadOutElements()

StatusCode MuonGMR4::ChamberAssembleTool::buildReadOutElements ( MuonDetectorManager & mgr)
finaloverridevirtual

TGC T4E chambers & Mdt EIL chambers are glued together

Group chambers by sectors && station layer.

Check that the two readout elements are on the same side. Exception BOG eta 0 -> attributes to positive sectors

The two readout elements shall be located in the same sector

into a single chamber

If no chamber has been found, then create a new one

Find the chamber middle and create the geometry from that

Define the spectrometer sector

Define the chamber envelopes

Sort the readout elements by common parent volume

The BIS 7/8 chamber needs to be comparted into 4 subvolumes, each containing a single readout element to minimize the impact from the overlap between BIS78 & EIL-4 (TGC)

We need to ensure that the EIL 4/5 are split into a separate volume w.r.t. the New Small Wheel

Temporarily use the CSC to avoid reporting issues with the alignment algorithms

now, build simplified 2D representations of the sorted chambers we collected.

Now construct the sector volume from the chamber envelopes

Definition at line 84 of file ChamberAssembleTool.cxx.

84 {
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 ");
175 SpectrometerSector::defineArgs sectorArgs{};
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}
const std::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
static Double_t a
@ BIS
Definition RegSelEnums.h:11
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.
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 ...
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
GeoModel::TransientConstSharedPtr< Chamber > ChamberPtr
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW).
@ Csc
Thin gap champers.
Eigen::Matrix< double, 3, 1 > Vector3D
Chamber::defineArgs chamberArgs
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
const std::string & stName(StIndex index)
convert StIndex into a string
const std::string & chName(ChIndex index)
convert ChIndex into a string
Chamber
Define chamber types and locations.
ReadoutSet detEles
List of associated readout elements.
Definition Chamber.h:37

◆ surfaceBounds()

ChamberAssembleTool::SurfBoundPtr_t MuonGMR4::ChamberAssembleTool::surfaceBounds ( const VolBounds_t & volBounds,
Acts::SurfaceBoundFactory & surfBoundSet )
staticprivate

Construct surface bounds which measure equal sizes in halfXlow/halfXhigh & halfY as the parsed volume bounds.

Parameters
volBoundsBounds which are mapped to surface bounds
surfBoundSetBound factory to assign equivalent bounds to multiple surfaces

Definition at line 45 of file ChamberAssembleTool.cxx.

46 {
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}
double halfY(const Acts::VolumeBounds &bounds)
Returns the half-Y length for the parsed volume bounds (Trapezoid/ Cuboid).
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).

Member Data Documentation

◆ m_idHelperSvc

ServiceHandle<Muon::IMuonIdHelperSvc> MuonGMR4::ChamberAssembleTool::m_idHelperSvc {this, "IdHelperSvc", "Muon::MuonIdHelperSvc/MuonIdHelperSvc"}
private

Definition at line 69 of file ChamberAssembleTool.h.

69{this, "IdHelperSvc", "Muon::MuonIdHelperSvc/MuonIdHelperSvc"};

◆ m_isRun4

Gaudi::Property<bool> MuonGMR4::ChamberAssembleTool::m_isRun4 {this, "run4Layout", false}
private

Toggling whether the layout is a R3 or R4 layout.

If true, the BIS eta: -7 chambers are split into the individual readout elements.

Definition at line 72 of file ChamberAssembleTool.h.

72{this, "run4Layout", false};

The documentation for this class was generated from the following files: