ATLAS Offline Software
Loading...
Searching...
No Matches
runMdtGeoComparison.cxx
Go to the documentation of this file.
1
2/*
3 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
4*/
14#include "GeoModelHelpers/TransformToStringConverter.h"
17#include <GaudiKernel/SystemOfUnits.h>
18#include <iostream>
19
20
22#include <TFile.h>
23#include <TTreeReader.h>
24
25using namespace MuonGMR4;
26using namespace ActsTrk;
30 MdtChamber() = default;
31
35 std::string design{};
36
38 bool operator<(const MdtChamber& other) const {
39 return id < other.id;
40 }
41
43 Amg::Transform3D geoModelTransform{Amg::Transform3D::Identity()};
45 Amg::Transform3D alignableTransform{Amg::Transform3D::Identity()};
47 unsigned int numLayers{0};
49 unsigned int numTubes{0};
51 double tubePitch{0.};
53 double tubeRadius{0.};
54
55
58 unsigned int layerNum{0};
60 unsigned int tubeNum{0};
62 Amg::Transform3D localToGlobal{Amg::Transform3D::Identity()};
64 Amg::Vector3D readoutPos{Amg::Vector3D::Zero()};
66 double tubeLength{0.};
68 double wireLength{0.};
70 double activeLength{0.};
71 };
72 std::vector<TubePositioning> tubeInfo{};
75 const TubePositioning& getTube (unsigned int layer, unsigned int tube) const{
76 static const TubePositioning dummy{};
77 unsigned int idx = (layer -1)*numTubes + (tube -1);
78 return idx < tubeInfo.size() ? tubeInfo[idx] : dummy;
79 }
80 void insertTube(TubePositioning&& newTube) {
81 unsigned int idx = (newTube.layerNum - 1)*numTubes + (newTube.tubeNum -1);
82 if (tubeInfo.size() <= idx) tubeInfo.resize(idx+1);
83 tubeInfo[idx] = std::move(newTube);
84 }
85};
86
87
90std::ostream& operator<<(std::ostream& ostr, const MdtChamber& chamb) {
91 static const std::map<int, std::string> stationDict{
92 {0, "BIL"}, {1, "BIS"}, {7, "BIR"},
93 {2, "BML"}, {3, "BMS"}, {8, "BMF"}, {53, "BME"}, {54, "BMG"}, {52, "BIM"},
94 {4, "BOL"}, {5, "BOS"}, {9, "BOF"}, {10, "BOG"},
95 {6, "BEE"}, {14, "EEL"}, {15, "EES"},
96 {13, "EIL"}, {49, "EIS"},
97 {17, "EML"}, {18, "EMS"},
98 {20, "EOL"}, {21, "EOS"}
99 };
100 ostr<<stationDict.at(chamb.id.stationIndex)<<" "<<chamb.id<<" "<<chamb.design;
101 return ostr;
102}
103
104constexpr double tolerance = 10 * Gaudi::Units::micrometer;
105
106#define TEST_BASICPROP(attribute, propName) \
107 if (std::abs(1.*test.attribute - 1.*reference.attribute) > tolerance) { \
108 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": "<<test \
109 <<" differs w.r.t "<<propName<<" "<< reference.attribute \
110 <<" (ref) vs. " <<test.attribute << " (test)" << std::endl; \
111 chamberOkay = false; \
112 }
113
114#define TEST_TUBEPROP(attribute, propName) \
115 if (std::abs(1.*refTube.attribute - 1.*testTube.attribute) > tolerance) { \
116 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": In "<<test<<" the tubes (" \
117 <<layer<<","<<std::setfill('0')<<std::setw(3)<<tube<<")" \
118 <<" differ w.r.t "<<propName<<". " \
119 << refTube.attribute <<" (ref) vs. " <<testTube.attribute \
120 << " (test)" << std::endl; \
121 chamberOkay = false; \
122 }
123
124std::set<MdtChamber> readTreeDump(const std::string& inputFile) {
125 std::set<MdtChamber> to_ret{};
126 std::cout<<"Read the Mdt geometry tree dump from "<<inputFile<<std::endl;
127 std::unique_ptr<TFile> inFile{TFile::Open(inputFile.c_str())};
128 if (!inFile || !inFile->IsOpen()) {
129 std::cerr<<__FILE__<<":"<<__LINE__<<" Failed to open "<<inputFile<<std::endl;
130 return to_ret;
131 }
132 TTreeReader treeReader("MdtGeoModelTree", inFile.get());
133 if (treeReader.IsInvalid()){
134 std::cerr<<__FILE__<<":"<<__LINE__<<" The file "<<inputFile<<" does not contain the 'MdtGeoModelTree'"<<std::endl;
135 return to_ret;
136 }
137
138 TTreeReaderValue<unsigned short> stationIndex{treeReader, "stationIndex"};
139 TTreeReaderValue<short> stationEta{treeReader, "stationEta"};
140 TTreeReaderValue<short> stationPhi{treeReader, "stationPhi"};
141 TTreeReaderValue<short> stationML{treeReader, "stationMultiLayer"};
142 TTreeReaderValue<std::string> chamberDesign{treeReader,"chamberDesign"};
143
144 TTreeReaderValue<double> tubeRadius{treeReader, "tubeRadius"};
145 TTreeReaderValue<double> tubePitch{treeReader, "tubePitch"};
146 TTreeReaderValue<unsigned short> numTubes{treeReader, "numTubes"};
147 TTreeReaderValue<unsigned short> numLayers{treeReader, "numLayers"};
148
149 TTreeReaderValue<std::vector<float>> geoModelTransformX{treeReader, "GeoModelTransformX"};
150 TTreeReaderValue<std::vector<float>> geoModelTransformY{treeReader, "GeoModelTransformY"};
151 TTreeReaderValue<std::vector<float>> geoModelTransformZ{treeReader, "GeoModelTransformZ"};
152
153 TTreeReaderValue<std::vector<float>> alignableNodeX{treeReader, "AlignableNodeX"};
154 TTreeReaderValue<std::vector<float>> alignableNodeY{treeReader, "AlignableNodeY"};
155 TTreeReaderValue<std::vector<float>> alignableNodeZ{treeReader, "AlignableNodeZ"};
156
157
159 TTreeReaderValue<std::vector<unsigned short>> tubeLayer{treeReader, "tubeLayer"};
160 TTreeReaderValue<std::vector<unsigned short>> tubeNumber{treeReader, "tubeNumber"};
161
162 TTreeReaderValue<std::vector<double>> tubeLength{treeReader, "tubeLength"};
163 TTreeReaderValue<std::vector<double>> activeTubeLength{treeReader, "activeTubeLength"};
164 TTreeReaderValue<std::vector<double>> wireLength{treeReader, "wireLength"};
165
166 TTreeReaderValue<std::vector<float>> tubeTransformTransX{treeReader, "tubeTransformTranslationX"};
167 TTreeReaderValue<std::vector<float>> tubeTransformTransY{treeReader, "tubeTransformTranslationY"};
168 TTreeReaderValue<std::vector<float>> tubeTransformTransZ{treeReader, "tubeTransformTranslationZ"};
169
170 TTreeReaderValue<std::vector<float>> tubeTransformCol0X{treeReader, "tubeTransformLinearCol1X"};
171 TTreeReaderValue<std::vector<float>> tubeTransformCol0Y{treeReader, "tubeTransformLinearCol1Y"};
172 TTreeReaderValue<std::vector<float>> tubeTransformCol0Z{treeReader, "tubeTransformLinearCol1Z"};
173
174 TTreeReaderValue<std::vector<float>> tubeTransformCol1X{treeReader, "tubeTransformLinearCol2X"};
175 TTreeReaderValue<std::vector<float>> tubeTransformCol1Y{treeReader, "tubeTransformLinearCol2Y"};
176 TTreeReaderValue<std::vector<float>> tubeTransformCol1Z{treeReader, "tubeTransformLinearCol2Z"};
177
178 TTreeReaderValue<std::vector<float>> tubeTransformCol2X{treeReader, "tubeTransformLinearCol3X"};
179 TTreeReaderValue<std::vector<float>> tubeTransformCol2Y{treeReader, "tubeTransformLinearCol3Y"};
180 TTreeReaderValue<std::vector<float>> tubeTransformCol2Z{treeReader, "tubeTransformLinearCol3Z"};
181
182 TTreeReaderValue<std::vector<float>> readOutPosX{treeReader, "readOutPosX"};
183 TTreeReaderValue<std::vector<float>> readOutPosY{treeReader, "readOutPosY"};
184 TTreeReaderValue<std::vector<float>> readOutPosZ{treeReader, "readOutPosZ"};
185
186 while (treeReader.Next()) {
187 MdtChamber newchamber{};
188
189 newchamber.id.stationIndex = (*stationIndex);
190 newchamber.id.eta = (*stationEta);
191 newchamber.id.phi = (*stationPhi);
192 newchamber.id.multilayer = (*stationML);
193 newchamber.design = (*chamberDesign);
194
195 newchamber.tubeRadius = (*tubeRadius);
196 newchamber.tubePitch = (*tubePitch);
197
198 newchamber.numTubes = (*numTubes);
199 newchamber.numLayers = (*numLayers);
200
201 Amg::RotationMatrix3D geoRot{Amg::RotationMatrix3D::Identity()};
202 geoRot.col(0) = Amg::Vector3D((*geoModelTransformX)[1], (*geoModelTransformY)[1], (*geoModelTransformZ)[1]);
203 geoRot.col(1) = Amg::Vector3D((*geoModelTransformX)[2], (*geoModelTransformY)[2], (*geoModelTransformZ)[2]);
204 geoRot.col(2) = Amg::Vector3D((*geoModelTransformX)[3], (*geoModelTransformY)[3], (*geoModelTransformZ)[3]);
205 Amg::Vector3D geoTrans{(*geoModelTransformX)[0], (*geoModelTransformY)[0], (*geoModelTransformZ)[0]};
206 newchamber.geoModelTransform = Amg::getTransformFromRotTransl(std::move(geoRot), std::move(geoTrans));
207
208 geoRot.col(0) = Amg::Vector3D((*alignableNodeX)[1], (*alignableNodeY)[1], (*alignableNodeZ)[1]);
209 geoRot.col(1) = Amg::Vector3D((*alignableNodeX)[2], (*alignableNodeY)[2], (*alignableNodeZ)[2]);
210 geoRot.col(2) = Amg::Vector3D((*alignableNodeX)[3], (*alignableNodeY)[3], (*alignableNodeZ)[3]);
211 geoTrans = Amg::Vector3D{(*alignableNodeX)[0], (*alignableNodeY)[0], (*alignableNodeZ)[0]};
212 newchamber.alignableTransform = Amg::getTransformFromRotTransl(std::move(geoRot), std::move(geoTrans));
213
214
216 for (size_t t = 0; t < tubeLayer->size(); ++t){
217 using TubePositioning = MdtChamber::TubePositioning;
218 TubePositioning newTube{};
219 newTube.layerNum = (*tubeLayer)[t];
220 newTube.tubeNum = (*tubeNumber)[t];
221 newTube.tubeLength = (*tubeLength)[t];
222 newTube.wireLength = (*wireLength)[t];
223 Amg::RotationMatrix3D tubeRot{Amg::RotationMatrix3D::Identity()};
224 tubeRot.col(0) = Amg::Vector3D((*tubeTransformCol0X)[t],(*tubeTransformCol0Y)[t], (*tubeTransformCol0Z)[t]);
225 tubeRot.col(1) = Amg::Vector3D((*tubeTransformCol1X)[t],(*tubeTransformCol1Y)[t], (*tubeTransformCol1Z)[t]);
226 tubeRot.col(2) = Amg::Vector3D((*tubeTransformCol2X)[t],(*tubeTransformCol2Y)[t], (*tubeTransformCol2Z)[t]);
227 Amg::Vector3D tubeTrans{(*tubeTransformTransX)[t],(*tubeTransformTransY)[t], (*tubeTransformTransZ)[t]};
228 newTube.localToGlobal = Amg::getTransformFromRotTransl(std::move(tubeRot), std::move(tubeTrans));
229 newTube.readoutPos = Amg::Vector3D{(*readOutPosX)[t],(*readOutPosY)[t],(*readOutPosZ)[t]};
230 newchamber.insertTube(std::move(newTube));
231 }
232
233 auto insert_itr = to_ret.insert(std::move(newchamber));
234 if (!insert_itr.second) {
235 std::stringstream err{};
236 err<<__FILE__<<":"<<__LINE__<<" The chamber "<<(*insert_itr.first).id
237 <<" has already been inserted. "<<std::endl;
238 throw std::runtime_error(err.str());
239 }
240 }
241 std::cout<<"File parsing is finished. Found in total "<<to_ret.size()<<" readout element dumps "<<std::endl;
242 return to_ret;
243}
244
245int main( int argc, char** argv ) {
246 std::string refFile{}, testFile{};
247
248 for (int arg = 1; arg < argc; ++arg) {
249 std::string the_arg{argv[arg]};
250 if (the_arg == "--refFile" && arg +1 < argc) {
251 refFile = std::string{argv[arg+1]};
252 ++arg;
253 } else if (the_arg == "--testFile" && arg + 1 < argc) {
254 testFile = std::string{argv[arg+1]};
255 ++arg;
256 }
257 }
258 if (refFile.empty()) {
259 std::cerr<<"Please parse the path of the reference file via --refFile "<<std::endl;
260 return EXIT_FAILURE;
261 }
262 if (testFile.empty()) {
263 std::cerr<<"Please parse the path of the test file via --testFile "<<std::endl;
264 return EXIT_FAILURE;
265 }
267 if (!refFile.starts_with( "root://")) refFile = PathResolver::FindCalibFile(refFile);
268 if (!testFile.starts_with( "root://")) testFile = PathResolver::FindCalibFile(testFile);
270 std::set<MdtChamber> refChambers = readTreeDump(refFile);
271 if (refChambers.empty()) {
272 std::cerr<<"The file "<<refFile<<" should contain at least one chamber "<<std::endl;
273 return EXIT_FAILURE;
274 }
275 std::set<MdtChamber> testChambers = readTreeDump(testFile);
276 if (testChambers.empty()) {
277 std::cerr<<"The file "<<testFile<<" should contain at least one chamber "<<std::endl;
278 return EXIT_FAILURE;
279 }
280 int return_code = EXIT_SUCCESS;
281 unsigned int goodChamb{0};
283 for (const MdtChamber& reference : refChambers) {
284 std::set<MdtChamber>::const_iterator test_itr = testChambers.find(reference);
285
286 if (test_itr == testChambers.end()) {
287 std::cerr<<"The chamber "<<reference<<" is not part of the testing "<<std::endl;
288 return_code = EXIT_FAILURE;
289 continue;
290 }
291 bool chamberOkay = true;
292 const MdtChamber& test = {*test_itr};
294 TEST_BASICPROP(numLayers, "number of layers");
295 TEST_BASICPROP(numTubes, "number of tubes");
296 TEST_BASICPROP(tubePitch, "tube pitch");
297 TEST_BASICPROP(tubeRadius, "tube radius");
298
299 const Amg::Transform3D distortion = test.geoModelTransform.inverse() * reference.geoModelTransform;
302 bool flippedChamb = {reference.id.eta < 0 && Amg::doesNotDeform(distortion * Amg::getRotateX3D(M_PI))};
303 if (!Amg::doesNotDeform(distortion) && !flippedChamb) {
304 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": The chamber coordinate systems rotate differently for "
305 <<reference<<". Difference in the coordinate transformation: "<<Amg::toString(distortion)
306 <<" --- refTrf: "<<Amg::toString(reference.geoModelTransform)
307 <<" --- testTrf: "<<Amg::toString(test.geoModelTransform)<<std::endl;
308 chamberOkay = false;
309 }
312 if (distortion.translation().mag() > tolerance) {
313 std::cout<<"The origins of the chamber coordinate systems are not exactly at the same point for "
314 <<reference<<". Translation shift: "<<Amg::toString(distortion.translation(), 2)<<std::endl;
315 }
317 bool stagFailure{false}, alignFailure{false}, readoutOrient{false};
318 for (unsigned int layer = 1; layer<= std::min(reference.numLayers, test.numLayers) ; ++layer) {
319 for (unsigned int tube = 1; tube <= std::min(reference.numTubes, test.numTubes); ++tube) {
320 using TubePositioning = MdtChamber::TubePositioning;
321 const TubePositioning& refTube = reference.getTube(layer, tube);
322 const TubePositioning& testTube = test.getTube(layer, tube);
323 const Amg::Transform3D tubeDistortion = testTube.localToGlobal.inverse() * refTube.localToGlobal;
324 bool flippedTube{reference.id.eta < 0 && Amg::doesNotDeform(tubeDistortion * Amg::getRotateX3D(M_PI))};
325
326 if (!alignFailure && !(Amg::doesNotDeform(tubeDistortion) || flippedTube)) {
327 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": In chamber "<<reference<<" the tube reference systems for ("<<layer<<", "
328 <<std::setfill('0')<<std::setw(3)<<tube<<") are not exactly aligned. "<<GeoTrf::toString(tubeDistortion)<<std::endl;
329 alignFailure = true;
330 }
333 if (!stagFailure && tubeDistortion.translation().perp() > tolerance) {
334 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": Misplaced staggering found in "<<reference<<" the tube ("<<layer
335 <<", "<<std::setfill('0')<<std::setw(3)<<tube<<") "
336 << Amg::toString(tubeDistortion.translation(), 3)<<", mag: "<<tubeDistortion.translation().mag()<<
337 ", perp: "<<tubeDistortion.translation().perp()<<std::endl;
338 if (tube > 1) stagFailure = true;
339 }
340
341 // TEST_TUBEPROP(tubeLength, "tube length");
342 // TEST_TUBEPROP(wireLength, "wire length");
343 TEST_TUBEPROP(activeLength, "active length");
346 if (alignFailure || readoutOrient) continue;
347 const Amg::Transform3D refSystem = refTube.localToGlobal.inverse();
348
349 const Amg::Vector3D refRO = refSystem * refTube.readoutPos;
350 const Amg::Vector3D testRO = refSystem* testTube.readoutPos;
351 if (refRO.z()* testRO.z() < 0.){
352 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": The readout is on different sites for chamber: "<<reference<<
353 ", layer "<<layer<<", tube: "<<std::setfill('0')<<std::setw(3)<<tube<<". "
354 <<Amg::toString(refRO, 2)<<" vs. "<<Amg::toString(testRO)<<std::endl;
355 readoutOrient = true;
356 }
357 }
358 if (stagFailure || alignFailure) {
359 chamberOkay = false;
360 }
361 }
362 if (!chamberOkay) {
363 return_code = EXIT_FAILURE;
364 continue;
365 }
366 const Amg::Transform3D alignableDistort = test.alignableTransform.inverse()*(reference.alignableTransform );
367 if (!Amg::doesNotDeform(alignableDistort) || alignableDistort.translation().mag() > tolerance) {
368 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": The alignable nodes are at differnt places for "
369 <<test<<". " <<GeoTrf::toString(alignableDistort, true)<<" chamber length: "<<
370 (reference.tubePitch * (1.*reference.numTubes + 0.5))<<std::endl;
371 chamberOkay = false;
372
373 } else {
374 std::cout<<"runMdtGeoComparision() "<<__LINE__<<": Found perfect agreement between new & old geometry for "<<reference<<std::endl;
375 ++goodChamb;
376 }
377 }
378 for (const MdtChamber& test : testChambers) {
379 if (!refChambers.count(test)) {
380 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": "<<test<<" is only in the test set."<<std::endl;
381 return_code = EXIT_FAILURE;
382 }
383 }
384 std::cout<<"runMdtGeoComparision() "<<__LINE__<<": "<<goodChamb<<"/"<<refChambers.size()<<" chambers are in perfect agreement. "<<std::endl;
385
386 return return_code;
387
388}
389
390
#define M_PI
double tubeLength
static std::string FindCalibFile(const std::string &logical_file_name)
int main()
Definition hello.cxx:18
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Amg::Transform3D getRotateX3D(double angle)
get a rotation transformation around X-axis
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 3 > RotationMatrix3D
bool doesNotDeform(const Amg::Transform3D &trans)
Checks whether the linear part of the transformation rotates or stetches any of the basis vectors.
Amg::Transform3D getTransformFromRotTransl(Amg::RotationMatrix3D rot, Amg::Vector3D transl_vec)
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
#define TEST_TUBEPROP(attribute, propName)
#define TEST_BASICPROP(attribute, propName)
std::set< MdtChamber > readTreeDump(const std::string &inputFile)
std::ostream & operator<<(std::ostream &ostr, const MdtChamber &chamb)
Translation of the station Index -> station Name.
Split the offline part of the cabling apart to use it later for sorting.
int8_t & multilayer
Phi sector of the MDT station.
int8_t & eta
Station of the chamber (i.e, BIL,BIS,etc.)
int8_t & phi
Eta of the MDT station.
Amg::Vector3D readoutPos
Position of the readout frame in global coordinates.
unsigned int layerNum
Layer to which the tube belongs.
double activeLength
actiive tube length
Amg::Transform3D localToGlobal
local -> global transformation of the tube
unsigned int tubeNum
Number of the tube.
Helper struct to represent a full Mdt chamber.
MdtCablingOffData chamberIdentifier
Identifier of the mdt chamber.
Amg::Transform3D geoModelTransform
Transformation of the underlying GeoModel element.
bool operator<(const MdtChamber &other) const
Sorting operator to insert the object into std::set.
chamberIdentifier id
void insertTube(TubePositioning &&newTube)
std::vector< TubePositioning > tubeInfo
double tubePitch
Pitch between two tubes.
MdtChamber()=default
Default constructor.
unsigned int numLayers
Number of tube layers.
unsigned int numTubes
Number of tubes.
const TubePositioning & getTube(unsigned int layer, unsigned int tube) const
Returns the access to the full tube information Layer : (1 -nLayers), Tube : (1-nTubes)
Amg::Transform3D alignableTransform
Transformation of the underlying Alignable node.
double tubeRadius
Inner tube radius.