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 }
147 else if (!gapPars.yCutOut) {
149 stripDesign->defineTrapezoid(gapPars.shortWidth, gapPars.longWidth, gapPars.halfHeight + 0.01);
150 stripDesign->defineStripLayout(Amg::Vector2D{firstStripPos, 0.},
151 paramBook.stripPitch, paramBook.stripWidth, paramBook.numStrips);
152 ATH_MSG_VERBOSE("Created new strip design "<<(*stripDesign));
153
155 wireGroupDesign->defineTrapezoid(0.5*paramBook.sPadLength, 0.5*paramBook.lPadLength, gapPars.halfHeight);
156 wireGroupDesign->flipTrapezoid();
157 wireGroupDesign->defineStripLayout(Amg::Vector2D{firstWirePos, 0.},
158 paramBook.wirePitch,
159 paramBook.wireWidth,
160 numWireGroups);
161 ATH_MSG_VERBOSE("Created new wireGroup design "<<(*wireGroupDesign));
162
164 padDesign->defineTrapezoid(0.5*paramBook.sPadLength, 0.5*paramBook.lPadLength, gapPars.halfHeight);
165 padDesign->flipTrapezoid();
166 ATH_MSG_VERBOSE("Created new pad design "<<(*padDesign));
167 }
168
170 wireGroupDesign->declareGroup(paramBook.firstWireGroupWidth[gasGap]);
171 for (uint wireGr=2; wireGr<numWireGroups; wireGr++){
172 wireGroupDesign->declareGroup(paramBook.wireGroupWidth);
173 }
174 unsigned int lastWireGroup = (paramBook.numWires[gasGap] - wireGroupDesign->nAllWires());
175 wireGroupDesign->declareGroup(lastWireGroup);
176 wireGroupDesign->defineWireCutout(paramBook.wireCutout[gasGap]);
177
179 double beamlineRadius = (define.physVol->getAbsoluteTransform() * gapVol.transform).translation().perp();
180 padDesign->defineBeamlineRadius(beamlineRadius);
181 ATH_MSG_DEBUG("The beamline radius is: " << beamlineRadius);
182 padDesign->definePadRow(paramBook.firstPadPhiDivision[gasGap],
183 paramBook.numPadPhi[gasGap],
184 paramBook.anglePadPhi,
185 paramBook.PadPhiShift[gasGap]);
186 padDesign->definePadColumn(paramBook.firstPadHeight[gasGap],
187 paramBook.numPadEta[gasGap],
188 paramBook.padHeight[gasGap]);
189
198 ++gasGap;
200 stripDesign = (*factoryCache.stripDesigns.emplace(stripDesign).first);
201 StripLayer stripLayer(factoryCache.trfNodeMaker.makeTransform(gapVol.transform
202 * Amg::getRotateZ3D(-90. * Gaudi::Units::deg)
203 * Amg::getRotateY3D(180* Gaudi::Units::deg)), stripDesign,
205 ATH_MSG_VERBOSE("Added new diamond strip layer at "<< stripLayer);
206 define.stripLayers.push_back(std::move(stripLayer));
207
209 wireGroupDesign = (*factoryCache.wireGroupDesigns.emplace(wireGroupDesign).first);
210 StripLayer wireGroupLayer(factoryCache.trfNodeMaker.makeTransform(gapVol.transform
211 * Amg::getRotateY3D(180* Gaudi::Units::deg)),
212 wireGroupDesign, sTgcReadoutElement::createHash(gasGap,
214 ATH_MSG_VERBOSE("Added new diamond wireGroup layer at "<<wireGroupLayer);
215 define.wireGroupLayers.push_back(std::move(wireGroupLayer));
216
218 padDesign = (*factoryCache.padDesigns.emplace(padDesign).first);
219 StripLayer padLayer(factoryCache.trfNodeMaker.makeTransform(gapVol.transform
220 * Amg::getRotateY3D(180* Gaudi::Units::deg)),
221 padDesign, sTgcReadoutElement::createHash(gasGap,
223 ATH_MSG_VERBOSE("Added new diamond pad layer at "<<padLayer);
224 define.padLayers.push_back(std::move(padLayer));
225 }
226 return StatusCode::SUCCESS;
227}
228
230 ATH_CHECK(m_geoDbTagSvc.retrieve());
231 ATH_CHECK(m_idHelperSvc.retrieve());
232 ATH_CHECK(m_geoUtilTool.retrieve());
233
234 GeoModelIO::ReadGeoModel* sqliteReader = m_geoDbTagSvc->getSqliteReader();
235 if (!sqliteReader) {
236 ATH_MSG_FATAL("Error, the tool works exclusively from sqlite geometry inputs");
237 return StatusCode::FAILURE;
238 }
239
240 FactoryCache facCache{};
241 ATH_CHECK(readParameterBook(facCache));
242
243 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
244 // Get the list of full phys volumes from SQLite, and create detector elements
245
246 physNodeMap mapFPV = sqliteReader->getPublishedNodes<std::string, GeoFullPhysVol*>("Muon");
247#ifndef SIMULATIONBASE
248 auto layerBounds = std::make_shared<Acts::SurfaceBoundFactory>();
249#endif
250
251 for (auto& [key, pv] : mapFPV) {
255 std::vector<std::string> key_tokens = tokenize(key, "_");
256 if (key_tokens.size() != 5 ||
257 key_tokens[0].find("sTGC") == std::string::npos)
258 continue;
259 ATH_MSG_DEBUG("Key is: "<<key);
260 bool isValid{false};
261 const std::string stName = key_tokens[1][1] == 'L' ? "STL" : "STS";
262 const int stEta = atoi(key_tokens[2]);
263 const int stPhi = atoi(key_tokens[3]);
264 const int ml = atoi(key_tokens[4]);
265
266 defineArgs define{};
267#ifndef SIMULATIONBASE
268 define.layerBounds = layerBounds;
269#endif
270 //Need identifier to get multilayer, the following constants don't matter.
271 define.detElId = idHelper.channelID(stName, stEta, stPhi, ml, 1, sTgcIdHelper::sTgcChannelTypes::Strip, 1, isValid);
272 if (!isValid) {
273 ATH_MSG_FATAL("Failed to build a good identifier out of " << key);
274 return StatusCode::FAILURE;
275 }
277 define.physVol = pv;
278 define.chambDesign = "sTGC_" + key_tokens[1];
279 define.alignTransform = m_geoUtilTool->findAlignableTransform(define.physVol);
280 ATH_MSG_VERBOSE("Key "<<key<<" lead to the identifier "<<m_idHelperSvc->toStringDetEl(define.detElId));
281 ATH_CHECK(loadDimensions(define, facCache));
282 std::unique_ptr<sTgcReadoutElement> readoutEle = std::make_unique<sTgcReadoutElement>(std::move(define));
283 ATH_CHECK(mgr.addsTgcReadoutElement(std::move(readoutEle)));
284 }
285 return StatusCode::SUCCESS;
286}
288 ServiceHandle<IRDBAccessSvc> accessSvc(m_geoDbTagSvc->getParamSvcName(), name());
289 ATH_CHECK(accessSvc.retrieve());
290 IRDBRecordset_ptr paramTable = accessSvc->getRecordsetPtr("WSTGC", "");
291 if (paramTable->size() == 0) {
292 ATH_MSG_FATAL("Empty parameter book table found");
293 return StatusCode::FAILURE;
294 }
295 ATH_MSG_VERBOSE("Found the " << paramTable->nodeName() << " ["
296 << paramTable->tagName() << "] table with "
297 << paramTable->size() << " records");
298 for (const IRDBRecord_ptr& record : *paramTable) {
299 // parameterBook pars{};
300 const std::string key = record-> getString("WSTGC_TYPE");
301 wSTGCTable& parBook = cache.parameterBook[key];
302 parBook.numStrips = record->getInt("nStrips");
303 parBook.stripPitch = record->getDouble("stripPitch");
304 parBook.stripWidth = record->getDouble("stripWidth");
305 parBook.firstStripPitch = tokenizeDouble(record->getString("firstStripWidth"), ";");
306
307 parBook.numWires = tokenizeInt(record->getString("nWires"), ";");
308 parBook.firstWireGroupWidth = tokenizeInt(record->getString("firstWireGroup"), ";");
309 parBook.numWireGroups = tokenizeInt(record->getString("nWireGroups"), ";");
310 parBook.wireCutout = tokenizeDouble(record->getString("wireCutout"), ";");
311 parBook.wirePitch = record->getDouble("wirePitch");
312 parBook.wireWidth = record->getDouble("wireWidth");
313 parBook.wireGroupWidth = record->getInt("wireGroupWidth");
314 parBook.firstWirePos = tokenizeDouble(record->getString("firstWire"), ";");
315
316 parBook.numPadEta = tokenizeInt(record->getString("nPadH"), ";");
317 parBook.numPadPhi = tokenizeInt(record->getString("nPadPhi"), ";");
318 parBook.firstPadHeight = tokenizeDouble(record->getString("firstPadH"), ";");
319 parBook.padHeight = tokenizeDouble(record->getString("padH"), ";");
320 parBook.PadPhiShift = tokenizeInt(record->getString("PadPhiShift"), ";");
321 parBook.anglePadPhi = record->getDouble("anglePadPhi");
322 parBook.firstPadPhiDivision = tokenizeDouble(record->getString("firstPadPhiDivision"), ";");
323 parBook.lPadLength = record->getDouble("lPadWidth");
324 parBook.sPadLength = record->getDouble("sPadWidth");
325
326 parBook.yCutout = record->getDouble("yCutout");
327 parBook.yCutoutCathode = record->getDouble("yCutoutCathode");
328 parBook.gasTck = record->getDouble("gasTck");
329 parBook.lFrameWidth = record->getDouble("ylFrame");
330 parBook.sFrameWidth = record->getDouble("ysFrame");
331
332 ATH_MSG_DEBUG("Parameters of the chamber " << key << " are: "
333 << " numStrips: " << parBook.numStrips
334 << " stripPitch: " << parBook.stripPitch
335 << " stripWidth: " << parBook.stripWidth
336 << " FirstStripPitch: "<< parBook.firstStripPitch
337 << " numWires: " << parBook.numWires
338 << " firstWireGroupWidth: " << parBook.firstWireGroupWidth
339 << " numWireGroups: " << parBook.numWireGroups
340 << " wireCutout: " << parBook.wireCutout
341 << " wirePitch: " << parBook.wirePitch
342 << " wireWidth: " << parBook.wireWidth
343 << " wireGroupWidth: " << parBook.wireGroupWidth
344 << " firstWirePosition: " << parBook.firstWirePos
345 << " Pads in Eta: " << parBook.numPadEta
346 << " Pads in Phi: " << parBook.numPadPhi
347 << " firstPadHeight: " << parBook.firstPadHeight
348 << " padHeight: " << parBook.padHeight
349 << " PadPhiShift: " << parBook.PadPhiShift
350 << " anglePadPhi: " << parBook.anglePadPhi
351 << " firstPadPhiDivision: " << parBook.firstPadPhiDivision
352 << " lPadLength: " << parBook.lPadLength
353 << " sPadLength: " << parBook.sPadLength
354 << " yCutout: " << parBook.yCutout
355 << " yCutoutCathode: " << parBook.yCutoutCathode
356 << " gasGapTck: " << parBook.gasTck
357 << " lFrameWidth: " << parBook.lFrameWidth
358 << " sFrameWidth: " << parBook.sFrameWidth);
359 }
360 return StatusCode::SUCCESS;
361}
362} // 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
static IdentifierHash createHash(const unsigned int gasGap, const unsigned int channelType, const unsigned int channel, const unsigned int 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::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.