ATLAS Offline Software
Loading...
Searching...
No Matches
SpectrometerSector.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef SIMULATIONBASE
6
8
9#include "Identifier/Identifier.h"
10#include "GeoModelKernel/throwExcept.h"
11#include "Acts/Surfaces/PlaneSurface.hpp"
12#include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
13#include "Acts/Geometry/Volume.hpp"
14
21
22#include <cstddef>
23#include <format>
24
25namespace {
26 std::vector<unsigned int> range (unsigned min, unsigned max) {
27 assert(max > min);
28 std::vector<unsigned int> v(max - min);
29 std::iota(v.begin(), v.end(), min);
30 return v;
31 };
32}
33
34namespace MuonGMR4 {
35
37using BoundEnums = Acts::TrapezoidVolumeBounds::BoundValues;
38
40 AthMessaging("MuonSpectrometerSector"),
41 m_args{std::move(args)} {
42 for (auto & chamber : m_args.chambers) {
43 chamber->setParent(this);
44 }
45 }
46
48 return m_args.id < other.m_args.id;
49}
51 return Acts::copySign(1, chambers().front()->stationEta());
52}
54const Muon::IMuonIdHelperSvc* SpectrometerSector::idHelperSvc() const { return m_args.chambers.front()->idHelperSvc();}
55Muon::MuonStationIndex::ChIndex SpectrometerSector::chamberIndex() const { return m_args.chambers.front()->chamberIndex(); }
56int SpectrometerSector::stationPhi() const { return m_args.chambers.front()->stationPhi(); }
57int SpectrometerSector::sector() const {return m_args.chambers.front()->sector(); }
58bool SpectrometerSector::barrel() const { return m_args.chambers.front()->barrel(); }
60 return std::format("id: {:3d}, {:} {:}-side sector: {:2},", m_args.id,
62 side() == 1 ? 'A' : 'C' , sector());
63}
64const ChamberSet& SpectrometerSector::chambers() const{ return m_args.chambers; }
65const Acts::PlaneSurface& SpectrometerSector::surface() const {
66 return *m_args.surface;
67}
68
69const Acts::Transform3& SpectrometerSector::localToGlobalTransform(const Acts::GeometryContext& tgContext) const{
70 return surface().localToGlobalTransform(tgContext);
71}
72const Acts::Transform3& SpectrometerSector::globalToLocalTransform(const Acts::GeometryContext& tgContext) const{
73 return m_args.placement->globalToLocalTransform(tgContext);
74}
75const Acts::Transform3& SpectrometerSector::localToGlobalTransform(const ActsTrk::GeometryContext& gctx) const {
76 return surface().localToGlobalTransform(gctx.context());
77}
78const Acts::Transform3& SpectrometerSector::globalToLocalTransform(const ActsTrk::GeometryContext& gctx) const {
79 return globalToLocalTransform(gctx.context());
80}
83double SpectrometerSector::halfY() const { return MuonGMR4::halfY(* m_args.bounds); }
84double SpectrometerSector::halfZ() const { return MuonGMR4::halfZ(*m_args.bounds);}
85
86
87std::shared_ptr<Acts::Volume> SpectrometerSector::boundingVolume() const {
88 Acts::VolumePlacementBase* ATLAS_THREAD_SAFE placement = m_args.placement.get();
89 return std::make_shared<Acts::Volume>(*placement, bounds());
90}
91std::shared_ptr<Acts::VolumeBounds> SpectrometerSector::bounds() const { return m_args.bounds; }
93 Chamber::ReadoutSet toReturn{};
94 for (const ChamberPtr& ch : chambers()) {
95 toReturn.insert(toReturn.end(), ch->readoutEles().begin(), ch->readoutEles().end());
96 }
97 return toReturn;
98}
99const std::vector<SpectrometerSector::chamberLocation> & SpectrometerSector::chamberLocations() const{
100 return m_args.detectorLocs;
101
102}
103std::ostream& operator<<(std::ostream& ostr,
104 const SpectrometerSector::defineArgs& args) {
105 ostr<<std::endl;
106 ostr<<"halfX (S/L): "<<halfXlowY(*args.bounds)<<"/"<<halfXhighY(*args.bounds)<<" [mm], ";
107 ostr<<"halfY: "<<halfY(*args.bounds)<<" [mm], ";
108 ostr<<"halfZ: "<<halfZ(*args.bounds)<<" [mm], ";
109 ostr<<"************************************************************************"<<std::endl;
110 for (const SpectrometerSector::ChamberPtr& ch : args.chambers) {
111 ostr<<" --- "<<(*ch)<<std::endl;
112 }
113 return ostr;
114}
115std::ostream& operator<<(std::ostream& ostr, const SpectrometerSector& chamber) {
116 ostr<<"MS sector "<<chamber.identString()<<" "<<chamber.parameters();
117 return ostr;
118}
119
120const std::vector<unsigned int>& SpectrometerSector::logicalLayerIdx(const MuonReadoutElement* reEle) const{
121 return m_detLayIdCache.at(reEle);
122};
123
124std::unordered_map<const MuonReadoutElement*, std::vector<unsigned int>>
126
127 std::unordered_map<const MuonReadoutElement*, std::vector<unsigned int>> cache{};
128 const ActsTrk::GeometryContext gctx{};
129 const Acts::Transform3 sectorTrans = globalToLocalTransform(gctx);
130
131 // sort the Readout elements by z in the sector fram
132 Chamber::ReadoutSet reEleSorted {readoutEles()};
133 std::ranges::sort(reEleSorted, [&sectorTrans, &gctx](const MuonReadoutElement* reEle1, const MuonReadoutElement* reEle2)-> bool {
134 return (sectorTrans * reEle1->center(gctx, reEle1->identify())).z() < (sectorTrans * reEle2->center(gctx, reEle2->identify())).z();
135 });
136
137 // this is a function to find the next logical layer, returning the corresponding reEle and Id
138 auto nextLayer = [this, &cache, &reEleSorted](const Identifier& lastId) ->
139 std::pair<const MuonReadoutElement*, const Identifier> {
140
141 const MuonReadoutElement* nextReEle {nullptr};
142 Identifier nextId {};
143
144 for (const MuonReadoutElement* reEle : reEleSorted){
145
146 // Check if this reEle has already been filled up
147 if (cache.count(reEle)) continue;
148
149 // compute the logical layer Id of the first layer of the reEle (first layer/gasgap, first channel, projecting to
150 // stationEta=1, doubletZ=1, doubletPhi=1, according to the technology)
151 const Identifier logicalId {computeDetLayerId(reEle)};
152
153 //if we find another measurement layer with the same detLayerId as the last we added (e.g. the same gasgap of two RPC z doublets)
154 if (logicalId == lastId){
155 return std::make_pair(reEle, logicalId);
156 }
157
158 // Save the next (subsequent) logic layer in z
159 if (!nextReEle) {
160 nextReEle = reEle;
161 nextId = logicalId;
162 }
163
164 }
165 return std::make_pair(nextReEle, nextId);
166 };
167
168 unsigned int layCounter {0}, nIter {0};
169 Identifier lastId {};
170 unsigned int deltaN {0};
171 while(++nIter <= reEleSorted.size()){
172
173 auto [nextReEle, nextId] = nextLayer(lastId);
174 if (!nextReEle){
175 THROW_EXCEPTION("Failed to retrieve next reEle in fillDetLayIdCache()");
176 }
177
178 unsigned int nLayers = nLayerPerReadout(nextReEle);
179
180 if (nextId != lastId) {
181 layCounter += deltaN;
182 deltaN = nLayers;
183 lastId = nextId;
184 }
185 else{
186 deltaN = std::max(deltaN, nLayers);
187 }
188
189 cache[nextReEle] = range(layCounter, layCounter + nLayers);
190
191 ATH_MSG_DEBUG( identString() << " ReEle: " << idHelperSvc()->toStringDetEl(nextReEle->identify()) <<
192 " Add logicLay: " << idHelperSvc()->toStringGasGap(nextId) << " nInserted, layCounter " << cache.at(nextReEle).size() << " ," << layCounter);
193 }
194 return cache;
195};
196
198
199 switch (rele->detectorType()) {
201 auto mdtRele = dynamic_cast<const MdtReadoutElement*>(rele);
202 return idHelperSvc()->mdtIdHelper().channelID(mdtRele->stationName(), 1,
203 mdtRele->stationPhi(),
204 mdtRele->multilayer(),
205 1,1);
206 }
208 auto rpcRele = dynamic_cast<const RpcReadoutElement*>(rele);
209 return idHelperSvc()->rpcIdHelper().channelID(rpcRele->stationName(), 1,
210 rpcRele->stationPhi(),
211 rpcRele->doubletR(), 1, 1,
212 1, 0, 1);
213 }
215 auto tgcRele = dynamic_cast<const TgcReadoutElement*>(rele);
216 return idHelperSvc()->tgcIdHelper().channelID(tgcRele->stationName(), 1,
217 tgcRele->stationPhi(),
218 1, 0, 1);
219 }
221 auto stgcRele = dynamic_cast<const sTgcReadoutElement*>(rele);
222 return idHelperSvc()->stgcIdHelper().channelID(stgcRele->stationName(), 1,
223 stgcRele->stationPhi(),
224 stgcRele->multilayer(),
225 1, 0, 1);
226 }
228 auto mmRele = dynamic_cast<const MmReadoutElement*>(rele);
229 return idHelperSvc()->mmIdHelper().channelID(mmRele->stationName(), 1,
230 mmRele->stationPhi(),
231 mmRele->multilayer(),
232 1, 1);
233 }
234 default:
235 THROW_EXCEPTION("Unexpected Readout Element Type in computeDetLayerId()");
236 }
237}
238
240
241 switch (rele->detectorType()) {
243 auto mdtRele = dynamic_cast<const MdtReadoutElement*>(rele);
244 return mdtRele->numLayers();
245 }
247 auto rpcRele = dynamic_cast<const RpcReadoutElement*>(rele);
248 return rpcRele->nGasGaps();
249 }
251 auto tgcRele = dynamic_cast<const TgcReadoutElement*>(rele);
252 return tgcRele->nGasGaps();
253 }
255 auto stgcRele = dynamic_cast<const sTgcReadoutElement*>(rele);
256 return stgcRele->numLayers();
257 }
259 auto mmRele = dynamic_cast<const MmReadoutElement*>(rele);
260 return mmRele->nGasGaps();
261 }
262 default:
263 THROW_EXCEPTION("Unexpected Readout Element Type in nLayerPerReadout()");
264 }
265}
266void SpectrometerSector::addPlacement(std::unique_ptr<ActsTrk::VolumePlacement>&& placement) const {
267 m_args.chambers.front()->addPlacement(std::move(placement));
268}
269
270}
271
272#endif
#define ATH_MSG_DEBUG(x,...)
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
Acts::GeometryContext context() const
virtual DetectorType detectorType() const =0
Returns the detector element type.
std::atomic_flag m_initialized ATLAS_THREAD_SAFE
Messaging initialized (initMessaging).
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
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
std::vector< const MuonReadoutElement * > ReadoutSet
Define the list of read out elements of the chamber.
Definition Chamber.h:32
Readout element to describe the Monitored Drift Tube (Mdt) chambers Mdt chambers usually comrpise out...
unsigned numLayers() const
Returns how many tube layers are inside the multi layer [1;4].
unsigned int nGasGaps() const
Returns the number of gas gaps.
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
Amg::Vector3D center(const ActsTrk::GeometryContext &ctx) const
Returns the geometrical center point of the readout element.
Identifier identify() const override final
Return the ATLAS identifier.
unsigned nGasGaps() const
Returns the number of gasgaps described by this ReadOutElement (usally 2 or 3).
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
bool operator<(const SpectrometerSector &other) const
int8_t side() const
Returns the side of the MS-sector 1 -> A side ; -1 -> C side.
const Acts::Transform3 & globalToLocalTransform(const ActsTrk::GeometryContext &gctx) const
Returns the global -> local transformation from the ATLAS global.
const std::vector< unsigned int > & logicalLayerIdx(const MuonReadoutElement *reEle) const
Returns the logic layer numbering of a given Readout Element.
double halfZ() const
Thickness of the chamber in the z-direction.
unsigned int nLayerPerReadout(const MuonReadoutElement *rele) const
Helper function giving the number of measurement layers in a given readout ele.
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns the IdHelpeSvc.
std::shared_ptr< Acts::Volume > boundingVolume() const
Returns the Acts::Volume representation of the sector.
bool barrel() const
Returns whether the sector is placed in the barrel.
const Acts::Transform3 & localToGlobalTransform(const ActsTrk::GeometryContext &gctx) const
Returns the local -> global tarnsformation from the sector.
Chamber::ReadoutSet readoutEles() const
Returns the list of all associated readout elements.
std::unordered_map< const MuonReadoutElement *, std::vector< unsigned int > > fillDetLayIdCache() const
Function filling the map mapping the readout elements to layer numbers.
SpectrometerSector(defineArgs &&args)
Standard constructor taking the defining parameters.
Identifier computeDetLayerId(const MuonReadoutElement *rele) const
Helper function calculating the logic layer Id and the physical layer id.
std::string identString() const
Returns a string encoding the chamber index & the sector of the MS sector.
double halfY() const
Extend of the chamber in the y-direction.
const Acts::PlaneSurface & surface() const
Returns the associated surface.
const ChamberSet & chambers() const
Returns the associated chambers with this sector.
GeoModel::TransientConstSharedPtr< Chamber > ChamberPtr
void addPlacement(std::unique_ptr< ActsTrk::VolumePlacement > &&placement) const
Adds a volume placement to the Chamber's memory management.
double halfXLong() const
Long-extend of the chamber in the x-direction at positive Y.
int sector() const
Returns the sector of the MS-sector.
std::shared_ptr< Acts::VolumeBounds > bounds() const
Returns the volume bounds.
const std::unordered_map< const MuonReadoutElement *, std::vector< unsigned int > > m_detLayIdCache
Map mapping each Readout Element to the layer numbering in the sector frame.
const std::vector< chamberLocation > & chamberLocations() const
returns the list of all MDT chambers in the sector for fast navigation
double halfXShort() const
Short extend of the chamber in the x-direction at negative Y.
int stationPhi() const
: Returns the station phi of the sector
const defineArgs & parameters() const
Returns the reference to the defining parameters of the sector.
Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index scheme.
std::vector< ChamberPtr > ChamberSet
unsigned nGasGaps() const
Returns the number of gasgaps described by this ReadOutElement (usally 2 or 3).
unsigned numLayers() const
Returns the number of gas gap layers.
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
virtual const MmIdHelper & mmIdHelper() const =0
access to CscIdHelper
virtual const RpcIdHelper & rpcIdHelper() const =0
access to RpcIdHelper
virtual const sTgcIdHelper & stgcIdHelper() const =0
access to TgcIdHelper
virtual const TgcIdHelper & tgcIdHelper() const =0
access to TgcIdHelper
virtual const MdtIdHelper & mdtIdHelper() const =0
access to MdtIdHelper
Identifier channelID(int stationName, int stationEta, int stationPhi, int doubletR, int doubletZ, int doubletPhi, int gasGap, int measuresPhi, int strip) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int gasGap, int isStrip, int channel) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channelType, int channel) const
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW).
@ Rpc
Monitored Drift Tubes.
@ Mdt
MuonSpectrometer.
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
Acts::TrapezoidVolumeBounds::BoundValues BoundEnums
double halfY(const Acts::VolumeBounds &bounds)
Returns the half-Y length for the parsed volume bounds (Trapezoid/ Cuboid).
std::ostream & operator<<(std::ostream &ostr, const Chamber::defineArgs &args)
Definition Chamber.cxx:18
SpectrometerSector::ChamberSet ChamberSet
double halfZ(const Acts::VolumeBounds &bounds)
Returns the half-Z 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).
const std::string & chName(ChIndex index)
convert ChIndex into a string
ChIndex
enum to classify the different chamber layers in the muon spectrometer
STL namespace.
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10