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-2025 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 ATH_CHECK(m_visualSvc.retrieve());
37 ATH_CHECK(m_visualSvc->registerClient(m_clientToken));
38 }
40 ATH_CHECK(m_tree.init(this));
41
42 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
43 auto translateTokenList = [this, &idHelper](const std::vector<std::string>& chNames){
44
45 std::set<Identifier> transcriptedIds{};
46 for (const std::string& token : chNames) {
47 if (token.size() != 6) {
48 ATH_MSG_WARNING("Wrong format given for "<<token<<". Expecting 6 characters");
49 continue;
50 }
52 const std::string statName = token.substr(0, 3);
53 const unsigned statEta = std::atoi(token.substr(3, 1).c_str()) * (token[4] == 'A' ? 1 : -1);
54 const unsigned statPhi = std::atoi(token.substr(5, 1).c_str());
55 bool isValid{false};
56 const Identifier eleId = idHelper.elementID(statName, statEta, statPhi, 1, isValid);
57 if (!isValid) {
58 ATH_MSG_WARNING("Failed to deduce a station name for " << token);
59 continue;
60 }
61 transcriptedIds.insert(eleId);
62 std::copy_if(idHelper.detectorElement_begin(), idHelper.detectorElement_end(),
63 std::inserter(transcriptedIds, transcriptedIds.end()),
64 [&eleId, &idHelper](const Identifier& copyMe){
65 return idHelper.stationName(copyMe) == idHelper.stationName(eleId) &&
66 idHelper.stationEta(copyMe) == idHelper.stationEta(eleId) &&
67 idHelper.stationPhi(copyMe) == idHelper.stationPhi(eleId);
68 });
69 }
70 return transcriptedIds;
71 };
72
73 std::vector <std::string>& selectedSt = m_selectStat.value();
74 const std::vector <std::string>& excludedSt = m_excludeStat.value();
75 selectedSt.erase(std::remove_if(selectedSt.begin(), selectedSt.end(),
76 [&excludedSt](const std::string& token){
77 return std::ranges::find(excludedSt, token) != excludedSt.end();
78 }), selectedSt.end());
79
80 if (selectedSt.size()) {
81 m_testStations = translateTokenList(selectedSt);
82 std::stringstream sstr{};
83 for (const Identifier& id : m_testStations) {
84 sstr<<" *** "<<m_idHelperSvc->toString(id)<<std::endl;
85 }
86 ATH_MSG_INFO("Test only the following stations "<<std::endl<<sstr.str());
87 } else {
88 const std::set<Identifier> excluded = translateTokenList(excludedSt);
90 for(auto itr = idHelper.detectorElement_begin();
91 itr!= idHelper.detectorElement_end();++itr){
92 if (!excluded.count(*itr)) {
93 m_testStations.insert(*itr);
94 }
95 }
97 if (!excluded.empty()) {
98 std::stringstream excluded_report{};
99 for (const Identifier& id : excluded){
100 excluded_report << " *** " << m_idHelperSvc->toStringDetEl(id) << std::endl;
101 }
102 ATH_MSG_INFO("Test all station except the following excluded ones " << std::endl << excluded_report.str());
103 }
104 }
105 ATH_CHECK(detStore()->retrieve(m_detMgr));
106 return StatusCode::SUCCESS;
107}
109 ATH_CHECK(m_tree.write());
110 return StatusCode::SUCCESS;
111}
112void GeoModelRpcTest::visualizeStripPanel(const EventContext& ctx,
113 const StripDesignPtr& design,
114 const Identifier& detId,
115 const bool measPhi) const {
116 if (!design || !m_visualStrips) {
117 return;
118 }
119 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
120 const std::string chName = std::format("{:}{:}{:}{:}R{:}Z{:}P{:}{:}",
121 m_idHelperSvc->stationNameString(detId),
122 std::abs(m_idHelperSvc->stationEta(detId)),
123 m_idHelperSvc->stationEta(detId) > 0 ? 'A' : 'C',
124 m_idHelperSvc->stationPhi(detId),
125 idHelper.doubletR(detId), idHelper.doubletZ(detId),
126 idHelper.doubletPhi(detId), measPhi ? "Phi" : "Eta");
127 auto canvas = m_visualSvc->prepareCanvas(ctx, m_clientToken, chName);
128 canvas->expandPad(-design->halfWidth(), -design->shortHalfHeight());
129 canvas->expandPad(design->halfWidth(), design->shortHalfHeight());
130 canvas->setAxisTitles("x [mm]", "y [mm]");
131 canvas->setRangeScale(1.1);
132 using namespace MuonValR4;
133 canvas->add(drawBox(Amg::Vector3D::Zero(),
134 2.*design->halfWidth(),
135 2.*design->shortHalfHeight(),
136 kBlack, hollowFilling));
137 constexpr int oddFill = 3315;
138 constexpr int evenFill = 3351;
139 for (int strip = design->firstStripNumber(); strip <= design->numStrips(); ++strip) {
140 const Amg::Vector2D stripPos = design->center(strip).value_or(Amg::Vector2D::Zero());
141 canvas->add(drawBox(Amg::Vector3D{0., stripPos.x(), stripPos.y()},
142 design->stripWidth(),
143 2.*design->shortHalfHeight(), strip % 2 ? kBlue: kRed,
144 strip % 2 ? oddFill : evenFill));
145 }
146 canvas->add(drawLabel(std::format("{:}, #{:}-panel", m_idHelperSvc->toStringDetEl(detId),
147 measPhi ? "phi" : "eta"), 0.2, 0.05));
148}
150 const EventContext& ctx{Gaudi::Hive::currentContext()};
151
152 const ActsTrk::GeometryContext* geoContextHandle{nullptr};
153 ATH_CHECK(SG::get(geoContextHandle, m_geoCtxKey, ctx));
154 const ActsTrk::GeometryContext& gctx{*geoContextHandle};
155
156 for (const Identifier& test_me : m_testStations) {
157 ATH_MSG_DEBUG("Test retrieval of Rpc detector element "<<m_idHelperSvc->toStringDetEl(test_me));
158 const RpcReadoutElement* reElement = m_detMgr->getRpcReadoutElement(test_me);
159 if (!reElement) {
160 continue;
161 }
163 if (reElement->identify() != test_me) {
164 ATH_MSG_FATAL("Expected to retrieve "<<m_idHelperSvc->toStringDetEl(test_me)
165 <<". But got instead "<<m_idHelperSvc->toStringDetEl(reElement->identify()));
166 return StatusCode::FAILURE;
167 }
168 ATH_CHECK(dumpToTree(ctx, gctx, reElement));
169 visualizeStripPanel(ctx, reElement->getParameters().etaDesign, reElement->identify(), false);
170 visualizeStripPanel(ctx, reElement->getParameters().phiDesign, reElement->identify(), true);
171
172 const Amg::Transform3D globToLocal{reElement->globalToLocalTrans(gctx)};
173 const Amg::Transform3D& localToGlob{reElement->localToGlobalTrans(gctx)};
175 const Amg::Transform3D transClosure = globToLocal * localToGlob;
176 if (!Amg::doesNotDeform(transClosure)) {
177 ATH_MSG_FATAL("Closure test failed for "<<m_idHelperSvc->toStringDetEl(test_me)
178 <<". Ended up with "<< Amg::toString(transClosure) );
179 return StatusCode::FAILURE;
180 }
181 const RpcIdHelper& id_helper{m_idHelperSvc->rpcIdHelper()};
182 for (unsigned gasGap = 1; gasGap <= reElement->nGasGaps(); ++gasGap) {
183 for (int doubPhi = reElement->doubletPhi(); doubPhi <= reElement->doubletPhiMax(); ++doubPhi) {
184 for (bool measPhi: {false, true}) {
185 unsigned numStrip = (measPhi ? reElement->nPhiStrips() :
186 reElement->nEtaStrips());
187 for (unsigned strip = 1; strip < numStrip ; ++strip) {
188 bool isValid{false};
189 const Identifier chId = id_helper.channelID(reElement->identify(),
190 reElement->doubletZ(),
191 doubPhi, gasGap, measPhi, strip, isValid);
192 if (!isValid) {
193 continue;
194 }
196 const IdentifierHash measHash = reElement->measurementHash(chId);
197 const IdentifierHash layHash = reElement->layerHash(chId);
198 ATH_MSG_VERBOSE("gasGap: "<<gasGap<<", doubletPhi: "<<doubPhi<<", measPhi: "<<measPhi
199 <<" --> layerHash: "<<static_cast<unsigned>(layHash));
200 const Identifier backCnv = reElement->measurementId(measHash);
201 if (backCnv != chId) {
202 ATH_MSG_FATAL("The back and forth conversion of "<<m_idHelperSvc->toString(chId)
203 <<" failed. Got "<<m_idHelperSvc->toString(backCnv));
204 return StatusCode::FAILURE;
205 }
206 if (layHash != reElement->layerHash(measHash)) {
207 ATH_MSG_FATAL("Constructing the layer hash from the identifier "<<
208 m_idHelperSvc->toString(chId)<<" leadds to different layer hashes "<<
209 layHash<<" vs. "<< reElement->layerHash(measHash));
210 return StatusCode::FAILURE;
211 }
212 ATH_MSG_VERBOSE("Channel "<<m_idHelperSvc->toString(chId)<<" strip position "
213 <<stripPosToString(reElement, gctx, measHash));
214 }
215 }
216 }
217 }
218 }
219 return StatusCode::SUCCESS;
220}
221StatusCode GeoModelRpcTest::dumpToTree(const EventContext& ctx,
222 const ActsTrk::GeometryContext& gctx,
223 const RpcReadoutElement* reElement){
224
225 m_stIndex = reElement->stationName();
226 m_stEta = reElement->stationEta();
227 m_stPhi = reElement->stationPhi();
228 m_doubletR = reElement->doubletR();
229 m_doubletZ = reElement->doubletZ();
230 m_doubletPhi = reElement->doubletPhi();
231 m_chamberDesign = reElement->chamberDesign();
232
233 m_numRpcLayers = reElement->nGasGaps();
234
235 m_numGasGapsPhi = reElement->nPhiPanels();
236 m_numPhiPanels = reElement->nPhiPanels();
237
239 m_numStripsEta = reElement->nEtaStrips();
240 m_numStripsPhi = reElement->nPhiStrips();
241
242 m_stripEtaPitch = reElement->stripEtaPitch();
243 m_stripPhiPitch = reElement->stripPhiPitch();
244 m_stripEtaWidth = reElement->stripEtaWidth();
245 m_stripPhiWidth = reElement->stripPhiWidth();
246 m_stripEtaLength = reElement->stripEtaLength();
247 m_stripPhiLength = reElement->stripPhiLength();
248
250 m_envelopeWidth = 2.*reElement->getParameters().halfWidth;
251 m_envelopeLength = 2.*reElement->getParameters().halfLength;
253 const Amg::Transform3D& transform{reElement->localToGlobalTrans(gctx)};
254 m_readoutTransform = transform;
255 m_alignableNode = reElement->alignableTransform()->getDefTransform();
256
257 const RpcIdHelper& id_helper{m_idHelperSvc->rpcIdHelper()};
258
259 for (unsigned gasGap = 1; gasGap <= reElement->nGasGaps(); ++gasGap) {
260 for (int doubPhi = reElement->doubletPhi(); doubPhi <= reElement->doubletPhiMax(); ++doubPhi) {
261 for (bool measPhi: {false, true}) {
262 unsigned numStrip = (measPhi ? reElement->nPhiStrips() :
263 reElement->nEtaStrips());
264 for (unsigned strip = 1; strip <= numStrip ; ++strip) {
265
266 bool isValid{false};
267 const Identifier stripID = id_helper.channelID(reElement->identify(),
268 reElement->doubletZ(),
269 doubPhi, gasGap, measPhi, strip, isValid);
270 if (!isValid) {
271 ATH_MSG_WARNING("Invalid Identifier detected for readout element "
272 <<m_idHelperSvc->toStringDetEl(reElement->identify())
273 <<" gap: "<<gasGap<<" strip: "<<strip<<" meas phi: "<<measPhi);
274 continue;
275 }
276 const IdentifierHash measHash = reElement->measurementHash(stripID);
277 const IdentifierHash layHash = reElement->layerHash(measHash);
278 const Amg::Vector3D stripPos = reElement->stripPosition(gctx, measHash);
279 m_stripPos.push_back(stripPos);
280 m_locStripPos.push_back((reElement->globalToLocalTrans(gctx, layHash) * stripPos).block<2,1>(0,0));
281 m_stripPosGasGap.push_back(gasGap);
282 m_stripPosMeasPhi.push_back(measPhi);
283 m_stripPosNum.push_back(strip);
284 m_stripDblPhi.push_back(doubPhi);
285
286 if (strip != 1) continue;
287 const Amg::Transform3D locToGlob = reElement->localToGlobalTrans(gctx, layHash)
288 * Amg::getRotateZ3D(90.*Gaudi::Units::deg * measPhi);
289 m_stripRot.push_back(locToGlob);
290 m_stripRotGasGap.push_back(gasGap);
291 m_stripRotMeasPhi.push_back(measPhi);
292 m_stripRotDblPhi.push_back(doubPhi);
293 }
294 }
295 }
296 }
297 return m_tree.fill(ctx) ? StatusCode::SUCCESS : StatusCode::FAILURE;
298}
299
300}
301
#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.
int stationEta() const
Returns the stationEta (positive A site, negative O site)
const Amg::Transform3D & localToGlobalTrans(const ActsTrk::GeometryContext &ctx) const
Returns the local to global transformation into the ATLAS coordinate system.
const std::string & chamberDesign() const
The chamber design refers to the construction parameters of a readout element.
Identifier identify() const override final
Return the athena 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
Returnsthe alignable transform of the readout element.
Amg::Transform3D globalToLocalTrans(const ActsTrk::GeometryContext &ctx) const
Transformations to translate between local <-> global coordinates.
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
double stripEtaWidth() const
Strip width in eta.
Identifier measurementId(const IdentifierHash &measHash) const override final
Converts the measurement hash back to the full Identifier.
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)
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.