ATLAS Offline Software
Loading...
Searching...
No Matches
TgcReadoutGeomTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <GaudiKernel/SystemOfUnits.h>
10
11#include <GeoModelKernel/GeoFullPhysVol.h>
12#include <GeoModelKernel/GeoPhysVol.h>
13#include <GeoModelKernel/GeoTrd.h>
14#include <GeoModelKernel/GeoBox.h>
15
16#include <GeoModelRead/ReadGeoModel.h>
20
21#include <format>
23
25
26#ifndef SIMULATIONBASE
27# include "Acts/Utilities/BoundFactory.hpp"
28#endif
29
30using namespace CxxUtils;
31using namespace ActsTrk;
32
33namespace MuonGMR4 {
34
37
38
39
40std::unique_ptr<WireGroupDesign>
42 const GeoTrd* gapTrd) const {
43 if (table.wireGangs.empty()) {
44 return nullptr;
45 }
46 const double halfMinX = std::min(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
47 const double halfMaxX = std::max(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
48 const double halfY = gapTrd->getZHalfLength();
49 auto design = std::make_unique<WireGroupDesign>();
50 design->defineTrapezoid(halfMinX, halfMaxX, halfY);
51 for (unsigned gang : table.wireGangs) {
52 design->declareGroup(gang);
53 }
54 const double wireOffSet = -0.5*table.wirePitch * design->nAllWires();
55 design->defineStripLayout(Amg::Vector2D{wireOffSet, 0.},
56 table.wirePitch, 0., table.wireGangs.size());
57 return design;
58}
59std::unique_ptr<RadialStripDesign>
61 const GeoTrd* gapTrd) const {
62 if (table.bottomStripPos.empty()) {
63 return nullptr;
64 }
65 const double halfMinX = std::min(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
66 const double halfMaxX = std::max(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
67 const double halfY = gapTrd->getZHalfLength();
68
69 auto design = std::make_unique<RadialStripDesign>();
70
71 design->defineTrapezoid(halfMinX, halfMaxX, halfY);
72 design->defineStripLayout(Amg::Vector2D{-halfY,0.},
73 0.,0.,table.bottomStripPos.size());
74 design->flipTrapezoid();
75 for (size_t s = 0; s < table.bottomStripPos.size(); ++s) {
76 design->addStrip(table.bottomStripPos.at(s),
77 table.topStripPos.at(s));
78 }
79 return design;
80}
81
83 FactoryCache& factoryCache) {
84 ATH_MSG_VERBOSE("Load dimensions of "<<m_idHelperSvc->toString(define.detElId)
85 <<std::endl<<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
86 const GeoShape* shape = m_geoUtilTool->extractShape(define.physVol);
87 if (!shape) {
88 ATH_MSG_FATAL("Failed to deduce a valid shape for "<<m_idHelperSvc->toString(define.detElId));
89 return StatusCode::FAILURE;
90 }
91
92 if (shape->typeID() != GeoTrd::getClassTypeID()) {
93 ATH_MSG_FATAL("The shape of "<<m_idHelperSvc->toStringDetEl(define.detElId)
94 <<" is expected to be a trapezoid "<<m_geoUtilTool->dumpShape(shape));
95 return StatusCode::FAILURE;
96 }
97 const GeoTrd* chambTrd = static_cast<const GeoTrd*>(shape);
98 define.halfWidthShort = std::min(chambTrd->getYHalfLength1(), chambTrd->getYHalfLength2());
99 define.halfWidthLong = std::max(chambTrd->getYHalfLength1(), chambTrd->getYHalfLength2());
100 define.halfHeight = chambTrd->getZHalfLength();
101 define.halfThickness = chambTrd->getXHalfLength1();
103 std::vector<physVolWithTrans> allGasGaps = m_geoUtilTool->findAllLeafNodesByName(define.physVol, "TgcGas");
104 if (allGasGaps.empty()) {
105 ATH_MSG_FATAL("The volume "<<m_idHelperSvc->toStringDetEl(define.detElId)<<" does not have any childern TgcGas"
106 <<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
107 return StatusCode::FAILURE;
108 }
109 unsigned gasGap{0};
111 auto assignReadoutLayer = [&define, & gasGap, this] (const StripLayerPtr& layerReadout) {
112 if (!layerReadout) {
113 return StatusCode::SUCCESS;
114 }
115 unsigned layerIdx = static_cast<unsigned>(layerReadout->hash());
116 if (layerIdx >= define.sensorLayouts.size()) {
117 ATH_MSG_FATAL("The strip index "<<layerIdx<<" is out of range for gasGap "<<gasGap);
118 return StatusCode::FAILURE;
119 }
120 define.sensorLayouts[layerIdx] = layerReadout;
121 return StatusCode::SUCCESS;
122 };
123 for (const physVolWithTrans& pVolTrans : allGasGaps) {
124 const std::string key = std::format("{:}_{:}{:}",define.chambDesign, gasGap+1,
125 (m_idHelperSvc->stationEta(define.detElId) > 0 ? "A" : "C"));
126 StripLayerPtr& wireReadout{factoryCache.readoutLayers[key]};
127 if (!wireReadout) {
128 const wTgcTable& table{factoryCache.parameterBook[key]};
129 if (!table.gasGap) {
130 ATH_MSG_FATAL("No wTGC table could be found for "<<m_idHelperSvc->toStringDetEl(define.detElId)
131 <<" "<<define.chambDesign<<", gasGap "<<(gasGap+1));
132 return StatusCode::FAILURE;
133 }
134 const GeoShape* gapShape = m_geoUtilTool->extractShape(pVolTrans.volume);
135 if (gapShape->typeID() != GeoTrd::getClassTypeID()) {
136 ATH_MSG_FATAL("Expected shape "<<m_geoUtilTool->dumpShape(gapShape)<<" to be a trapezoid");
137 return StatusCode::FAILURE;
138 }
139 const GeoTrd* gapTrd = static_cast<const GeoTrd*>(gapShape);
140 WireDesignPtr wireDesign = constructWireDesign(table, gapTrd);
141 RadialStripDesignPtr radDesign = constructRadialDesign(table, gapTrd);
142 if (wireDesign) {
143 wireDesign = (*factoryCache.wireLayouts.insert(std::move(wireDesign)).first);
144 }
145 if (radDesign) {
146 radDesign = (*factoryCache.stripReadouts.insert(std::move(radDesign)).first);
147 }
149 if (!wireReadout && wireDesign) {
150 const IdentifierHash layHash = TgcReadoutElement::constructHash(0, gasGap+1, false);
151 ATH_MSG_VERBOSE("Wire hash "<<layHash);
152 const Amg::Transform3D trans{pVolTrans.transform
153 * Amg::getRotateY3D(-90.*Gaudi::Units::deg)
154 * Amg::getRotateX3D(180.* Gaudi::Units::deg)};
155 if (radDesign) {
156 wireReadout = std::make_unique<StripLayer>(factoryCache.trfNodeMaker.makeTransform(trans),
157 wireDesign, radDesign, layHash);
158 wireReadout->flipPhiRotation();
159 } else {
160 wireReadout = std::make_unique<StripLayer>(factoryCache.trfNodeMaker.makeTransform(trans),
161 wireDesign, layHash);
162 }
163 }
164 }
165 ATH_CHECK(assignReadoutLayer(wireReadout));
166 ++gasGap;
167 }
168 define.nGasGaps = gasGap;
169 return StatusCode::SUCCESS;
170}
172 ATH_CHECK(m_geoDbTagSvc.retrieve());
173 ATH_CHECK(m_idHelperSvc.retrieve());
174 ATH_CHECK(m_geoUtilTool.retrieve());
175 GeoModelIO::ReadGeoModel* sqliteReader = m_geoDbTagSvc->getSqliteReader();
176 if (!sqliteReader) {
177 ATH_MSG_FATAL("Error, the tool works exclusively from sqlite geometry inputs");
178 return StatusCode::FAILURE;
179 }
180
181 FactoryCache facCache{};
182 ATH_CHECK(readParameterBook(facCache));
183
184#ifndef SIMULATIONBASE
185 auto layerBounds = std::make_shared<Acts::SurfaceBoundFactory>();
186#endif
187 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
188 // Get the list of full phys volumes from SQLite, and create detector elements
190 physNodeMap mapFPV = sqliteReader->getPublishedNodes<std::string, GeoFullPhysVol*>("Muon");
191 for (auto& [key, pv] : mapFPV) {
195 std::vector<std::string> key_tokens = tokenize(key, "_");
196 if (key_tokens.size() < 4 ||
197 !key_tokens[0].starts_with( "TGC"))
198 continue;
199
200 bool isValid{false};
201 const Identifier elementID = idHelper.elementID(key_tokens[1].substr(0,3), atoi(key_tokens[2]), atoi(key_tokens[3]), isValid);
203 if (!isValid){
204 ATH_MSG_FATAL("Failed to construct the station Identifier from "<<key);
205 return StatusCode::FAILURE;
206 }
207 defineArgs define{};
208 define.physVol = pv;
209 define.detElId = elementID;
210 define.chambDesign = key_tokens[0];
211 define.alignTransform = m_geoUtilTool->findAlignableTransform(define.physVol);
212#ifndef SIMULATIONBASE
213 define.layerBounds = layerBounds;
214#endif
215 ATH_MSG_DEBUG("Key "<<key<<" lead to Identifier "<<m_idHelperSvc->toStringDetEl(define.detElId));
216 ATH_CHECK(loadDimensions(define, facCache));
217 std::unique_ptr<TgcReadoutElement> readoutEle = std::make_unique<TgcReadoutElement>(std::move(define));
218 ATH_CHECK(mgr.addTgcReadoutElement(std::move(readoutEle)));
219 }
221 return StatusCode::SUCCESS;
222}
225 std::vector<const TgcReadoutElement*> tgcReadOutEles = mgr.getAllTgcReadoutElements();
226 std::unique_ptr<std::vector<int>> tgcSectorMapping = std::make_unique<std::vector<int>>();
227 tgcSectorMapping->resize(m_idHelperSvc->tgcIdHelper().module_hash_max());
228 Muon::MuonSectorMapping sectorMapping{};
229 const ActsTrk::GeometryContext gctx{};
230 for (const TgcReadoutElement* readoutEle : tgcReadOutEles) {
231 int& sectNumb = (*tgcSectorMapping)[m_idHelperSvc->moduleHash(readoutEle->identify())];
232 sectNumb = sectorMapping.getSector(readoutEle->center(gctx).phi());
233 }
234 ATH_CHECK(detStore()->record(std::move(tgcSectorMapping), "TGC_SectorMapping"));
235 return StatusCode::SUCCESS;
236}
238 ServiceHandle<IRDBAccessSvc> accessSvc(m_geoDbTagSvc->getParamSvcName(), name());
239 ATH_CHECK(accessSvc.retrieve());
240 IRDBRecordset_ptr paramTable = accessSvc->getRecordsetPtr("TgcSensorLayout", "");
241 if (paramTable->size() == 0) {
242 ATH_MSG_FATAL("Empty parameter book table found");
243 return StatusCode::FAILURE;
244 }
245 for (const IRDBRecord_ptr& record : *paramTable) {
246 const std::string chambType = record->getString("technology");
247 const int gasGap = record->getInt("gasGap");
248 const std::vector<int> wireGangs{tokenizeInt(record->getString("wireGangs"),",")};
249 const std::vector<double> botStrips = tokenizeDouble(record->getString("bottomStrips"), ",");
250 const std::vector<double> topStrips = tokenizeDouble(record->getString("topStrips"), ",");
251 const std::vector<std::string> sides = tokenize(record->getString("side"), ";");
252 const double wirePitch = record->getDouble("wirePitch");
253 for (const std::string& side : sides) {
254 const std::string key = std::format("{:}_{:}{:}", chambType, gasGap, side);
255 wTgcTable& parBook{cache.parameterBook[key]};
256 parBook.wireGangs.insert(parBook.wireGangs.end(), wireGangs.begin(), wireGangs.end());
257 parBook.bottomStripPos = botStrips;
258 parBook.topStripPos = topStrips;
259 parBook.wirePitch = wirePitch;
260 parBook.gasGap = gasGap;
261 }
262
263 }
264 ATH_MSG_DEBUG("Read in total "<<cache.parameterBook.size()<<" chamber layouts");
265 return StatusCode::SUCCESS;
266}
267} // namespace MuonGMR4
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(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
Definition of the abstract IRDBAccessSvc interface.
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
std::unique_ptr< IRDBRecord > IRDBRecord_ptr
virtual unsigned int size() const =0
This is a "hash" representation of an Identifier.
GeoChildNodeWithTrf physVolWithTrans
Helper struct to cache a PhysVolume pointer together with the transformation to go from the volume to...
static IdentifierHash constructHash(unsigned measCh, unsigned gasGap, const bool isStrip)
Constructs the Hash out of the Identifier fields (channel, gasGap, isStrip)
StatusCode writeSectorMapping(const MuonDetectorManager &mgr) const
Map the Tgc sectors to the classical Muon System sectors.
StatusCode buildReadOutElements(MuonDetectorManager &mgr) override final
std::unique_ptr< WireGroupDesign > constructWireDesign(const wTgcTable &table, const GeoTrd *gapTrd) const
Constructs a new wire group design, if the table has wires defined.
StatusCode loadDimensions(TgcReadoutElement::defineArgs &args, FactoryCache &factory)
Loads the chamber dimensions from GeoModel.
PublicToolHandle< IMuonGeoUtilityTool > m_geoUtilTool
std::unique_ptr< RadialStripDesign > constructRadialDesign(const wTgcTable &table, const GeoTrd *gapTrd) const
Constructs a new radial strip design, if the table contains radial strips.
ServiceHandle< IGeoDbTagSvc > m_geoDbTagSvc
StatusCode readParameterBook(FactoryCache &cache)
Retrieves the auxillary tables from the database.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
int getSector(double phi) const
returns the sector corresponding to the phi position
Identifier elementID(int stationName, int stationEta, int stationPhi) const
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Amg::Transform3D getRotateX3D(double angle)
get a rotation transformation around X-axis
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Amg::Transform3D getRotateY3D(double angle)
get a rotation transformation around Y-axis
std::vector< int > tokenizeInt(const std::string &the_str, std::string_view delimiter)
std::vector< std::string > tokenize(const std::string &the_str, std::string_view delimiters)
Splits the string into smaller substrings.
std::vector< double > tokenizeDouble(const std::string &the_str, std::string_view delimiter)
int atoi(std::string_view str)
Helper functions to unpack numbers decoded in string into integers and doubles The strings are requir...
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)
GeoModel::TransientConstSharedPtr< WireGroupDesign > WireDesignPtr
RpcReadoutElement::defineArgs defineArgs
IMuonGeoUtilityTool::physVolWithTrans physVolWithTrans
GeoModel::TransientConstSharedPtr< StripLayer > StripLayerPtr
Definition StripLayer.h:100
GeoModel::TransientConstSharedPtr< RadialStripDesign > RadialStripDesignPtr
GeoIntrusivePtr< GeoVFullPhysVol > physVol
Pointer to the underlying physical volume in GeoModel.
std::string chambDesign
chamber design name as it's occuring in the parameter book tables E.g. BMS5, RPC10,...
std::array< StripLayerPtr, 6 > sensorLayouts
We have maximum 3 gasgaps times eta / phi measurement.
WireGroupDesignSet wireLayouts
Set to share equivalent WireGroupDesigns across multiple gas gaps.
RadialStripDesignSet stripReadouts
Set to share equivalent RadialStripDesigns across multiple gas gaps.
GeoDeDuplicator trfNodeMaker
Helper object to turn Amg::Transforms into GeoModel tree transform nodes.
Helper struct to cache the essential readout parameters from the WTGC tables.