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}
154 const EventContext& ctx{Gaudi::Hive::currentContext()};
156 if (!detMgr.isValid()) {
157 ATH_MSG_FATAL("Failed to retrieve MuonDetectorManager "
158 << m_detMgrKey.fullKey());
159 return StatusCode::FAILURE;
160 }
161 dumpReadoutXML(**detMgr);
162 for (const Identifier& test_me : m_testStations) {
163 ATH_MSG_VERBOSE("Test retrieval of Mdt detector element "
164 << m_idHelperSvc->toStringDetEl(test_me));
165 const TgcReadoutElement* reElement = detMgr->getTgcReadoutElement(test_me);
166 if (!reElement) {
167 ATH_MSG_VERBOSE("Detector element is invalid");
168 continue;
169 }
171 if (reElement->identify() != test_me) {
172 ATH_MSG_FATAL("Expected to retrieve "
173 << m_idHelperSvc->toStringDetEl(test_me) << ". But got instead "
174 << m_idHelperSvc->toStringDetEl(reElement->identify()));
175 return StatusCode::FAILURE;
176 }
177
178 const Identifier prevId = reElement->getStationPhi() > 1 ? m_idHelperSvc->tgcIdHelper().elementID(m_idHelperSvc->stationNameString(test_me),
179 reElement->getStationEta(),
180 reElement->getStationPhi() - 1) : test_me;
181 const TgcReadoutElement* prevRE = detMgr->getTgcReadoutElement(prevId);
182 const Amg::Vector3D center = reElement->center();
183 ATH_MSG_DEBUG("Tgc element "<<m_idHelperSvc->toString(reElement->identify())
184 <<" position "<<Amg::toString(center, 2)
185 <<" perp: "<<center.perp()
186 <<" phi: "<<(center.phi() / Gaudi::Units::deg)
187 <<" theta: "<<(center.theta() / Gaudi::Units::deg)
188 <<" rSize: "<<reElement->getRsize()<<"/"<<reElement->getLongRsize()
189 <<" sSize: "<<reElement->getSsize()<<"/"<<reElement->getLongSsize()
190 <<" zSize: "<<reElement->getZsize()<<"/"<<reElement->getLongZsize()
191 <<" dPhi: "<<(prevRE->center().deltaPhi(center) / Gaudi::Units::deg));
192 ATH_CHECK(dumpToTree(ctx, reElement));
193 }
194 return StatusCode::SUCCESS;
195}
196StatusCode GeoModelTgcTest::dumpToTree(const EventContext& ctx, const TgcReadoutElement* readoutEle) {
197 m_stIndex = readoutEle->getStationIndex();
198 m_stEta = readoutEle->getStationEta();
199 m_stPhi = readoutEle->getStationPhi();
200 m_nGasGaps = readoutEle->nGasGaps();
201 ATH_MSG_DEBUG("Dump readout element "<<m_idHelperSvc->toString(readoutEle->identify()));
202
203 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
204
205 const Amg::Transform3D& trans{readoutEle->transform()};
206 m_readoutTransform = trans;
207 m_shortWidth = readoutEle->getSsize();
208 m_longWidth = readoutEle->getLongSsize();
209 m_height = readoutEle->length();
210
211 m_thickness = readoutEle->getZsize();
212 m_stLayout = readoutEle->getTechnologyName();
213
214 const MuonGM::MuonStation* station = readoutEle->parentMuonStation();
215 m_alignableNode = station->getGeoTransform()->getDefTransform() *
216 station->getNativeToAmdbLRS().inverse();
217
218 if (station->hasALines()){
219 m_ALineTransS = station->getALine_tras();
220 m_ALineTransT = station->getALine_traz();
221 m_ALineTransZ = station->getALine_trat();
222 m_ALineRotS = station->getALine_rots();
223 m_ALineRotT = station->getALine_rotz();
224 m_ALineRotZ = station->getALine_rott();
225 }
226
227 for (bool isStrip : {false, true}) {
228 for (int layer = 1 ; layer <= readoutEle->numberOfLayers(isStrip); ++layer){
229 const unsigned int nChan = isStrip ? nStrips(*readoutEle, layer) :
230 readoutEle->nWireGangs(layer);
231 if (!nChan) continue;
232 const Identifier layerId = idHelper.channelID(readoutEle->identify(),layer, isStrip, 1);
233 m_layTans.push_back(readoutEle->surface(layerId).transform());
234 m_layMeasPhi.push_back(isStrip);
235 m_layNumber.push_back(layer);
236 m_layHeight.push_back(readoutEle->length());
237 m_layShortWidth.push_back(readoutEle->getSsize() /*- readoutEle->frameXwidth() * 2. */);
238 m_layLongWidth.push_back(readoutEle->getLongSsize() /*- readoutEle->frameXwidth() * 2. */);
239 unsigned int numWires = !isStrip ? readoutEle->nWires(layer) : 0;
240 m_layNumWires.push_back(numWires);
241
242 if (isStrip) {
244 for (int strip = 1; strip <= nStrips(*readoutEle,layer); ++strip) {
245 bool is_valid{false};
246 const Identifier stripId = idHelper.channelID(readoutEle->identify(), layer, isStrip, strip, is_valid);
247 if (!is_valid) continue;
248
250 const Amg::Vector3D globStripPos = readoutEle->channelPos(stripId);
251 Amg::Vector2D locStripPos{Amg::Vector2D::Zero()};
252 const Trk::Surface& surf{readoutEle->surface(stripId)};
253 if (!surf.globalToLocal(globStripPos, Amg::Vector3D::Zero(), locStripPos)){
254 ATH_MSG_FATAL("Failed to build local strip position "<<m_idHelperSvc->toString(stripId));
255 return StatusCode::FAILURE;
256 }
257 m_locStripCenter.push_back(locStripPos);
258 m_stripCenter.push_back(globStripPos);
260 const double stripHalfLength = readoutEle->stripLength() / 2.;
261
262 const Amg::Vector2D locStripBot{readoutEle->stripPosOnShortBase(strip, layer), -stripHalfLength};
263 const Amg::Vector2D locStripTop{readoutEle->stripPosOnLargeBase(strip, layer), stripHalfLength};
264 const Amg::Vector3D globStripBot{surf.localToGlobal(locStripBot)};
265 const Amg::Vector3D globStripTop{surf.localToGlobal(locStripTop)};
266
267 m_stripBottom.push_back(globStripBot);
268 m_stripTop.push_back(globStripTop);
269
270 m_locStripBottom.push_back(locStripBot);
271 m_locStripTop.push_back(locStripTop);
272
273 m_stripGasGap.push_back(layer);
274 m_stripNum.push_back(strip);
275 m_stripLength.push_back(stripHalfLength * 2.);
276 m_stripPitch.push_back(readoutEle->stripPitch(layer,strip));
277 m_stripShortWidth.push_back(readoutEle->stripShortWidth(layer, strip));
278 m_stripLongWidth.push_back(readoutEle->stripLongWidth(layer, strip));
279 }
280 } else {
282 for (int gang = 1; gang <= readoutEle->nWireGangs(layer); ++gang) {
283 const Identifier gangId{idHelper.channelID(readoutEle->identify(), layer, isStrip, gang)};
284 const Trk::Surface& surf{readoutEle->surface(gangId)};
285 const Amg::Vector3D globPos{readoutEle->wireGangPos(layer, gang)};
286 Amg::Vector2D locPos{Amg::Vector2D::Zero()};
287 if (!surf.globalToLocal(globPos,Amg::Vector3D::Zero(),locPos)) {
288 ATH_MSG_FATAL("Failed to extract local position "<<m_idHelperSvc->toString(gangId));
289 return StatusCode::FAILURE;
290 }
291 m_locGangPos.push_back(locPos);
292 m_gangCenter.push_back(globPos);
293 m_gangGasGap.push_back(layer);
294 m_gangNum.push_back(gang);
295 m_gangNumWires.push_back(readoutEle->nWires(layer, gang));
296 m_gangLength.push_back(0.5 *(readoutEle->gangShortWidth(layer, gang) +
297 readoutEle->gangLongWidth(layer, gang) ));
298 }
299 }
300 }
301 }
302 return m_tree.fill(ctx) ? StatusCode::SUCCESS : StatusCode::FAILURE;
303}
304
306 if (m_readoutXML.empty()) {
307 return;
308 }
309 std::ofstream xmlStream{m_readoutXML};
310 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
311 std::map<Identifier, TgcChamberLayout> allLayouts{};
312 for (TgcIdHelper::const_id_iterator itr = idHelper.module_begin();
313 itr != idHelper.module_end(); ++itr) {
314 const MuonGM::TgcReadoutElement* reEle = detMgr.getTgcReadoutElement(*itr);
315 if (!reEle) continue;
316 for (bool isStrip : {false, true}) {
317 for (int layer = 1 ; layer <= reEle->numberOfLayers(isStrip); ++layer){
318 const Identifier layerId = idHelper.channelID(reEle->identify(), layer, isStrip, 1);
319 TgcChamberLayout& chambLayout = allLayouts[m_idHelperSvc->gasGapId(layerId)];
320 chambLayout.gasGap = m_idHelperSvc->gasGapId(layerId);
321 chambLayout.techType = reEle->getTechnologyName();
322 if (isStrip && nStrips(*reEle, layer)) {
323 const double halfHeight = 0.5 * (reEle->getRsize() - 2. * reEle->physicalDistanceFromBase());
324 const Amg::Transform3D globToLoc{reEle->surface(layerId).transform().inverse() * reEle->absTransform()};
325 const double sign = (reEle->getStationEta()> 0. ? -1. : 1.) *( (globToLoc*Amg::Vector3D::UnitY()).x() > 0 ? 1. : -1);
326
327 for (int strip = 1; strip < 33; ++strip) {
330 chambLayout.botStripPos.push_back(sign *reEle->stripLowEdgeLocX(layer,strip, -halfHeight));
331 chambLayout.topStripPos.push_back(sign *reEle->stripLowEdgeLocX(layer,strip, +halfHeight));
332 if (strip != 32) continue;
333 chambLayout.botStripPos.push_back(sign *reEle->stripHighEdgeLocX(layer,strip, -halfHeight));
334 chambLayout.topStripPos.push_back(sign *reEle->stripHighEdgeLocX(layer,strip, +halfHeight));
335 }
336 } else if (!isStrip) {
337 unsigned int accumlWires{0};
338 chambLayout.wirePitch = reEle->wirePitch();
344 for (int gang = 1; gang <= reEle->nWireGangs(layer); ++gang) {
345 unsigned int nWires = reEle->nWires(layer , gang);
346 accumlWires+=nWires;
347 if (nWires) {
348 chambLayout.wireGangLayout.push_back(nWires);
349 } else {
350 chambLayout.wireGangLayout.push_back(reEle->nWires(layer) - accumlWires);
351 break;
352 }
353 }
354 }
355 }
356 }
357 }
359 std::vector<ChamberGrp> groupedLayouts{};
360 for (const auto& lay : allLayouts) {
361 bool added{false};
362 for (ChamberGrp& grp : groupedLayouts) {
363 if (grp.addChamber(lay.second)){
364 added = true;
365 break;
366 }
367 }
368 if (!added) groupedLayouts.emplace_back(lay.second);
369 }
370 allLayouts.clear();
371 std::stable_sort(groupedLayouts.begin(),groupedLayouts.end(),
372 [](const ChamberGrp& a, const ChamberGrp& b){
373 return a.layout().techType < b.layout().techType;
374 });
376 ATH_MSG_INFO("Found in total "<<groupedLayouts.size()<<" different chamber layouts");
377 xmlStream<<"<Table name=\"TgcSensorLayout\">"<<std::endl;
378 unsigned int counter{1};
379 for (const ChamberGrp& grp : groupedLayouts) {
380 for (const auto& [tech_type, gapIds]: grp.allGaps()) {
381 std::set<int> gaps{};
382 std::set<char> sides{};
383 for (const Identifier gapId : gapIds) {
384 gaps.insert(m_idHelperSvc->gasGap(gapId));
385 sides.insert(m_idHelperSvc->stationEta(gapId) > 0 ? 'A' : 'C');
386 }
387 xmlStream<<" <Row ";
388 xmlStream<<"TGCSENSORLAYOUT_DATA_ID=\""<<counter<<"\" ";
389 xmlStream<<"technology=\""<<tech_type<<"\" ";
390 xmlStream<<"gasGap=\""<<gaps<<"\" ";
391 xmlStream<<"side=\""<<sides<<"\" ";
392 xmlStream<<"wirePitch=\""<<grp.layout().wirePitch<<"\" ";
393 xmlStream<<"wireGangs=\""<<grp.layout().wireGangLayout<<"\" ";
394 xmlStream<<"bottomStrips=\""<<grp.layout().botStripPos<<"\" ";
395 xmlStream<<"topStrips=\""<<grp.layout().topStripPos<<"\" ";
396 xmlStream<<" />"<<std::endl;
397 ++counter;
398 }
399 }
400 xmlStream<<"</Table> "<<std::endl;
401}
402
403
404}
#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
static Double_t a
int sign(int a)
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.
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