ATLAS Offline Software
Loading...
Searching...
No Matches
RpcReadoutGeomTool.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
13
14#include <GeoModelKernel/GeoFullPhysVol.h>
15#include <GeoModelKernel/GeoPhysVol.h>
16#include <GeoModelKernel/GeoBox.h>
17
18#include <GeoModelRead/ReadGeoModel.h>
21
22#ifndef SIMULATIONBASE
23# include "Acts/Utilities/BoundFactory.hpp"
24#endif
25
26using namespace CxxUtils;
27using namespace ActsTrk;
28
29namespace MuonGMR4 {
30
33
36struct gapVolume: public GeoChildNodeWithTrf {
37 gapVolume(GeoChildNodeWithTrf&& physVol,
38 unsigned gap,
39 unsigned phi):
40 GeoChildNodeWithTrf{std::move(physVol)},
41 gasGap{gap},
42 doubPhi{phi} {}
43 unsigned gasGap{0};
44 unsigned doubPhi{0};
45
46};
47
48
49std::unique_ptr<StripDesign> RpcReadoutGeomTool::constructDesign(const GeoBox* planeBox,
50 const wRPCTable& paramBook,
51 bool phiPlane) const {
52 const unsigned nStrips = phiPlane ? paramBook.numPhiStrips : paramBook.numEtaStrips;
53 if (!nStrips) {
54 ATH_MSG_VERBOSE("Parameter book does not for see a readout in "<<(phiPlane? "phi" : "eta")<<" direction");
55 return nullptr;
56 }
57
58 const double halfX = phiPlane ? planeBox->getYHalfLength() : planeBox->getZHalfLength();
59 const double halfY = phiPlane ? planeBox->getZHalfLength() : planeBox->getYHalfLength();
60
61 const double pitch = phiPlane ? paramBook.stripPitchPhi : paramBook.stripPitchEta;
62 const double width = phiPlane ? paramBook.stripWidthPhi : paramBook.stripWidthEta;
63 const double firstPos = -halfX + (phiPlane ? paramBook.firstOffSetPhi : paramBook.firstOffSetEta);
64 auto newDesign = std::make_unique<StripDesign>();
65 newDesign->defineTrapezoid(halfY, halfY, halfX);
66 newDesign->defineStripLayout(firstPos * Amg::Vector2D::UnitX(), pitch,width, nStrips);
67 return newDesign;
68}
69
71 FactoryCache& factoryCache) {
72
73 ATH_MSG_VERBOSE("Load dimensions of "<<m_idHelperSvc->toString(define.detElId)
74 <<std::endl<<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
75
76 const GeoShape* shape = m_geoUtilTool->extractShape(define.physVol);
77 if (!shape) {
78 ATH_MSG_FATAL("Failed to deduce a valid shape for "<<m_idHelperSvc->toString(define.detElId));
79 return StatusCode::FAILURE;
80 }
81 ATH_MSG_DEBUG("Extracted shape "<<m_geoUtilTool->dumpShape(shape));
83 if (shape->typeID() != GeoBox::getClassTypeID()) {
84 ATH_MSG_FATAL(__FILE__<<":"<<__LINE__<<" expect shape to be a box but it's "<<m_geoUtilTool->dumpShape(shape));
85 return StatusCode::FAILURE;
86 }
87
88 const GeoBox* box = static_cast<const GeoBox*>(shape);
89 define.halfThickness = box->getXHalfLength() * Gaudi::Units::mm;
90 define.halfLength = box->getZHalfLength() * Gaudi::Units::mm;
91 define.halfWidth = box->getYHalfLength() * Gaudi::Units::mm;
92
102 std::vector<GeoChildNodeWithTrf> rpcLayers = getChildrenWithRef(define.physVol, false);
104 rpcLayers.erase(std::remove_if(rpcLayers.begin(), rpcLayers.end(),
105 [](const GeoChildNodeWithTrf& subVol){ return !subVol.volumeId; }), rpcLayers.end());
107 std::ranges::sort(rpcLayers, [](const GeoChildNodeWithTrf& a, const GeoChildNodeWithTrf& b){
108 return a.volumeId.value_or(0) < b.volumeId.value_or(0);});
109
110 if (rpcLayers.empty()) {
111 ATH_MSG_FATAL("The volume "<<m_idHelperSvc->toStringDetEl(define.detElId)<<" does not have any childern with Identifiers "
112 <<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
113 return StatusCode::FAILURE;
114 }
116 unsigned gasGap{0};
117 const unsigned modulePhi = m_idHelperSvc->rpcIdHelper().doubletPhi(define.detElId);
118
119 std::vector<gapVolume> allGapsWithIdx{};
120 for (const GeoChildNodeWithTrf& rpcSinglet : rpcLayers) {
121 auto fetchNodes = [this, &rpcSinglet] (const std::string& leafName) {
122 std::vector<GeoChildNodeWithTrf> nodes = m_geoUtilTool->findAllLeafNodesByName(rpcSinglet.volume, leafName);
123 std::ranges::for_each(nodes,[&rpcSinglet](GeoChildNodeWithTrf& node){ node.transform = rpcSinglet.transform * node.transform; });
124 return nodes;
125 };
126 std::vector<GeoChildNodeWithTrf> gasGaps = fetchNodes("RpcGasGap");
127 if (gasGaps.empty()) {
128 ATH_MSG_FATAL("The child "<<m_geoUtilTool->dumpVolume(rpcSinglet.volume)<<" has "<<gasGaps.size()<<" gasGaps. ");
129 return StatusCode::FAILURE;
130 }
131 std::vector<GeoChildNodeWithTrf> stripLayers = fetchNodes("bottomStripLayer");
132 if (stripLayers.empty()) {
133 ATH_MSG_FATAL("The child "<<m_geoUtilTool->dumpVolume(rpcSinglet.volume)<<" does not have a strip layer ");
134 return StatusCode::FAILURE;
135 }
136 ++gasGap;
137 for (GeoChildNodeWithTrf& stripPanel : stripLayers) {
139 stripPanel.transform.translation().x() = gasGaps.front().transform.translation().x();
140 const int doubPhi = std::max(modulePhi, 1u*stripPanel.volumeId.value_or(999));
141 allGapsWithIdx.emplace_back(std::move(stripPanel), gasGap, doubPhi);
142 }
143 }
144
145 const bool isAside{m_idHelperSvc->stationEta(define.detElId) > 0};
147 define.nGasGaps = gasGap;
150 define.nPanelsInPhi = modulePhi == 2 ? 1 : allGapsWithIdx.size () / gasGap;
151 FactoryCache::ParamBookTable::const_iterator parBookItr = factoryCache.parameterBook.find(define.chambDesign);
152 if (parBookItr == factoryCache.parameterBook.end()) {
153 ATH_MSG_FATAL("The chamber "<<define.chambDesign<<" is not part of the WRPC table");
154 return StatusCode::FAILURE;
155 }
156 const wRPCTable& paramBook{parBookItr->second};
157
158 auto insertStripLayer = [this, &define, &factoryCache](std::unique_ptr<StripLayer> stripLay) {
159 const unsigned layIdx = static_cast<unsigned>(stripLay->hash());
160 if (layIdx >= define.layers.size()) {
161 define.layers.resize(layIdx + 1);
162 }
163 define.layers[layIdx] = (*factoryCache.stripLayers.emplace(std::move(stripLay)).first);
164 ATH_MSG_VERBOSE("Added new eta gap at "<<(*define.layers[layIdx]));
165 };
166 for (gapVolume& gapVol : allGapsWithIdx) {
167 const GeoShape* gapShape = m_geoUtilTool->extractShape(gapVol.volume);
168 if (gapShape->typeID() != GeoBox::getClassTypeID()) {
169 ATH_MSG_FATAL("Failed to extract a geo shape");
170 return StatusCode::FAILURE;
171 }
172 const GeoBox* gapBox = static_cast<const GeoBox*>(gapShape);
173 ATH_MSG_DEBUG("Gas gap dimensions "<<m_geoUtilTool->dumpShape(gapBox));
174 StripDesignPtr etaDesign = constructDesign(gapBox, paramBook, false);
175 StripDesignPtr phiDesign = constructDesign(gapBox, paramBook, true);
176 if (etaDesign) {
177 etaDesign = (*factoryCache.stripDesigns.emplace(etaDesign).first);
178 }
179 if (phiDesign) {
180 phiDesign = (*factoryCache.stripDesigns.emplace(phiDesign).first);
181 }
182 if (!define.etaDesign) {
183 define.etaDesign = etaDesign;
184 }
185 if (!define.phiDesign) {
186 define.phiDesign = phiDesign;
187 }
188 gapVol.transform = gapVol.transform * Amg::getRotateY3D( (isAside ? -90. : 90.)* Gaudi::Units::degree);
189
190 if (etaDesign && phiDesign) {
191 insertStripLayer(std::make_unique<StripLayer>(factoryCache.trfNodeMaker.makeTransform(gapVol.transform),
192 etaDesign, phiDesign,
193 RpcReadoutElement::createHash(0, gapVol.gasGap, gapVol.doubPhi, false)));
194 } else if (etaDesign) {
195 insertStripLayer(std::make_unique<StripLayer>(factoryCache.trfNodeMaker.makeTransform(gapVol.transform),
196 etaDesign, RpcReadoutElement::createHash(0, gapVol.gasGap, gapVol.doubPhi, false)));
197 } else {
198 ATH_MSG_ERROR("It's not forseen to have a chamber without eta design");
199 return StatusCode::FAILURE;
200 }
201 }
202 return StatusCode::SUCCESS;
203}
205 GeoModelIO::ReadGeoModel* sqliteReader = m_geoDbTagSvc->getSqliteReader();
206 if (!sqliteReader) {
207 ATH_MSG_FATAL("Error, the tool works exclusively from sqlite geometry inputs");
208 return StatusCode::FAILURE;
209 }
210
211 FactoryCache facCache{};
212 ATH_CHECK(readParameterBook(facCache));
213
214 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
215 // Get the list of full phys volumes from SQLite, and create detector elements
216
218 physNodeMap mapFPV = sqliteReader->getPublishedNodes<std::string, GeoFullPhysVol*>("Muon");
219#ifndef SIMULATIONBASE
220 auto layerBounds = std::make_shared<Acts::SurfaceBoundFactory>();
221#endif
222 for (auto& [key, pv] : mapFPV) {
229 std::vector<std::string> key_tokens = tokenize(key, "_");
230 if (key_tokens.size() < 7 ||
231 key_tokens[1].find("RPC") == std::string::npos) {
232 continue;
233 }
234 bool isValid{false};
236 const Identifier elementID = idHelper.padID(idHelper.stationNameIndex(key_tokens[0].substr(0, 3)),
237 atoi(key_tokens[2]),
238 atoi(key_tokens[3]),
239 atoi(key_tokens[4]),
240 atoi(key_tokens[6]),
241 atoi(key_tokens[5]),
242 isValid);
243 if (!isValid) {
244 ATH_MSG_FATAL("Failed to construct the station Identifier from "<<key);
245 return StatusCode::FAILURE;
246 }
247 defineArgs define{};
248 define.physVol = pv;
249 define.chambDesign = key_tokens[1];
250 define.alignTransform = m_geoUtilTool->findAlignableTransform(define.physVol);
251 define.detElId = elementID;
252 ATH_MSG_VERBOSE("Key "<<key<<" lead to Identifier "<<m_idHelperSvc->toStringDetEl(elementID));
253 ATH_CHECK(loadDimensions(define, facCache));
254#ifndef SIMULATIONBASE
255 define.layerBounds = layerBounds;
256#endif
257 std::unique_ptr<RpcReadoutElement> readoutEle = std::make_unique<RpcReadoutElement>(std::move(define));
258 ATH_CHECK(mgr.addRpcReadoutElement(std::move(readoutEle)));
259 }
260 return StatusCode::SUCCESS;
261}
263 ServiceHandle<IRDBAccessSvc> accessSvc(m_geoDbTagSvc->getParamSvcName(), name());
264 ATH_CHECK(accessSvc.retrieve());
265 IRDBRecordset_ptr paramTable = accessSvc->getRecordsetPtr("WRPC", "");
266 if (paramTable->size() == 0) {
267 ATH_MSG_FATAL("Empty parameter book table found");
268 return StatusCode::FAILURE;
269 }
270 ATH_MSG_VERBOSE("Found the " << paramTable->nodeName() << " ["
271 << paramTable->tagName() << "] table with "
272 << paramTable->size() << " records");
273
274 for (const IRDBRecord_ptr& record : *paramTable) {
275 const std::string chambType = record->getString("WRPC_TYPE");
276 wRPCTable& parBook = cache.parameterBook[record->getString("WRPC_TYPE")];
277 parBook.stripPitchEta = record->getDouble("etaStripPitch") * Gaudi::Units::cm;
278 parBook.stripPitchPhi = record->getDouble("phiStripPitch") * Gaudi::Units::cm;
279 const double stripDeadWidth = record->getDouble("stripDeadWidth") * Gaudi::Units::cm;
280 parBook.stripWidthEta = parBook.stripPitchEta - stripDeadWidth;
281 parBook.stripWidthPhi = parBook.stripPitchPhi - stripDeadWidth;
282 parBook.numEtaStrips = record->getInt("nEtaStrips");
283 parBook.numPhiStrips = record->getInt("nPhiStrips");
284 parBook.firstOffSetPhi = record->getDouble("phiStripOffSet") * Gaudi::Units::cm +
285 0.5 * parBook.stripPitchPhi;
286 parBook.firstOffSetEta = record->getDouble("etaStripOffSet") * Gaudi::Units::cm +
287 record->getDouble("TCKSSU") * Gaudi::Units::cm +
288 0.5 * parBook.stripPitchEta;
289
290 ATH_MSG_VERBOSE("Extracted parameters for chamber "<<chambType
291 <<", num strips (eta/phi): "<<parBook.numEtaStrips<<"/"<<parBook.numPhiStrips
292 <<", strip pitch (eta/phi) "<<parBook.stripPitchEta<<"/"<<parBook.stripPitchPhi
293 <<", strip width (eta/phi): "<<parBook.stripWidthEta<<"/"<<parBook.stripWidthPhi
294 <<", strip offset (eta/phi): "<<parBook.firstOffSetEta<<"/"<<parBook.firstOffSetPhi
295 <<", etaStripOffSet: "<<(record->getDouble("etaStripOffSet") * Gaudi::Units::cm)
296 <<", phiStripOffSet: "<<(record->getDouble("phiStripOffSet") * Gaudi::Units::cm)
297 <<", TCKSSU: "<<(record->getDouble("TCKSSU")* Gaudi::Units::cm));
298 }
299 return StatusCode::SUCCESS;
300}
301} // namespace MuonGMR4
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#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
static Double_t a
const double width
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...
static IdentifierHash createHash(const unsigned strip, const unsigned gasGap, const unsigned doubPhi, const bool measPhi)
Constructs an Identifier hash from the Identifier fields controlled by this readout element.
PublicToolHandle< IMuonGeoUtilityTool > m_geoUtilTool
StatusCode readParameterBook(FactoryCache &cache)
Retrieves the auxillary tables from the database.
ServiceHandle< IGeoDbTagSvc > m_geoDbTagSvc
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
StatusCode buildReadOutElements(MuonDetectorManager &mgr) override final
std::unique_ptr< StripDesign > constructDesign(const GeoBox *planeBox, const wRPCTable &paramBook, bool phiPlane) const
Constructs a new Strip design from the parameter book to describe either the phi plane or the eta str...
StatusCode loadDimensions(RpcReadoutElement::defineArgs &args, FactoryCache &factory)
Loads the chamber dimensions from GeoModel.
int stationNameIndex(const std::string &name) const
Identifier padID(const Identifier &elementID, int doubletZ, int doubletPhi) const
Definition node.h:24
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Amg::Transform3D getRotateY3D(double angle)
get a rotation transformation around Y-axis
std::vector< std::string > tokenize(const std::string &the_str, std::string_view delimiters)
Splits the string into smaller substrings.
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)
RpcReadoutElement::defineArgs defineArgs
IMuonGeoUtilityTool::physVolWithTrans physVolWithTrans
GeoModel::TransientConstSharedPtr< StripDesign > StripDesignPtr
Definition StripDesign.h:29
STL namespace.
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
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,...
int nPanelsInPhi
Each gas gap is usually subdivided into 2 phi panels which is actually the sector granularity of the ...
unsigned nGasGaps
The number of gas gaps (along the radial direction) in the RPC chamber (2 or 3)
Cache object to the wRPCTable & store stripDesigns & layers to make the information available through...
std::set< StripLayerPtr, StripLayerSorter > stripLayers
std::set< StripDesignPtr, StripDesignSorter > stripDesigns
GeoDeDuplicator trfNodeMaker
Helper object to turn Amg::Transforms into GeoModel tree transform nodes.
Struct to cache the relevant parameters of from the WRPC tables.
double firstOffSetEta
Offset of the first eta strip.
unsigned int numEtaStrips
Number of eta strips.
unsigned int numPhiStrips
Number of phi strips.
double firstOffSetPhi
Offset of the first phi strip.
Helper struct to attribute the Identifier fields with the gas gap volumes.
gapVolume(GeoChildNodeWithTrf &&physVol, unsigned gap, unsigned phi)