ATLAS Offline Software
Loading...
Searching...
No Matches
sTgcReadoutGeomTool.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
12#include <GeoModelKernel/GeoFullPhysVol.h>
13#include <GeoModelKernel/GeoPhysVol.h>
14#include <GeoModelKernel/GeoTrd.h>
15#include <GeoModelKernel/GeoSimplePolygonBrep.h>
16
17#include <GeoModelRead/ReadGeoModel.h>
20
22
23#ifndef SIMULATIONBASE
24# include "Acts/Utilities/BoundFactory.hpp"
25#endif
26
27using namespace CxxUtils;
28using namespace ActsTrk;
29
30namespace MuonGMR4 {
31
34
35
38 if (shape->typeID() == GeoTrd::getClassTypeID()) {
39 const GeoTrd* trd = static_cast<const GeoTrd*>(shape);
40 result.longWidth = trd->getXHalfLength1();
41 result.shortWidth = trd->getXHalfLength2();
42 result.halfHeight = trd->getYHalfLength1();
43 result.thickness = trd->getZHalfLength();
44 } else if (shape->typeID() == GeoSimplePolygonBrep::getClassTypeID()) {
45 const GeoSimplePolygonBrep* poly = static_cast<const GeoSimplePolygonBrep*>(shape);
46 std::vector<Amg::Vector2D> polyEdges = m_geoUtilTool->polygonEdges(*poly);
47 result.thickness = poly->getDZ() * Gaudi::Units::mm;
48 if (polyEdges.size() == 4) {
49 result.longWidth = 0.5 * (polyEdges[0].x() - polyEdges[1].x()) * Gaudi::Units::mm;
50 result.shortWidth = 0.5 * (polyEdges[3].x() - polyEdges[2].x()) * Gaudi::Units::mm;
51 result.halfHeight = 0.5 * (polyEdges[0].y() - polyEdges[3].y()) * Gaudi::Units::mm;
52 } else if (polyEdges.size() == 6) {
53 result.longWidth = 0.5 * (polyEdges[0].x() - polyEdges[1].x()) * Gaudi::Units::mm;
54 result.shortWidth = 0.5 * (polyEdges[4].x() - polyEdges[3].x()) * Gaudi::Units::mm;
55 result.halfHeight = 0.5 * (polyEdges[0].y() - polyEdges[4].y()) * Gaudi::Units::mm;
56 result.yCutOut = (polyEdges[1].y() - polyEdges[2].y()) * Gaudi::Units::mm;
57 }
58 } else {
59 ATH_MSG_FATAL("Unknown shape type "<<shape->type());
60 throw std::runtime_error("Invalid shape to extract sTGC parameters");
61 }
62 return result;
63}
64
66 ATH_MSG_VERBOSE("Load dimensions of "<<m_idHelperSvc->toString(define.detElId)
67 <<std::endl<<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
68 const GeoShape* shape = m_geoUtilTool->extractShape(define.physVol);
69 if (!shape) {
70 ATH_MSG_FATAL("Failed to deduce a valid shape for "<<m_idHelperSvc->toString(define.detElId));
71 return StatusCode::FAILURE;
72 }
73 ATH_MSG_DEBUG("Extracted shape "<<m_geoUtilTool->dumpShape(shape));
75 sTgcShape modPars = extractParameters(shape);
76
77 define.sHalfChamberLength = modPars.shortWidth;
78 define.lHalfChamberLength = modPars.longWidth;
79 define.halfChamberHeight = modPars.halfHeight;
80 define.halfChamberTck = modPars.thickness;
81 define.yCutout = modPars.yCutOut;
82
83 ATH_MSG_DEBUG("chamber length (L/S) is: " << 2*define.lHalfChamberLength << "/"
84 << 2*define.sHalfChamberLength << " chamber height is: "
85 << 2*define.halfChamberHeight << " chamber thickness is: " << 2*define.halfChamberTck << " yCutout value is: " << define.yCutout);
86
88 std::vector<physVolWithTrans> allGasGaps = m_geoUtilTool->findAllLeafNodesByName(define.physVol, "sTgcGas");
89 if (allGasGaps.empty()) {
90 ATH_MSG_FATAL("The volume "<<m_idHelperSvc->toStringDetEl(define.detElId)<<" does not have any children 'sTgcGas'"
91 <<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
92 return StatusCode::FAILURE;
93 }
94
96 define.numLayers = allGasGaps.size();
97 ATH_MSG_VERBOSE("The number of gasGaps are: " << define.numLayers);
98 FactoryCache::ParamBookTable::const_iterator parBookItr = factoryCache.parameterBook.find(define.chambDesign);
99 if (parBookItr == factoryCache.parameterBook.end()) {
100 ATH_MSG_FATAL("The chamber "<<define.chambDesign<<" is not part of the WSTGC table");
101 return StatusCode::FAILURE;
102 }
103
104 const wSTGCTable& paramBook{parBookItr->second};
105
106 define.gasTck = paramBook.gasTck;
108 unsigned int gasGap{0};
109 for (physVolWithTrans& gapVol : allGasGaps) {
110 StripDesignPtr stripDesign = std::make_unique<StripDesign>();
111 WireDesignPtr wireGroupDesign = std::make_unique<WireGroupDesign>();
112 PadDesignPtr padDesign = std::make_unique<PadDesign>();
113
114 sTgcShape gapPars = extractParameters(m_geoUtilTool->extractShape(gapVol.volume));
115
117 double firstStripPos = -gapPars.halfHeight + paramBook.firstStripPitch[gasGap] - 0.5 * paramBook.stripPitch;
118 define.firstStripPitch = paramBook.firstStripPitch;
119 ATH_MSG_DEBUG("FirstStripPos for stripPitch: " << paramBook.firstStripPitch[gasGap] << " is: " << Amg::toString(firstStripPos, 2) << " and the half height is: " << gapPars.halfHeight);
120
122 unsigned int numWireGroups = paramBook.numWireGroups[gasGap];
124 double firstWirePos = paramBook.firstWirePos[gasGap];
125
126 if(gapPars.yCutOut) {
128 stripDesign->defineDiamond(gapPars.shortWidth, gapPars.longWidth, gapPars.halfHeight + 0.001, paramBook.yCutoutCathode);
129 ATH_MSG_VERBOSE("The yCutout of the active area is: " << gapPars.yCutOut);
130 stripDesign->defineStripLayout(Amg::Vector2D{firstStripPos, 0.},
131 paramBook.stripPitch, paramBook.stripWidth, paramBook.numStrips);
132 ATH_MSG_VERBOSE("Created new diamond strip design "<<(*stripDesign));
134 wireGroupDesign->defineDiamond(0.5*paramBook.sPadLength, 0.5*paramBook.lPadLength, gapPars.halfHeight, paramBook.yCutoutCathode);
135 wireGroupDesign->flipTrapezoid();
136 wireGroupDesign->defineStripLayout(Amg::Vector2D{firstWirePos, 0.},
137 paramBook.wirePitch,
138 paramBook.wireWidth,
139 numWireGroups);
140 ATH_MSG_VERBOSE("Created new diamond wireGroup design "<<(*wireGroupDesign));
141
143 padDesign->defineDiamond(0.5*paramBook.sPadLength, 0.5*paramBook.lPadLength, gapPars.halfHeight, paramBook.yCutoutCathode);
144 padDesign->flipTrapezoid();
145 ATH_MSG_VERBOSE("Created new diamond pad design "<<(*padDesign));
146 } else {
148 stripDesign->defineTrapezoid(gapPars.shortWidth, gapPars.longWidth, gapPars.halfHeight + 0.01);
149 stripDesign->defineStripLayout(Amg::Vector2D{firstStripPos, 0.},
150 paramBook.stripPitch, paramBook.stripWidth, paramBook.numStrips);
151 ATH_MSG_VERBOSE("Created new strip design "<<(*stripDesign));
152
154 wireGroupDesign->defineTrapezoid(0.5*paramBook.sPadLength, 0.5*paramBook.lPadLength, gapPars.halfHeight);
155 wireGroupDesign->flipTrapezoid();
156 wireGroupDesign->defineStripLayout(Amg::Vector2D{firstWirePos, 0.},
157 paramBook.wirePitch,
158 paramBook.wireWidth,
159 numWireGroups);
160 ATH_MSG_VERBOSE("Created new wireGroup design "<<(*wireGroupDesign));
161
163 padDesign->defineTrapezoid(0.5*paramBook.sPadLength, 0.5*paramBook.lPadLength, gapPars.halfHeight);
164 padDesign->flipTrapezoid();
165 ATH_MSG_VERBOSE("Created new pad design "<<(*padDesign));
166 }
167
169 wireGroupDesign->declareGroup(paramBook.firstWireGroupWidth[gasGap]);
170 for (uint wireGr=2; wireGr<numWireGroups; wireGr++){
171 wireGroupDesign->declareGroup(paramBook.wireGroupWidth);
172 }
173 unsigned int lastWireGroup = (paramBook.numWires[gasGap] - wireGroupDesign->nAllWires());
174 wireGroupDesign->declareGroup(lastWireGroup);
175 wireGroupDesign->defineWireCutout(paramBook.wireCutout[gasGap]);
176
178 double beamlineRadius = (define.physVol->getAbsoluteTransform() * gapVol.transform).translation().perp();
179 padDesign->defineBeamlineRadius(beamlineRadius);
180 ATH_MSG_DEBUG("The beamline radius is: " << beamlineRadius);
181 padDesign->definePadRow(paramBook.firstPadPhiDivision[gasGap],
182 paramBook.numPadPhi[gasGap],
183 paramBook.anglePadPhi,
184 paramBook.PadPhiShift[gasGap]);
185 padDesign->definePadColumn(paramBook.firstPadHeight[gasGap],
186 paramBook.numPadEta[gasGap],
187 paramBook.padHeight[gasGap]);
188
197 ++gasGap;
199 stripDesign = (*factoryCache.stripDesigns.emplace(stripDesign).first);
200 wireGroupDesign = (*factoryCache.wireGroupDesigns.emplace(wireGroupDesign).first);
201 StripLayer stripLayer{factoryCache.trfNodeMaker.makeTransform(gapVol.transform
202 * Amg::getRotateZ3D(-90. * Gaudi::Units::deg)
203 * Amg::getRotateY3D(180* Gaudi::Units::deg)),
204 stripDesign, wireGroupDesign,
206 stripLayer.flipPhiRotation();
207 ATH_MSG_VERBOSE("Added new diamond strip layer at "<< stripLayer);
208 define.stripLayers.push_back(std::move(stripLayer));
209
211 padDesign = (*factoryCache.padDesigns.emplace(padDesign).first);
212 StripLayer padLayer(factoryCache.trfNodeMaker.makeTransform(gapVol.transform
213 * Amg::getRotateZ3D(-90. * Gaudi::Units::deg)
214 * Amg::getRotateY3D(180* Gaudi::Units::deg)),
215 stripDesign, padDesign, sTgcReadoutElement::createHash(gasGap, sTgcIdHelper::Pad, 0));
216 padLayer.flipPhiRotation();
217 ATH_MSG_VERBOSE("Added new diamond pad layer at "<<padLayer);
218 define.padLayers.push_back(std::move(padLayer));
219 }
220 return StatusCode::SUCCESS;
221}
222
224 ATH_CHECK(m_geoDbTagSvc.retrieve());
225 ATH_CHECK(m_idHelperSvc.retrieve());
226 ATH_CHECK(m_geoUtilTool.retrieve());
227
228 GeoModelIO::ReadGeoModel* sqliteReader = m_geoDbTagSvc->getSqliteReader();
229 if (!sqliteReader) {
230 ATH_MSG_FATAL("Error, the tool works exclusively from sqlite geometry inputs");
231 return StatusCode::FAILURE;
232 }
233
234 FactoryCache facCache{};
235 ATH_CHECK(readParameterBook(facCache));
236
237 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
238 // Get the list of full phys volumes from SQLite, and create detector elements
239
240 physNodeMap mapFPV = sqliteReader->getPublishedNodes<std::string, GeoFullPhysVol*>("Muon");
241#ifndef SIMULATIONBASE
242 auto layerBounds = std::make_shared<Acts::SurfaceBoundFactory>();
243#endif
244
245 for (auto& [key, pv] : mapFPV) {
249 std::vector<std::string> key_tokens = tokenize(key, "_");
250 if (key_tokens.size() != 5 ||
251 key_tokens[0].find("sTGC") == std::string::npos)
252 continue;
253 ATH_MSG_DEBUG("Key is: "<<key);
254 bool isValid{false};
255 const std::string stName = key_tokens[1][1] == 'L' ? "STL" : "STS";
256 const int stEta = atoi(key_tokens[2]);
257 const int stPhi = atoi(key_tokens[3]);
258 const int ml = atoi(key_tokens[4]);
259
260 defineArgs define{};
261#ifndef SIMULATIONBASE
262 define.layerBounds = layerBounds;
263#endif
264 //Need identifier to get multilayer, the following constants don't matter.
265 define.detElId = idHelper.channelID(stName, stEta, stPhi, ml, 1, sTgcIdHelper::sTgcChannelTypes::Strip, 1, isValid);
266 if (!isValid) {
267 ATH_MSG_FATAL("Failed to build a good identifier out of " << key);
268 return StatusCode::FAILURE;
269 }
271 define.physVol = pv;
272 define.chambDesign = "sTGC_" + key_tokens[1];
273 define.alignTransform = m_geoUtilTool->findAlignableTransform(define.physVol);
274 ATH_MSG_VERBOSE("Key "<<key<<" lead to the identifier "<<m_idHelperSvc->toStringDetEl(define.detElId));
275 ATH_CHECK(loadDimensions(define, facCache));
276 std::unique_ptr<sTgcReadoutElement> readoutEle = std::make_unique<sTgcReadoutElement>(std::move(define));
277 ATH_CHECK(mgr.addsTgcReadoutElement(std::move(readoutEle)));
278 }
279 return StatusCode::SUCCESS;
280}
282 ServiceHandle<IRDBAccessSvc> accessSvc(m_geoDbTagSvc->getParamSvcName(), name());
283 ATH_CHECK(accessSvc.retrieve());
284 IRDBRecordset_ptr paramTable = accessSvc->getRecordsetPtr("WSTGC", "");
285 if (paramTable->size() == 0) {
286 ATH_MSG_FATAL("Empty parameter book table found");
287 return StatusCode::FAILURE;
288 }
289 ATH_MSG_VERBOSE("Found the " << paramTable->nodeName() << " ["
290 << paramTable->tagName() << "] table with "
291 << paramTable->size() << " records");
292 for (const IRDBRecord_ptr& record : *paramTable) {
293 // parameterBook pars{};
294 const std::string key = record-> getString("WSTGC_TYPE");
295 wSTGCTable& parBook = cache.parameterBook[key];
296 parBook.numStrips = record->getInt("nStrips");
297 parBook.stripPitch = record->getDouble("stripPitch");
298 parBook.stripWidth = record->getDouble("stripWidth");
299 parBook.firstStripPitch = tokenizeDouble(record->getString("firstStripWidth"), ";");
300
301 parBook.numWires = tokenizeInt(record->getString("nWires"), ";");
302 parBook.firstWireGroupWidth = tokenizeInt(record->getString("firstWireGroup"), ";");
303 parBook.numWireGroups = tokenizeInt(record->getString("nWireGroups"), ";");
304 parBook.wireCutout = tokenizeDouble(record->getString("wireCutout"), ";");
305 parBook.wirePitch = record->getDouble("wirePitch");
306 parBook.wireWidth = record->getDouble("wireWidth");
307 parBook.wireGroupWidth = record->getInt("wireGroupWidth");
308 parBook.firstWirePos = tokenizeDouble(record->getString("firstWire"), ";");
309
310 parBook.numPadEta = tokenizeInt(record->getString("nPadH"), ";");
311 parBook.numPadPhi = tokenizeInt(record->getString("nPadPhi"), ";");
312 parBook.firstPadHeight = tokenizeDouble(record->getString("firstPadH"), ";");
313 parBook.padHeight = tokenizeDouble(record->getString("padH"), ";");
314 parBook.PadPhiShift = tokenizeInt(record->getString("PadPhiShift"), ";");
315 parBook.anglePadPhi = record->getDouble("anglePadPhi");
316 parBook.firstPadPhiDivision = tokenizeDouble(record->getString("firstPadPhiDivision"), ";");
317 parBook.lPadLength = record->getDouble("lPadWidth");
318 parBook.sPadLength = record->getDouble("sPadWidth");
319
320 parBook.yCutout = record->getDouble("yCutout");
321 parBook.yCutoutCathode = record->getDouble("yCutoutCathode");
322 parBook.gasTck = record->getDouble("gasTck");
323 parBook.lFrameWidth = record->getDouble("ylFrame");
324 parBook.sFrameWidth = record->getDouble("ysFrame");
325
326 ATH_MSG_DEBUG("Parameters of the chamber " << key << " are: "
327 << " numStrips: " << parBook.numStrips
328 << " stripPitch: " << parBook.stripPitch
329 << " stripWidth: " << parBook.stripWidth
330 << " FirstStripPitch: "<< parBook.firstStripPitch
331 << " numWires: " << parBook.numWires
332 << " firstWireGroupWidth: " << parBook.firstWireGroupWidth
333 << " numWireGroups: " << parBook.numWireGroups
334 << " wireCutout: " << parBook.wireCutout
335 << " wirePitch: " << parBook.wirePitch
336 << " wireWidth: " << parBook.wireWidth
337 << " wireGroupWidth: " << parBook.wireGroupWidth
338 << " firstWirePosition: " << parBook.firstWirePos
339 << " Pads in Eta: " << parBook.numPadEta
340 << " Pads in Phi: " << parBook.numPadPhi
341 << " firstPadHeight: " << parBook.firstPadHeight
342 << " padHeight: " << parBook.padHeight
343 << " PadPhiShift: " << parBook.PadPhiShift
344 << " anglePadPhi: " << parBook.anglePadPhi
345 << " firstPadPhiDivision: " << parBook.firstPadPhiDivision
346 << " lPadLength: " << parBook.lPadLength
347 << " sPadLength: " << parBook.sPadLength
348 << " yCutout: " << parBook.yCutout
349 << " yCutoutCathode: " << parBook.yCutoutCathode
350 << " gasGapTck: " << parBook.gasTck
351 << " lFrameWidth: " << parBook.lFrameWidth
352 << " sFrameWidth: " << parBook.sFrameWidth);
353 }
354 return StatusCode::SUCCESS;
355}
356} // 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
unsigned int uint
#define y
#define x
virtual std::string tagName() const =0
virtual std::string nodeName() const =0
virtual unsigned int size() const =0
GeoChildNodeWithTrf physVolWithTrans
Helper struct to cache a PhysVolume pointer together with the transformation to go from the volume to...
The StripLayer interfaces the 2D description of the strip plane layout with the 3D description of the...
Definition StripLayer.h:19
void flipPhiRotation()
Flips the phi rotation from 90 -> -90 degrees.
static IdentifierHash createHash(const unsigned gasGap, const unsigned channelType, const unsigned channel, const unsigned wireInGrp=0)
Create a measurement hash from the Identifier fields.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
StatusCode loadDimensions(sTgcReadoutElement::defineArgs &args, FactoryCache &factory)
Loads the chamber dimensions from GeoModel.
sTgcShape extractParameters(const GeoShape *shape) const
PublicToolHandle< IMuonGeoUtilityTool > m_geoUtilTool
ServiceHandle< IGeoDbTagSvc > m_geoDbTagSvc
StatusCode readParameterBook(FactoryCache &cache)
Retrieves the auxillary tables from the database.
StatusCode buildReadOutElements(MuonDetectorManager &mgr) override final
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channelType, int channel) const
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
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...
GeoModel::TransientConstSharedPtr< WireGroupDesign > WireDesignPtr
RpcReadoutElement::defineArgs defineArgs
IMuonGeoUtilityTool::physVolWithTrans physVolWithTrans
GeoModel::TransientConstSharedPtr< StripDesign > StripDesignPtr
Definition StripDesign.h:29
GeoModel::TransientConstSharedPtr< PadDesign > PadDesignPtr
Definition PadDesign.h:22
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::vector< double > firstStripPitch
firstStripPitch needed for the globalChannelPosition function
std::set< PadDesignPtr, PadDesignSorter > padDesigns
std::set< StripDesignPtr, StripDesignSorter > stripDesigns
GeoDeDuplicator trfNodeMaker
Helper object to turn Amg::Transforms into GeoModel tree transform nodes.
std::set< WireDesignPtr, WireDesignSorter > wireGroupDesigns
Helper struct to translate the GeoModelShape into the parameters used to construct the readout elemen...
double longWidth
Width of the module at the upper edge.
double thickness
Thickness of the shape along global z.
double halfHeight
Height of the module in radial direction.
double shortWidth
Width of the module ath the bottom edge.
Struct to cache the relevant parameters of from the WSTGC tables.