ATLAS Offline Software
Loading...
Searching...
No Matches
MuonPhaseII/MuonDetDescr/MuonGeoModelTestR4/src/GeoModelRpcTest.cxx
Go to the documentation of this file.
1
2/*
3 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
4*/
5#include "GeoModelRpcTest.h"
10#include <fstream>
11
12namespace {
13// Splitting this out into a separate function avoids a false positive
14// out-of-bounds array access warning from gcc14 in the archflag build.
15// (It should also be addressed in versions of Eigen after 3.4.)
16std::string stripPosToString (const MuonGMR4::RpcReadoutElement* reElement,
17 const ActsTrk::GeometryContext& gctx,
18 const IdentifierHash measHash)
19{
20 Amg::Vector3D v = reElement->stripPosition(gctx, measHash);
21 return Amg::toString(v);
22}
23}
24
25using namespace ActsTrk;
26namespace MuonGMR4{
27
28
30 ATH_CHECK(m_idHelperSvc.retrieve());
31 ATH_CHECK(m_geoCtxKey.initialize());
32 if (m_visualStrips) {
33 m_clientToken.preFixName="GeoModelRpcTest";
34 m_clientToken.subDirectory = "RpcPlots";
35 m_clientToken.canvasLimit = -1;
36 m_clientToken.drawSqrtS = false;
37 ATH_CHECK(m_visualSvc.retrieve());
38 ATH_CHECK(m_visualSvc->registerClient(m_clientToken));
39 }
41 ATH_CHECK(m_tree.init(this));
42
43 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
44 auto translateTokenList = [this, &idHelper](const std::vector<std::string>& chNames){
45
46 std::set<Identifier> transcriptedIds{};
47 for (const std::string& token : chNames) {
48 if (token.size() != 6) {
49 ATH_MSG_WARNING("Wrong format given for "<<token<<". Expecting 6 characters");
50 continue;
51 }
53 const std::string statName = token.substr(0, 3);
54 const unsigned statEta = std::atoi(token.substr(3, 1).c_str()) * (token[4] == 'A' ? 1 : -1);
55 const unsigned statPhi = std::atoi(token.substr(5, 1).c_str());
56 bool isValid{false};
57 const Identifier eleId = idHelper.elementID(statName, statEta, statPhi, 1, isValid);
58 if (!isValid) {
59 ATH_MSG_WARNING("Failed to deduce a station name for " << token);
60 continue;
61 }
62 transcriptedIds.insert(eleId);
63 std::copy_if(idHelper.detectorElement_begin(), idHelper.detectorElement_end(),
64 std::inserter(transcriptedIds, transcriptedIds.end()),
65 [&eleId, &idHelper](const Identifier& copyMe){
66 return idHelper.stationName(copyMe) == idHelper.stationName(eleId) &&
67 idHelper.stationEta(copyMe) == idHelper.stationEta(eleId) &&
68 idHelper.stationPhi(copyMe) == idHelper.stationPhi(eleId);
69 });
70 }
71 return transcriptedIds;
72 };
73
74 std::vector <std::string>& selectedSt = m_selectStat.value();
75 const std::vector <std::string>& excludedSt = m_excludeStat.value();
76 selectedSt.erase(std::remove_if(selectedSt.begin(), selectedSt.end(),
77 [&excludedSt](const std::string& token){
78 return std::ranges::find(excludedSt, token) != excludedSt.end();
79 }), selectedSt.end());
80
81 if (selectedSt.size()) {
82 m_testStations = translateTokenList(selectedSt);
83 std::stringstream sstr{};
84 for (const Identifier& id : m_testStations) {
85 sstr<<" *** "<<m_idHelperSvc->toString(id)<<std::endl;
86 }
87 ATH_MSG_INFO("Test only the following stations "<<std::endl<<sstr.str());
88 } else {
89 const std::set<Identifier> excluded = translateTokenList(excludedSt);
91 for(auto itr = idHelper.detectorElement_begin();
92 itr!= idHelper.detectorElement_end();++itr){
93 if (!excluded.count(*itr)) {
94 m_testStations.insert(*itr);
95 }
96 }
98 if (!excluded.empty()) {
99 std::stringstream excluded_report{};
100 for (const Identifier& id : excluded){
101 excluded_report << " *** " << m_idHelperSvc->toStringDetEl(id) << std::endl;
102 }
103 ATH_MSG_INFO("Test all station except the following excluded ones " << std::endl << excluded_report.str());
104 }
105 }
106 ATH_CHECK(detStore()->retrieve(m_detMgr));
107 return StatusCode::SUCCESS;
108}
110 ATH_CHECK(m_tree.write());
111 return StatusCode::SUCCESS;
112}
113void GeoModelRpcTest::visualizeStripPanel(const EventContext& ctx,
114 const StripDesignPtr& design,
115 const Identifier& detId,
116 const bool measPhi) const {
117 if (!design || !m_visualStrips) {
118 return;
119 }
120 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
121 const std::string chName = std::format("{:}{:}{:}{:}R{:}Z{:}P{:}{:}",
122 m_idHelperSvc->stationNameString(detId),
123 std::abs(m_idHelperSvc->stationEta(detId)),
124 m_idHelperSvc->stationEta(detId) > 0 ? 'A' : 'C',
125 m_idHelperSvc->stationPhi(detId),
126 idHelper.doubletR(detId), idHelper.doubletZ(detId),
127 idHelper.doubletPhi(detId), measPhi ? "Phi" : "Eta");
128 auto canvas = m_visualSvc->prepareCanvas(ctx, m_clientToken, chName);
129 canvas->expandPad(-design->halfWidth(), -design->shortHalfHeight());
130 canvas->expandPad(design->halfWidth(), design->shortHalfHeight());
131 canvas->setAxisTitles("x [mm]", "y [mm]");
132 canvas->setRangeScale(1.1);
133 using namespace MuonValR4;
134 canvas->add(drawBox(Amg::Vector3D::Zero(),
135 2.*design->halfWidth(),
136 2.*design->shortHalfHeight(),
137 kBlack, hollowFilling));
138 constexpr int oddFill = 3315;
139 constexpr int evenFill = 3351;
140 for (int strip = design->firstStripNumber(); strip <= design->numStrips(); ++strip) {
141 const Amg::Vector2D stripPos = design->center(strip).value_or(Amg::Vector2D::Zero());
142 canvas->add(drawBox(Amg::Vector3D{0., stripPos.x(), stripPos.y()},
143 design->stripWidth(),
144 2.*design->shortHalfHeight(), strip % 2 ? kBlue: kRed,
145 strip % 2 ? oddFill : evenFill));
146 }
147 canvas->add(drawLabel(std::format("{:}, #{:}-panel",
148 m_idHelperSvc->toStringDetEl(detId),
149 measPhi ? "phi" : "eta"), 0.1, 0.05));
150 canvas->add(drawLabel(std::format("Dimensions: {:.1f}X{:.1f} [mm]",
151 2.*design->halfWidth(),
152 2.*design->shortHalfHeight()), 0.1, 0.015));
153}
155 const EventContext& ctx{Gaudi::Hive::currentContext()};
156
157 const ActsTrk::GeometryContext* geoContextHandle{nullptr};
158 ATH_CHECK(SG::get(geoContextHandle, m_geoCtxKey, ctx));
159 const ActsTrk::GeometryContext& gctx{*geoContextHandle};
160
161 for (const Identifier& test_me : m_testStations) {
162 ATH_MSG_DEBUG("Test retrieval of Rpc detector element "<<m_idHelperSvc->toStringDetEl(test_me));
163 const RpcReadoutElement* reElement = m_detMgr->getRpcReadoutElement(test_me);
164 if (!reElement) {
165 continue;
166 }
168 if (reElement->identify() != test_me) {
169 ATH_MSG_FATAL("Expected to retrieve "<<m_idHelperSvc->toStringDetEl(test_me)
170 <<". But got instead "<<m_idHelperSvc->toStringDetEl(reElement->identify()));
171 return StatusCode::FAILURE;
172 }
173 ATH_CHECK(dumpToTree(ctx, gctx, reElement));
174 visualizeStripPanel(ctx, reElement->getParameters().etaDesign, reElement->identify(), false);
175 visualizeStripPanel(ctx, reElement->getParameters().phiDesign, reElement->identify(), true);
176
177 const Amg::Transform3D globToLocal{reElement->globalToLocalTransform(gctx)};
178 const Amg::Transform3D& localToGlob{reElement->localToGlobalTransform(gctx)};
180 const Amg::Transform3D transClosure = globToLocal * localToGlob;
181 if (!Amg::doesNotDeform(transClosure)) {
182 ATH_MSG_FATAL("Closure test failed for "<<m_idHelperSvc->toStringDetEl(test_me)
183 <<". Ended up with "<< Amg::toString(transClosure) );
184 return StatusCode::FAILURE;
185 }
186 const RpcIdHelper& id_helper{m_idHelperSvc->rpcIdHelper()};
187 for (unsigned gasGap = 1; gasGap <= reElement->nGasGaps(); ++gasGap) {
188 for (int doubPhi = reElement->doubletPhi(); doubPhi <= reElement->doubletPhiMax(); ++doubPhi) {
189 for (bool measPhi: {false, true}) {
190 unsigned numStrip = (measPhi ? reElement->nPhiStrips() :
191 reElement->nEtaStrips());
192 for (unsigned strip = 1; strip < numStrip ; ++strip) {
193 bool isValid{false};
194 const Identifier chId = id_helper.channelID(reElement->identify(),
195 reElement->doubletZ(),
196 doubPhi, gasGap, measPhi, strip, isValid);
197 if (!isValid) {
198 continue;
199 }
201 const IdentifierHash measHash = reElement->measurementHash(chId);
202 const IdentifierHash layHash = reElement->layerHash(chId);
203 ATH_MSG_VERBOSE("gasGap: "<<gasGap<<", doubletPhi: "<<doubPhi<<", measPhi: "<<measPhi
204 <<" --> layerHash: "<<static_cast<unsigned>(layHash));
205 const Identifier backCnv = reElement->measurementId(measHash);
206 if (backCnv != chId) {
207 ATH_MSG_FATAL("The back and forth conversion of "<<m_idHelperSvc->toString(chId)
208 <<" failed. Got "<<m_idHelperSvc->toString(backCnv));
209 return StatusCode::FAILURE;
210 }
211 if (layHash != reElement->layerHash(measHash)) {
212 ATH_MSG_FATAL("Constructing the layer hash from the identifier "<<
213 m_idHelperSvc->toString(chId)<<" leadds to different layer hashes "<<
214 layHash<<" vs. "<< reElement->layerHash(measHash));
215 return StatusCode::FAILURE;
216 }
217 ATH_MSG_VERBOSE("Channel "<<m_idHelperSvc->toString(chId)<<" strip position "
218 <<stripPosToString(reElement, gctx, measHash));
219 }
220 }
221 }
222 }
223 }
224 return StatusCode::SUCCESS;
225}
226StatusCode GeoModelRpcTest::dumpToTree(const EventContext& ctx,
227 const ActsTrk::GeometryContext& gctx,
228 const RpcReadoutElement* reElement){
229
230 m_stIndex = reElement->stationName();
231 m_stEta = reElement->stationEta();
232 m_stPhi = reElement->stationPhi();
233 m_doubletR = reElement->doubletR();
234 m_doubletZ = reElement->doubletZ();
235 m_doubletPhi = reElement->doubletPhi();
236 m_chamberDesign = reElement->chamberDesign();
237
238 m_numRpcLayers = reElement->nGasGaps();
239
240 m_numGasGapsPhi = reElement->nPhiPanels();
241 m_numPhiPanels = reElement->nPhiPanels();
242
244 m_numStripsEta = reElement->nEtaStrips();
245 m_numStripsPhi = reElement->nPhiStrips();
246
247 m_stripEtaPitch = reElement->stripEtaPitch();
248 m_stripPhiPitch = reElement->stripPhiPitch();
249 m_stripEtaWidth = reElement->stripEtaWidth();
250 m_stripPhiWidth = reElement->stripPhiWidth();
251 m_stripEtaLength = reElement->stripEtaLength();
252 m_stripPhiLength = reElement->stripPhiLength();
253
255 m_envelopeWidth = 2.*reElement->getParameters().halfWidth;
256 m_envelopeLength = 2.*reElement->getParameters().halfLength;
258 const Amg::Transform3D& transform{reElement->localToGlobalTransform(gctx)};
259 m_readoutTransform = transform;
260 m_alignableNode = reElement->alignableTransform()->getDefTransform();
261
262 const RpcIdHelper& id_helper{m_idHelperSvc->rpcIdHelper()};
263
264 for (unsigned gasGap = 1; gasGap <= reElement->nGasGaps(); ++gasGap) {
265 for (int doubPhi = reElement->doubletPhi(); doubPhi <= reElement->doubletPhiMax(); ++doubPhi) {
266 for (bool measPhi: {false, true}) {
267 unsigned numStrip = (measPhi ? reElement->nPhiStrips() :
268 reElement->nEtaStrips());
269 for (unsigned strip = 1; strip <= numStrip ; ++strip) {
270
271 bool isValid{false};
272 const Identifier stripID = id_helper.channelID(reElement->identify(),
273 reElement->doubletZ(),
274 doubPhi, gasGap, measPhi, strip, isValid);
275 if (!isValid) {
276 ATH_MSG_WARNING("Invalid Identifier detected for readout element "
277 <<m_idHelperSvc->toStringDetEl(reElement->identify())
278 <<" gap: "<<gasGap<<" strip: "<<strip<<" meas phi: "<<measPhi);
279 continue;
280 }
281 const IdentifierHash measHash = reElement->measurementHash(stripID);
282 const IdentifierHash layHash = reElement->layerHash(measHash);
283 const Amg::Vector3D stripPos = reElement->stripPosition(gctx, measHash);
284 m_stripPos.push_back(stripPos);
285 m_locStripPos.push_back((reElement->globalToLocalTransform(gctx, layHash) * stripPos).block<2,1>(0,0));
286 m_stripPosGasGap.push_back(gasGap);
287 m_stripPosMeasPhi.push_back(measPhi);
288 m_stripPosNum.push_back(strip);
289 m_stripDblPhi.push_back(doubPhi);
290
291 if (strip != 1) continue;
292 const Amg::Transform3D locToGlob = reElement->localToGlobalTransform(gctx, layHash)
293 * Amg::getRotateZ3D(90.*Gaudi::Units::deg * measPhi);
294 m_stripRot.push_back(locToGlob);
295 m_stripRotGasGap.push_back(gasGap);
296 m_stripRotMeasPhi.push_back(measPhi);
297 m_stripRotDblPhi.push_back(doubPhi);
298 }
299 }
300 }
301 }
302 return m_tree.fill(ctx) ? StatusCode::SUCCESS : StatusCode::FAILURE;
303}
304
305}
306
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(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
const ServiceHandle< StoreGateSvc > & detStore() const
This is a "hash" representation of an Identifier.
Gaudi::Property< bool > m_visualStrips
Flag toggling whether the strip planes shall be printed.
void visualizeStripPanel(const EventContext &ctx, const StripDesignPtr &design, const Identifier &detId, const bool measPhi) const
Draw the strips in the panel on a Canvas.
MuonVal::ScalarBranch< float > & m_envelopeHeight
Box dimension.
ServiceHandle< MuonValR4::IRootVisualizationService > m_visualSvc
Service handle of the visualization service.
MuonVal::CoordSystemsBranch m_stripRot
Rotation matrix of the respective layers.
Gaudi::Property< std::vector< std::string > > m_selectStat
String should be formated like <stationName><stationEta><A/C><stationPhi>
MuonValR4::IRootVisualizationService::ClientToken m_clientToken
Token to be presented to the visualization service.
MuonVal::ScalarBranch< uint8_t > & m_numRpcLayers
Number of eta & phi gas gaps.
MuonVal::ScalarBranch< uint8_t > & m_numStripsEta
Number of strips, strip pitch in eta & phi direction.
StatusCode dumpToTree(const EventContext &ctx, const ActsTrk::GeometryContext &gctx, const RpcReadoutElement *readoutEle)
MuonVal::ScalarBranch< unsigned short > & m_stIndex
Identifier of the readout element.
MuonVal::CoordTransformBranch m_readoutTransform
Transformation of the readout element (Translation, ColX, ColY, ColZ)
MuonVal::ScalarBranch< float > & m_stripEtaPitch
Strip dimensions.
std::set< Identifier > m_testStations
Set of stations to be tested.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the local coordinate system of the readout element into the global AT...
int stationEta() const
Returns the stationEta (positive A site, negative C site)
Amg::Transform3D globalToLocalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the global ATLAS coordinate system into the local coordinate system o...
const std::string & chamberDesign() const
The chamber design refers to the construction parameters of a readout element.
Identifier identify() const override final
Return the ATLAS identifier.
int stationName() const
Returns the stationName (BIS, BOS, etc) encoded into the integer.
int stationPhi() const
Returns the stationPhi (1-8) -> sector (2*phi - (isSmall))
const GeoAlignableTransform * alignableTransform() const
Return the alignable transform node of the readout element.
unsigned nPhiStrips() const
Number of strips measuring the phi coordinate.
IdentifierHash measurementHash(const Identifier &measId) const override final
Constructs the identifier hash from the full measurement Identifier.
int doubletR() const
Returns the doublet R field of the MuonReadoutElement identifier.
int doubletZ() const
Returns the doublet Z field of the MuonReadoutElement identifier.
int doubletPhi() const
Returns the doublet Phi field of the MuonReadoutElement identifier.
double stripPhiLength() const
Returns the length of a phi strip.
IdentifierHash layerHash(const Identifier &measId) const override final
The layer hash removes the bits from the IdentifierHash corresponding to the measurement's channel nu...
double stripEtaWidth() const
Strip width in eta.
Identifier measurementId(const IdentifierHash &measHash) const override final
Back conversion of the measurement hash to a full Athena Identifier The behaviour is undefined if a l...
double stripPhiPitch() const
Strip pitch in phi.
unsigned nEtaStrips() const
Number of strips measuring the eta coordinate.
double stripEtaPitch() const
Strip pitch in eta.
Amg::Vector3D stripPosition(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the position of the strip center.
int nPhiPanels() const
Returns the number of phi panels (1 or 2)
double stripPhiWidth() const
Strip width in phi.
unsigned nGasGaps() const
Returns the number of gasgaps described by this ReadOutElement (usally 2 or 3)
double stripEtaLength() const
Returns the length of an eta strip.
const_id_iterator detectorElement_begin() const
Iterators over full set of ids.
const_id_iterator detectorElement_end() const
Identifier channelID(int stationName, int stationEta, int stationPhi, int doubletR, int doubletZ, int doubletPhi, int gasGap, int measuresPhi, int strip) const
Identifier elementID(int stationName, int stationEta, int stationPhi, int doubletR) const
int doubletPhi(const Identifier &id) const
int doubletR(const Identifier &id) const
int doubletZ(const Identifier &id) 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.
bool doesNotDeform(const Amg::Transform3D &trans)
Checks whether the linear part of the transformation rotates or stetches any of the basis vectors.
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
GeoModel::TransientConstSharedPtr< StripDesign > StripDesignPtr
Definition StripDesign.h:29
Lightweight algorithm to read xAOD MDT sim hits and (fast-digitised) drift circles from SG and fill a...
constexpr int hollowFilling
Filling codes for hollow / fullFilling / hatched filling.
std::unique_ptr< TLatex > drawLabel(const std::string &text, const double xPos, const double yPos, const unsigned int fontSize=18, const bool useNDC=true)
Create a TLatex label,.
std::unique_ptr< TBox > drawBox(const Amg::Vector3D &boxCenter, const double boxWidth, const double boxHeight, const int color=kGreen+2, const int fillStyle=hollowFilling, const int view=objViewEta)
Creates a box for drawing, e.g strip measurements.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
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.