ATLAS Offline Software
Loading...
Searching...
No Matches
MuonDetDescr/MuonGeoModelTest/src/GeoModelTgcTest.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4#include "GeoModelTgcTest.h"
5
6#include <fstream>
7#include <iostream>
8
13#include "GaudiKernel/SystemOfUnits.h"
14
15
16namespace MuonGM {
17
18template<typename VType> bool isEqual(const std::vector<VType>& a,
19 const std::vector<VType>& b) {
20 if (a.size() != b.size()) {
21 return false;
22 }
23 for (size_t k =0 ; k < a.size() ; ++k) {
24 if ( std::abs(a[k] - b[k]) > std::numeric_limits<VType>::epsilon()){
25 return false;
26 }
27 }
28 return true;
29}
30template <typename VType> std::ostream& operator<<(std::ostream& ostr, const std::vector<VType>& v){
31 for (size_t k = 0 ; k <v.size(); ++k){
32 ostr<<v[k];
33 if ( k+1 != v.size())ostr<<",";
34 }
35 return ostr;
36}
37template <typename VType> std::ostream& operator<<(std::ostream& ostr, const std::set<VType>& s){
38 unsigned int k=1;
39 for (const VType& ele : s){
40 ostr<<ele;
41 if (k != s.size()) ostr<<";";
42 ++k;
43 }
44 return ostr;
45}
46inline int nStrips(const MuonGM::TgcReadoutElement& readoutEle, int layer) {
47 return readoutEle.nStrips(layer) > 1 ? readoutEle.nStrips(layer) : 0;
48}
49
50
53 std::string techType{};
54 std::vector<double> botStripPos{};
55 std::vector<double> topStripPos{};
56 std::vector<int> wireGangLayout{};
57 double wirePitch{0.};
58
59 bool operator==(const TgcChamberLayout& other) const{
60 return isEqual(botStripPos, other.botStripPos) &&
61 isEqual(topStripPos, other.topStripPos) &&
62 isEqual(wireGangLayout, other.wireGangLayout) &&
63 std::abs(wirePitch - other.wirePitch) < std::numeric_limits<float>::epsilon();
64 }
65};
66struct ChamberGrp {
68 m_lay{grp} {
69 m_gaps[grp.techType].insert(grp.gasGap);
70 }
71 bool addChamber(const TgcChamberLayout& lay){
72 if (m_lay == lay) {
73 m_gaps[lay.techType].insert(lay.gasGap);
74 return true;
75 }
76 return false;
77 }
78 const std::map<std::string, std::set<Identifier>>& allGaps() const{ return m_gaps; }
79 const TgcChamberLayout& layout() const { return m_lay; }
81 private:
83 std::map<std::string, std::set<Identifier>> m_gaps{};
84
85};
86
88 ATH_CHECK(m_tree.write());
89 return StatusCode::SUCCESS;
90}
92 ATH_CHECK(m_detMgrKey.initialize());
93 ATH_CHECK(m_idHelperSvc.retrieve());
94 ATH_CHECK(m_tree.init(this));
95 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
96 auto translateTokenList = [this, &idHelper](const std::vector<std::string>& chNames){
97
98 std::set<Identifier> transcriptedIds{};
99 for (const std::string& token : chNames) {
100 if (token.size() != 7) {
101 ATH_MSG_WARNING("Wrong format given for "<<token<<". Expecting 7 characters");
102 continue;
103 }
105 const std::string statName = token.substr(0, 3);
106 const unsigned statEta = std::atoi(token.substr(3, 1).c_str()) * (token[4] == 'A' ? 1 : -1);
107 const unsigned statPhi = std::atoi(token.substr(5, 2).c_str());
108 bool isValid{false};
109 const Identifier eleId = idHelper.elementID(statName, statEta, statPhi, isValid);
110 if (!isValid) {
111 ATH_MSG_WARNING("Failed to deduce a station name for " << token);
112 continue;
113 }
114 transcriptedIds.insert(eleId);
115 }
116 return transcriptedIds;
117 };
118
119 std::vector <std::string>& selectedSt = m_selectStat.value();
120 const std::vector <std::string>& excludedSt = m_excludeStat.value();
121 selectedSt.erase(std::remove_if(selectedSt.begin(), selectedSt.end(),
122 [&excludedSt](const std::string& token){
123 return std::ranges::find(excludedSt, token) != excludedSt.end();
124 }), selectedSt.end());
125
126 if (selectedSt.size()) {
127 m_testStations = translateTokenList(selectedSt);
128 std::stringstream sstr{};
129 for (const Identifier& id : m_testStations) {
130 sstr<<" *** "<<m_idHelperSvc->toString(id)<<std::endl;
131 }
132 ATH_MSG_INFO("Test only the following stations "<<std::endl<<sstr.str());
133 } else {
134 const std::set<Identifier> excluded = translateTokenList(excludedSt);
136 for(auto itr = idHelper.detectorElement_begin();
137 itr!= idHelper.detectorElement_end();++itr){
138 if (!excluded.count(*itr)) {
139 m_testStations.insert(*itr);
140 }
141 }
143 if (!excluded.empty()) {
144 std::stringstream excluded_report{};
145 for (const Identifier& id : excluded){
146 excluded_report << " *** " << m_idHelperSvc->toStringDetEl(id) << std::endl;
147 }
148 ATH_MSG_INFO("Test all station except the following excluded ones " << std::endl << excluded_report.str());
149 }
150 }
151 return StatusCode::SUCCESS;
152}
153StatusCode GeoModelTgcTest::execute(const EventContext& ctx) {
155 if (!detMgr.isValid()) {
156 ATH_MSG_FATAL("Failed to retrieve MuonDetectorManager "
157 << m_detMgrKey.fullKey());
158 return StatusCode::FAILURE;
159 }
160 dumpReadoutXML(**detMgr);
161 for (const Identifier& test_me : m_testStations) {
162 ATH_MSG_VERBOSE("Test retrieval of Mdt detector element "
163 << m_idHelperSvc->toStringDetEl(test_me));
164 const TgcReadoutElement* reElement = detMgr->getTgcReadoutElement(test_me);
165 if (!reElement) {
166 ATH_MSG_VERBOSE("Detector element is invalid");
167 continue;
168 }
170 if (reElement->identify() != test_me) {
171 ATH_MSG_FATAL("Expected to retrieve "
172 << m_idHelperSvc->toStringDetEl(test_me) << ". But got instead "
173 << m_idHelperSvc->toStringDetEl(reElement->identify()));
174 return StatusCode::FAILURE;
175 }
176
177 const Identifier prevId = reElement->getStationPhi() > 1 ? m_idHelperSvc->tgcIdHelper().elementID(m_idHelperSvc->stationNameString(test_me),
178 reElement->getStationEta(),
179 reElement->getStationPhi() - 1) : test_me;
180 const TgcReadoutElement* prevRE = detMgr->getTgcReadoutElement(prevId);
181 const Amg::Vector3D center = reElement->center();
182 ATH_MSG_DEBUG("Tgc element "<<m_idHelperSvc->toString(reElement->identify())
183 <<" position "<<Amg::toString(center, 2)
184 <<" perp: "<<center.perp()
185 <<" phi: "<<(center.phi() / Gaudi::Units::deg)
186 <<" theta: "<<(center.theta() / Gaudi::Units::deg)
187 <<" rSize: "<<reElement->getRsize()<<"/"<<reElement->getLongRsize()
188 <<" sSize: "<<reElement->getSsize()<<"/"<<reElement->getLongSsize()
189 <<" zSize: "<<reElement->getZsize()<<"/"<<reElement->getLongZsize()
190 <<" dPhi: "<<(prevRE->center().deltaPhi(center) / Gaudi::Units::deg));
191 ATH_CHECK(dumpToTree(ctx, reElement));
192 }
193 return StatusCode::SUCCESS;
194}
195StatusCode GeoModelTgcTest::dumpToTree(const EventContext& ctx, const TgcReadoutElement* readoutEle) {
196 m_stIndex = readoutEle->getStationIndex();
197 m_stEta = readoutEle->getStationEta();
198 m_stPhi = readoutEle->getStationPhi();
199 m_nGasGaps = readoutEle->nGasGaps();
200 ATH_MSG_DEBUG("Dump readout element "<<m_idHelperSvc->toString(readoutEle->identify()));
201
202 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
203
204 const Amg::Transform3D& trans{readoutEle->transform()};
205 m_readoutTransform = trans;
206 m_shortWidth = readoutEle->getSsize();
207 m_longWidth = readoutEle->getLongSsize();
208 m_height = readoutEle->length();
209
210 m_thickness = readoutEle->getZsize();
211 m_stLayout = readoutEle->getTechnologyName();
212
213 const MuonGM::MuonStation* station = readoutEle->parentMuonStation();
214 m_alignableNode = station->getGeoTransform()->getDefTransform() *
215 station->getNativeToAmdbLRS().inverse();
216
217 if (station->hasALines()){
218 m_ALineTransS = station->getALine_tras();
219 m_ALineTransT = station->getALine_traz();
220 m_ALineTransZ = station->getALine_trat();
221 m_ALineRotS = station->getALine_rots();
222 m_ALineRotT = station->getALine_rotz();
223 m_ALineRotZ = station->getALine_rott();
224 }
225
226 for (bool isStrip : {false, true}) {
227 for (int layer = 1 ; layer <= readoutEle->numberOfLayers(isStrip); ++layer){
228 const unsigned int nChan = isStrip ? nStrips(*readoutEle, layer) :
229 readoutEle->nWireGangs(layer);
230 if (!nChan) continue;
231 const Identifier layerId = idHelper.channelID(readoutEle->identify(),layer, isStrip, 1);
232 m_layTans.push_back(readoutEle->surface(layerId).transform());
233 m_layMeasPhi.push_back(isStrip);
234 m_layNumber.push_back(layer);
235 m_layHeight.push_back(readoutEle->length());
236 m_layShortWidth.push_back(readoutEle->getSsize() /*- readoutEle->frameXwidth() * 2. */);
237 m_layLongWidth.push_back(readoutEle->getLongSsize() /*- readoutEle->frameXwidth() * 2. */);
238 unsigned int numWires = !isStrip ? readoutEle->nWires(layer) : 0;
239 m_layNumWires.push_back(numWires);
240
241 if (isStrip) {
243 for (int strip = 1; strip <= nStrips(*readoutEle,layer); ++strip) {
244 bool is_valid{false};
245 const Identifier stripId = idHelper.channelID(readoutEle->identify(), layer, isStrip, strip, is_valid);
246 if (!is_valid) continue;
247
249 const Amg::Vector3D globStripPos = readoutEle->channelPos(stripId);
250 Amg::Vector2D locStripPos{Amg::Vector2D::Zero()};
251 const Trk::Surface& surf{readoutEle->surface(stripId)};
252 if (!surf.globalToLocal(globStripPos, Amg::Vector3D::Zero(), locStripPos)){
253 ATH_MSG_FATAL("Failed to build local strip position "<<m_idHelperSvc->toString(stripId));
254 return StatusCode::FAILURE;
255 }
256 m_locStripCenter.push_back(locStripPos);
257 m_stripCenter.push_back(globStripPos);
259 const double stripHalfLength = readoutEle->stripLength() / 2.;
260
261 const Amg::Vector2D locStripBot{readoutEle->stripPosOnShortBase(strip, layer), -stripHalfLength};
262 const Amg::Vector2D locStripTop{readoutEle->stripPosOnLargeBase(strip, layer), stripHalfLength};
263 const Amg::Vector3D globStripBot{surf.localToGlobal(locStripBot)};
264 const Amg::Vector3D globStripTop{surf.localToGlobal(locStripTop)};
265
266 m_stripBottom.push_back(globStripBot);
267 m_stripTop.push_back(globStripTop);
268
269 m_locStripBottom.push_back(locStripBot);
270 m_locStripTop.push_back(locStripTop);
271
272 m_stripGasGap.push_back(layer);
273 m_stripNum.push_back(strip);
274 m_stripLength.push_back(stripHalfLength * 2.);
275 m_stripPitch.push_back(readoutEle->stripPitch(layer,strip));
276 m_stripShortWidth.push_back(readoutEle->stripShortWidth(layer, strip));
277 m_stripLongWidth.push_back(readoutEle->stripLongWidth(layer, strip));
278 }
279 } else {
281 for (int gang = 1; gang <= readoutEle->nWireGangs(layer); ++gang) {
282 const Identifier gangId{idHelper.channelID(readoutEle->identify(), layer, isStrip, gang)};
283 const Trk::Surface& surf{readoutEle->surface(gangId)};
284 const Amg::Vector3D globPos{readoutEle->wireGangPos(layer, gang)};
285 Amg::Vector2D locPos{Amg::Vector2D::Zero()};
286 if (!surf.globalToLocal(globPos,Amg::Vector3D::Zero(),locPos)) {
287 ATH_MSG_FATAL("Failed to extract local position "<<m_idHelperSvc->toString(gangId));
288 return StatusCode::FAILURE;
289 }
290 m_locGangPos.push_back(locPos);
291 m_gangCenter.push_back(globPos);
292 m_gangGasGap.push_back(layer);
293 m_gangNum.push_back(gang);
294 m_gangNumWires.push_back(readoutEle->nWires(layer, gang));
295 m_gangLength.push_back(0.5 *(readoutEle->gangShortWidth(layer, gang) +
296 readoutEle->gangLongWidth(layer, gang) ));
297 }
298 }
299 }
300 }
301 return m_tree.fill(ctx) ? StatusCode::SUCCESS : StatusCode::FAILURE;
302}
303
305 if (m_readoutXML.empty()) {
306 return;
307 }
308 std::ofstream xmlStream{m_readoutXML};
309 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
310 std::map<Identifier, TgcChamberLayout> allLayouts{};
311 for (TgcIdHelper::const_id_iterator itr = idHelper.module_begin();
312 itr != idHelper.module_end(); ++itr) {
313 const MuonGM::TgcReadoutElement* reEle = detMgr.getTgcReadoutElement(*itr);
314 if (!reEle) continue;
315 for (bool isStrip : {false, true}) {
316 for (int layer = 1 ; layer <= reEle->numberOfLayers(isStrip); ++layer){
317 const Identifier layerId = idHelper.channelID(reEle->identify(), layer, isStrip, 1);
318 TgcChamberLayout& chambLayout = allLayouts[m_idHelperSvc->gasGapId(layerId)];
319 chambLayout.gasGap = m_idHelperSvc->gasGapId(layerId);
320 chambLayout.techType = reEle->getTechnologyName();
321 if (isStrip && nStrips(*reEle, layer)) {
322 const double halfHeight = 0.5 * (reEle->getRsize() - 2. * reEle->physicalDistanceFromBase());
323 const Amg::Transform3D globToLoc{reEle->surface(layerId).transform().inverse() * reEle->absTransform()};
324 const double sign = (reEle->getStationEta()> 0. ? -1. : 1.) *( (globToLoc*Amg::Vector3D::UnitY()).x() > 0 ? 1. : -1);
325
326 for (int strip = 1; strip < 33; ++strip) {
329 chambLayout.botStripPos.push_back(sign *reEle->stripLowEdgeLocX(layer,strip, -halfHeight));
330 chambLayout.topStripPos.push_back(sign *reEle->stripLowEdgeLocX(layer,strip, +halfHeight));
331 if (strip != 32) continue;
332 chambLayout.botStripPos.push_back(sign *reEle->stripHighEdgeLocX(layer,strip, -halfHeight));
333 chambLayout.topStripPos.push_back(sign *reEle->stripHighEdgeLocX(layer,strip, +halfHeight));
334 }
335 } else if (!isStrip) {
336 unsigned int accumlWires{0};
337 chambLayout.wirePitch = reEle->wirePitch();
343 for (int gang = 1; gang <= reEle->nWireGangs(layer); ++gang) {
344 unsigned int nWires = reEle->nWires(layer , gang);
345 accumlWires+=nWires;
346 if (nWires) {
347 chambLayout.wireGangLayout.push_back(nWires);
348 } else {
349 chambLayout.wireGangLayout.push_back(reEle->nWires(layer) - accumlWires);
350 break;
351 }
352 }
353 }
354 }
355 }
356 }
358 std::vector<ChamberGrp> groupedLayouts{};
359 for (const auto& lay : allLayouts) {
360 bool added{false};
361 for (ChamberGrp& grp : groupedLayouts) {
362 if (grp.addChamber(lay.second)){
363 added = true;
364 break;
365 }
366 }
367 if (!added) groupedLayouts.emplace_back(lay.second);
368 }
369 allLayouts.clear();
370 std::stable_sort(groupedLayouts.begin(),groupedLayouts.end(),
371 [](const ChamberGrp& a, const ChamberGrp& b){
372 return a.layout().techType < b.layout().techType;
373 });
375 ATH_MSG_INFO("Found in total "<<groupedLayouts.size()<<" different chamber layouts");
376 xmlStream<<"<Table name=\"TgcSensorLayout\">"<<std::endl;
377 unsigned int counter{1};
378 for (const ChamberGrp& grp : groupedLayouts) {
379 for (const auto& [tech_type, gapIds]: grp.allGaps()) {
380 std::set<int> gaps{};
381 std::set<char> sides{};
382 for (const Identifier gapId : gapIds) {
383 gaps.insert(m_idHelperSvc->gasGap(gapId));
384 sides.insert(m_idHelperSvc->stationEta(gapId) > 0 ? 'A' : 'C');
385 }
386 xmlStream<<" <Row ";
387 xmlStream<<"TGCSENSORLAYOUT_DATA_ID=\""<<counter<<"\" ";
388 xmlStream<<"technology=\""<<tech_type<<"\" ";
389 xmlStream<<"gasGap=\""<<gaps<<"\" ";
390 xmlStream<<"side=\""<<sides<<"\" ";
391 xmlStream<<"wirePitch=\""<<grp.layout().wirePitch<<"\" ";
392 xmlStream<<"wireGangs=\""<<grp.layout().wireGangLayout<<"\" ";
393 xmlStream<<"bottomStrips=\""<<grp.layout().botStripPos<<"\" ";
394 xmlStream<<"topStrips=\""<<grp.layout().topStripPos<<"\" ";
395 xmlStream<<" />"<<std::endl;
396 ++counter;
397 }
398 }
399 xmlStream<<"</Table> "<<std::endl;
400}
401
402
403}
#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)
static Double_t a
int sign(int a)
StatusCode execute(const EventContext &ctx) override
Execute method.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
void dumpReadoutXML(const MuonGM::MuonDetectorManager &detMgr)
MuonVal::ScalarBranch< unsigned short > & m_stIndex
Identifier of the readout element.
MuonVal::VectorBranch< unsigned int > & m_stripNum
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_detMgrKey
MuonDetectorManager from the conditions store.
MuonVal::ScalarBranch< std::string > & m_stLayout
Gaudi::Property< std::vector< std::string > > m_excludeStat
MuonVal::VectorBranch< unsigned int > & m_gangNum
MuonVal::CoordTransformBranch m_readoutTransform
Transformation of the readout element (Translation, ColX, ColY, ColZ).
MuonVal::ScalarBranch< float > & m_ALineTransS
Alignment parameters.
std::set< Identifier > m_testStations
Set of stations to be tested.
MuonVal::MuonTesterTree m_tree
Write a TTree for validation purposes.
StatusCode dumpToTree(const EventContext &ctx, const TgcReadoutElement *readoutEle)
Gaudi::Property< std::vector< std::string > > m_selectStat
String should be formated like <stationName><stationEta><A/C><stationPhi>.
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
virtual const Amg::Vector3D & center() const override
Return the center of the element.
virtual const Amg::Transform3D & transform() const override
Return local to global transform.
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const TgcReadoutElement * getTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
Identifier identify() const override final
Returns the ATLAS Identifier of the MuonReadOutElement.
double getALine_trat() const
const Amg::Transform3D & getNativeToAmdbLRS() const
double getALine_rott() const
double getALine_rots() const
const GeoAlignableTransform * getGeoTransform() const
bool hasALines() const
double getALine_tras() const
double getALine_rotz() const
double getALine_traz() const
A TgcReadoutElement corresponds to a single TGC chamber; therefore typically a TGC station contains s...
int nWireGangs(int gasGap) const
Returns the number of wire gangs (Random grouping of wires) in a given gas gap.
Amg::Vector3D channelPos(const Identifier &id) const
Returns the position of the active channel (wireGang or strip).
double stripLength() const
Returns the length of each strip which is equal to the height of the chamber.
double stripHighEdgeLocX(int gasGap, int strip, double radialPos) const
Returns the local X of the right edge of the strip at a given local radial position.
double stripPitch(int gasGap, int strip) const
Returns the pitch of the given strip in gasGap i.
double stripPosOnShortBase(int strip, int gasGap) const
double gangShortWidth(int gasGap, int gang) const
Returns the length of the most bottom wire in the gang.
double stripPosOnLargeBase(int strip, int gasGap) const
virtual int numberOfLayers(bool isStrip) const override
number of layers in phi/eta projection
double stripLowEdgeLocX(int gasGap, int strip, double radialPos) const
Returns the local X of the left edge of the strip at a given local radial position.
double gangLongWidth(int gasGap, int gang) const
Returns the length of the most top wire in the gang.
int nGasGaps() const
Returns the number of gas gaps associated with the readout element (2 or 3).
int nWires(int gasGap) const
Returns the total number of wires in a given gas gap.
double physicalDistanceFromBase() const
int nStrips(int gasGap) const
Returns the number of strips in a given gas gap.
Amg::Vector3D wireGangPos(const Identifier &id) const
Returns the global position of a wireGang.
double wirePitch() const
Returns the pitch of the wires.
std::vector< Identifier >::const_iterator const_id_iterator
const_id_iterator module_end() const
const_id_iterator module_begin() const
Iterators over full set of ids.
const_id_iterator detectorElement_begin() const
Iterators over full set of ids.
const_id_iterator detectorElement_end() const
Identifier elementID(int stationName, int stationEta, int stationPhi) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int gasGap, int isStrip, int channel) const
Abstract Base Class for tracking surfaces.
Definition Surface.h:79
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const =0
Specified by each surface type: LocalToGlobal method without dynamic memory allocation.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27
int nStrips(const MuonGM::TgcReadoutElement &readoutEle, int layer)
bool isEqual(const std::vector< VType > &a, const std::vector< VType > &b)
std::ostream & operator<<(std::ostream &os, const AlignPos &p)
Definition AlignPos.cxx:8
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
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.
const std::map< std::string, std::set< Identifier > > & allGaps() const
std::map< std::string, std::set< Identifier > > m_gaps
bool operator==(const TgcChamberLayout &other) const