ATLAS Offline Software
Loading...
Searching...
No Matches
runMdtGeoComparison.cxx
Go to the documentation of this file.
1
2/*
3 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
4*/
14#include "GeoModelHelpers/TransformToStringConverter.h"
17#include <GaudiKernel/SystemOfUnits.h>
18#include <iostream>
19
20#include "Acts/Utilities/UnitVectors.hpp"
21#include "Acts/Definitions/Units.hpp"
22
24#include <TFile.h>
25#include <TTreeReader.h>
26
27using namespace MuonGMR4;
28using namespace ActsTrk;
29
30Amg::Vector3D makeDir(const double theta, const double phi) {
31 using namespace Acts::UnitLiterals;
32 return Acts::makeDirectionFromPhiTheta(phi *1._degree, theta* 1._degree);
33}
34
37 MdtChamber() = default;
38
42 std::string design{};
43
45 bool operator<(const MdtChamber& other) const {
46 return id < other.id;
47 }
48
50 Amg::Transform3D geoModelTransform{Amg::Transform3D::Identity()};
52 Amg::Transform3D alignableTransform{Amg::Transform3D::Identity()};
54 unsigned int numLayers{0};
56 unsigned int numTubes{0};
58 double tubePitch{0.};
60 double tubeRadius{0.};
61
62
65 unsigned int layerNum{0};
67 unsigned int tubeNum{0};
69 Amg::Transform3D localToGlobal{Amg::Transform3D::Identity()};
71 Amg::Vector3D readoutPos{Amg::Vector3D::Zero()};
73 double tubeLength{0.};
75 double wireLength{0.};
77 double activeLength{0.};
78 };
79 std::vector<TubePositioning> tubeInfo{};
82 const TubePositioning& getTube (unsigned int layer, unsigned int tube) const{
83 static const TubePositioning dummy{};
84 unsigned int idx = (layer -1)*numTubes + (tube -1);
85 return idx < tubeInfo.size() ? tubeInfo[idx] : dummy;
86 }
87 void insertTube(TubePositioning&& newTube) {
88 unsigned int idx = (newTube.layerNum - 1)*numTubes + (newTube.tubeNum -1);
89 if (tubeInfo.size() <= idx) tubeInfo.resize(idx+1);
90 tubeInfo[idx] = std::move(newTube);
91 }
92};
93
94
97std::ostream& operator<<(std::ostream& ostr, const MdtChamber& chamb) {
98 static const std::map<int, std::string> stationDict{
99 {0, "BIL"}, {1, "BIS"}, {7, "BIR"},
100 {2, "BML"}, {3, "BMS"}, {8, "BMF"}, {53, "BME"}, {54, "BMG"}, {52, "BIM"},
101 {4, "BOL"}, {5, "BOS"}, {9, "BOF"}, {10, "BOG"},
102 {6, "BEE"}, {14, "EEL"}, {15, "EES"},
103 {13, "EIL"}, {49, "EIS"},
104 {17, "EML"}, {18, "EMS"},
105 {20, "EOL"}, {21, "EOS"}
106 };
107 ostr<<stationDict.at(chamb.id.stationIndex)<<" "<<chamb.id<<" "<<chamb.design;
108 return ostr;
109}
110
111constexpr double tolerance = 10 * Gaudi::Units::micrometer;
112
113#define TEST_BASICPROP(attribute, propName) \
114 if (std::abs(1.*test.attribute - 1.*reference.attribute) > tolerance) { \
115 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": "<<test \
116 <<" differs w.r.t "<<propName<<" "<< reference.attribute \
117 <<" (ref) vs. " <<test.attribute << " (test)" << std::endl; \
118 chamberOkay = false; \
119 }
120
121#define TEST_TUBEPROP(attribute, propName) \
122 if (std::abs(1.*refTube.attribute - 1.*testTube.attribute) > tolerance) { \
123 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": In "<<test<<" the tubes (" \
124 <<layer<<","<<std::setfill('0')<<std::setw(3)<<tube<<")" \
125 <<" differ w.r.t "<<propName<<". " \
126 << refTube.attribute <<" (ref) vs. " <<testTube.attribute \
127 << " (test)" << std::endl; \
128 chamberOkay = false; \
129 }
130
131std::set<MdtChamber> readTreeDump(const std::string& inputFile) {
132 std::set<MdtChamber> to_ret{};
133 std::cout<<"Read the Mdt geometry tree dump from "<<inputFile<<std::endl;
134 std::unique_ptr<TFile> inFile{TFile::Open(inputFile.c_str())};
135 if (!inFile || !inFile->IsOpen()) {
136 std::cerr<<__FILE__<<":"<<__LINE__<<" Failed to open "<<inputFile<<std::endl;
137 return to_ret;
138 }
139 TTreeReader treeReader("MdtGeoModelTree", inFile.get());
140 if (treeReader.IsInvalid()){
141 std::cerr<<__FILE__<<":"<<__LINE__<<" The file "<<inputFile<<" does not contain the 'MdtGeoModelTree'"<<std::endl;
142 return to_ret;
143 }
144
145 TTreeReaderValue<unsigned short> stationIndex{treeReader, "stationIndex"};
146 TTreeReaderValue<short> stationEta{treeReader, "stationEta"};
147 TTreeReaderValue<short> stationPhi{treeReader, "stationPhi"};
148 TTreeReaderValue<short> stationML{treeReader, "stationMultiLayer"};
149 TTreeReaderValue<std::string> chamberDesign{treeReader,"chamberDesign"};
150
151 TTreeReaderValue<double> tubeRadius{treeReader, "tubeRadius"};
152 TTreeReaderValue<double> tubePitch{treeReader, "tubePitch"};
153 TTreeReaderValue<unsigned short> numTubes{treeReader, "numTubes"};
154 TTreeReaderValue<unsigned short> numLayers{treeReader, "numLayers"};
155
156 TTreeReaderValue<std::vector<float>> geoModelTransformX{treeReader, "GeoModelTransformX"};
157 TTreeReaderValue<std::vector<float>> geoModelTransformY{treeReader, "GeoModelTransformY"};
158 TTreeReaderValue<std::vector<float>> geoModelTransformZ{treeReader, "GeoModelTransformZ"};
159
160 TTreeReaderValue<std::vector<float>> alignableNodeX{treeReader, "AlignableNodeX"};
161 TTreeReaderValue<std::vector<float>> alignableNodeY{treeReader, "AlignableNodeY"};
162 TTreeReaderValue<std::vector<float>> alignableNodeZ{treeReader, "AlignableNodeZ"};
163
164
166 TTreeReaderValue<std::vector<unsigned short>> tubeLayer{treeReader, "tubeLayer"};
167 TTreeReaderValue<std::vector<unsigned short>> tubeNumber{treeReader, "tubeNumber"};
168
169 TTreeReaderValue<std::vector<double>> tubeLength{treeReader, "tubeLength"};
170 TTreeReaderValue<std::vector<double>> activeTubeLength{treeReader, "activeTubeLength"};
171 TTreeReaderValue<std::vector<double>> wireLength{treeReader, "wireLength"};
172
173 TTreeReaderValue<std::vector<float>> tubeTransformTransX{treeReader, "tubeTransformTranslationX"};
174 TTreeReaderValue<std::vector<float>> tubeTransformTransY{treeReader, "tubeTransformTranslationY"};
175 TTreeReaderValue<std::vector<float>> tubeTransformTransZ{treeReader, "tubeTransformTranslationZ"};
176
177 TTreeReaderValue<std::vector<float>> tubeTransformCol0Theta{treeReader, "tubeTransformLinearCol0Theta"};
178 TTreeReaderValue<std::vector<float>> tubeTransformCol0Phi{treeReader, "tubeTransformLinearCol0Phi"};
179
180 TTreeReaderValue<std::vector<float>> tubeTransformCol1Theta{treeReader, "tubeTransformLinearCol1Theta"};
181 TTreeReaderValue<std::vector<float>> tubeTransformCol1Phi{treeReader, "tubeTransformLinearCol1Phi"};
182
183 TTreeReaderValue<std::vector<float>> tubeTransformCol2Theta{treeReader, "tubeTransformLinearCol2Theta"};
184 TTreeReaderValue<std::vector<float>> tubeTransformCol2Phi{treeReader, "tubeTransformLinearCol2Phi"};
185
186 TTreeReaderValue<std::vector<float>> readOutPosX{treeReader, "readOutPosX"};
187 TTreeReaderValue<std::vector<float>> readOutPosY{treeReader, "readOutPosY"};
188 TTreeReaderValue<std::vector<float>> readOutPosZ{treeReader, "readOutPosZ"};
189
190 while (treeReader.Next()) {
191 MdtChamber newchamber{};
192
193 newchamber.id.stationIndex = (*stationIndex);
194 newchamber.id.eta = (*stationEta);
195 newchamber.id.phi = (*stationPhi);
196 newchamber.id.multilayer = (*stationML);
197 newchamber.design = (*chamberDesign);
198
199 newchamber.tubeRadius = (*tubeRadius);
200 newchamber.tubePitch = (*tubePitch);
201
202 newchamber.numTubes = (*numTubes);
203 newchamber.numLayers = (*numLayers);
204
205 Amg::RotationMatrix3D geoRot{Amg::RotationMatrix3D::Identity()};
206 geoRot.col(0) = Amg::Vector3D((*geoModelTransformX)[1], (*geoModelTransformY)[1], (*geoModelTransformZ)[1]);
207 geoRot.col(1) = Amg::Vector3D((*geoModelTransformX)[2], (*geoModelTransformY)[2], (*geoModelTransformZ)[2]);
208 geoRot.col(2) = Amg::Vector3D((*geoModelTransformX)[3], (*geoModelTransformY)[3], (*geoModelTransformZ)[3]);
209 Amg::Vector3D geoTrans{(*geoModelTransformX)[0], (*geoModelTransformY)[0], (*geoModelTransformZ)[0]};
210 newchamber.geoModelTransform = Amg::getTransformFromRotTransl(std::move(geoRot), std::move(geoTrans));
211
212 geoRot.col(0) = Amg::Vector3D((*alignableNodeX)[1], (*alignableNodeY)[1], (*alignableNodeZ)[1]);
213 geoRot.col(1) = Amg::Vector3D((*alignableNodeX)[2], (*alignableNodeY)[2], (*alignableNodeZ)[2]);
214 geoRot.col(2) = Amg::Vector3D((*alignableNodeX)[3], (*alignableNodeY)[3], (*alignableNodeZ)[3]);
215 geoTrans = Amg::Vector3D{(*alignableNodeX)[0], (*alignableNodeY)[0], (*alignableNodeZ)[0]};
216 newchamber.alignableTransform = Amg::getTransformFromRotTransl(std::move(geoRot), std::move(geoTrans));
217
218
220 for (size_t t = 0; t < tubeLayer->size(); ++t){
221 using TubePositioning = MdtChamber::TubePositioning;
222 TubePositioning newTube{};
223 newTube.layerNum = (*tubeLayer)[t];
224 newTube.tubeNum = (*tubeNumber)[t];
225 newTube.tubeLength = (*tubeLength)[t];
226 newTube.wireLength = (*wireLength)[t];
227 Amg::RotationMatrix3D tubeRot{Amg::RotationMatrix3D::Identity()};
228 tubeRot.col(0) = makeDir((*tubeTransformCol0Theta)[t], (*tubeTransformCol0Phi)[t]);
229 tubeRot.col(1) = makeDir((*tubeTransformCol1Theta)[t], (*tubeTransformCol1Phi)[t]);
230 tubeRot.col(2) = makeDir((*tubeTransformCol2Theta)[t], (*tubeTransformCol2Phi)[t]);
231 Amg::Vector3D tubeTrans{(*tubeTransformTransX)[t],(*tubeTransformTransY)[t], (*tubeTransformTransZ)[t]};
232 newTube.localToGlobal = Amg::getTransformFromRotTransl(std::move(tubeRot), std::move(tubeTrans));
233 newTube.readoutPos = Amg::Vector3D{(*readOutPosX)[t],(*readOutPosY)[t],(*readOutPosZ)[t]};
234 newchamber.insertTube(std::move(newTube));
235 }
236
237 auto insert_itr = to_ret.insert(std::move(newchamber));
238 if (!insert_itr.second) {
239 std::stringstream err{};
240 err<<__FILE__<<":"<<__LINE__<<" The chamber "<<(*insert_itr.first).id
241 <<" has already been inserted. "<<std::endl;
242 throw std::runtime_error(err.str());
243 }
244 }
245 std::cout<<"File parsing is finished. Found in total "<<to_ret.size()<<" readout element dumps "<<std::endl;
246 return to_ret;
247}
248
249int main1( int argc, char** argv ) {
250 std::string refFile{}, testFile{};
251
252 for (int arg = 1; arg < argc; ++arg) {
253 std::string the_arg{argv[arg]};
254 if (the_arg == "--refFile" && arg +1 < argc) {
255 refFile = std::string{argv[arg+1]};
256 ++arg;
257 } else if (the_arg == "--testFile" && arg + 1 < argc) {
258 testFile = std::string{argv[arg+1]};
259 ++arg;
260 }
261 }
262 if (refFile.empty()) {
263 std::cerr<<"Please parse the path of the reference file via --refFile "<<std::endl;
264 return EXIT_FAILURE;
265 }
266 if (testFile.empty()) {
267 std::cerr<<"Please parse the path of the test file via --testFile "<<std::endl;
268 return EXIT_FAILURE;
269 }
271 if (!refFile.starts_with( "root://")) refFile = PathResolver::FindCalibFile(refFile);
272 if (!testFile.starts_with( "root://")) testFile = PathResolver::FindCalibFile(testFile);
274 std::set<MdtChamber> refChambers = readTreeDump(refFile);
275 if (refChambers.empty()) {
276 std::cerr<<"The file "<<refFile<<" should contain at least one chamber "<<std::endl;
277 return EXIT_FAILURE;
278 }
279 std::set<MdtChamber> testChambers = readTreeDump(testFile);
280 if (testChambers.empty()) {
281 std::cerr<<"The file "<<testFile<<" should contain at least one chamber "<<std::endl;
282 return EXIT_FAILURE;
283 }
284 int return_code = EXIT_SUCCESS;
285 unsigned int goodChamb{0};
287 for (const MdtChamber& reference : refChambers) {
288 std::set<MdtChamber>::const_iterator test_itr = testChambers.find(reference);
289
290 if (test_itr == testChambers.end()) {
291 std::cerr<<"The chamber "<<reference<<" is not part of the testing "<<std::endl;
292 return_code = EXIT_FAILURE;
293 continue;
294 }
295 bool chamberOkay = true;
296 const MdtChamber& test = {*test_itr};
298 TEST_BASICPROP(numLayers, "number of layers");
299 TEST_BASICPROP(numTubes, "number of tubes");
300 TEST_BASICPROP(tubePitch, "tube pitch");
301 TEST_BASICPROP(tubeRadius, "tube radius");
302
303 const Amg::Transform3D distortion = test.geoModelTransform.inverse() * reference.geoModelTransform;
306 bool flippedChamb = {reference.id.eta < 0 && Amg::doesNotDeform(distortion * Amg::getRotateX3D(M_PI))};
307 if (!Amg::doesNotDeform(distortion) && !flippedChamb) {
308 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": The chamber coordinate systems rotate differently for "
309 <<reference<<". Difference in the coordinate transformation: "<<Amg::toString(distortion)
310 <<" --- refTrf: "<<Amg::toString(reference.geoModelTransform)
311 <<" --- testTrf: "<<Amg::toString(test.geoModelTransform)<<std::endl;
312 chamberOkay = false;
313 }
316 if (distortion.translation().mag() > tolerance) {
317 std::cout<<"The origins of the chamber coordinate systems are not exactly at the same point for "
318 <<reference<<". Translation shift: "<<Amg::toString(distortion.translation(), 2)<<std::endl;
319 }
321 bool stagFailure{false}, alignFailure{false}, readoutOrient{false};
322 for (unsigned int layer = 1; layer<= std::min(reference.numLayers, test.numLayers) ; ++layer) {
323 for (unsigned int tube = 1; tube <= std::min(reference.numTubes, test.numTubes); ++tube) {
324 using TubePositioning = MdtChamber::TubePositioning;
325 const TubePositioning& refTube = reference.getTube(layer, tube);
326 const TubePositioning& testTube = test.getTube(layer, tube);
327 const Amg::Transform3D tubeDistortion = testTube.localToGlobal.inverse() * refTube.localToGlobal;
328 bool flippedTube{reference.id.eta < 0 && Amg::doesNotDeform(tubeDistortion * Amg::getRotateX3D(M_PI))};
329
330 if (!alignFailure && !(Amg::doesNotDeform(tubeDistortion) || flippedTube)) {
331 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": In chamber "<<reference<<" the tube reference systems for ("<<layer<<", "
332 <<std::setfill('0')<<std::setw(3)<<tube<<") are not exactly aligned. "<<GeoTrf::toString(tubeDistortion)<<std::endl;
333 alignFailure = true;
334 }
337 if (!stagFailure && tubeDistortion.translation().perp() > tolerance) {
338 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": Misplaced staggering found in "<<reference<<" the tube ("<<layer
339 <<", "<<std::setfill('0')<<std::setw(3)<<tube<<") "
340 << Amg::toString(tubeDistortion.translation(), 3)<<", mag: "<<tubeDistortion.translation().mag()<<
341 ", perp: "<<tubeDistortion.translation().perp()<<std::endl;
342 if (tube > 1) stagFailure = true;
343 }
344
345 // TEST_TUBEPROP(tubeLength, "tube length");
346 // TEST_TUBEPROP(wireLength, "wire length");
347 TEST_TUBEPROP(activeLength, "active length");
350 if (alignFailure || readoutOrient) continue;
351 const Amg::Transform3D refSystem = refTube.localToGlobal.inverse();
352
353 const Amg::Vector3D refRO = refSystem * refTube.readoutPos;
354 const Amg::Vector3D testRO = refSystem* testTube.readoutPos;
355 if (refRO.z()* testRO.z() < 0.){
356 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": The readout is on different sites for chamber: "<<reference<<
357 ", layer "<<layer<<", tube: "<<std::setfill('0')<<std::setw(3)<<tube<<". "
358 <<Amg::toString(refRO, 2)<<" vs. "<<Amg::toString(testRO)<<std::endl;
359 readoutOrient = true;
360 }
361 }
362 if (stagFailure || alignFailure) {
363 chamberOkay = false;
364 }
365 }
366 if (!chamberOkay) {
367 return_code = EXIT_FAILURE;
368 continue;
369 }
370 const Amg::Transform3D alignableDistort = test.alignableTransform.inverse()*(reference.alignableTransform );
371 if (!Amg::doesNotDeform(alignableDistort) || alignableDistort.translation().mag() > tolerance) {
372 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": The alignable nodes are at differnt places for "
373 <<test<<". " <<GeoTrf::toString(alignableDistort, true)<<" chamber length: "<<
374 (reference.tubePitch * (1.*reference.numTubes + 0.5))<<std::endl;
375 chamberOkay = false;
376
377 } else {
378 std::cout<<"runMdtGeoComparision() "<<__LINE__<<": Found perfect agreement between new & old geometry for "<<reference<<std::endl;
379 ++goodChamb;
380 }
381 }
382 for (const MdtChamber& test : testChambers) {
383 if (!refChambers.count(test)) {
384 std::cerr<<"runMdtGeoComparision() "<<__LINE__<<": "<<test<<" is only in the test set."<<std::endl;
385 return_code = EXIT_FAILURE;
386 }
387 }
388 std::cout<<"runMdtGeoComparision() "<<__LINE__<<": "<<goodChamb<<"/"<<refChambers.size()<<" chambers are in perfect agreement. "<<std::endl;
389
390 return return_code;
391
392}
393
394
395int main (int argc, char** argv )
396{
397 int ret = 1;
398 try {
399 ret = main1 (argc, argv);
400 }
401 catch (const std::exception& e) {
402 std::cerr << e.what() << "\n";
403 }
404 return ret;
405}
406
#define M_PI
Scalar phi() const
phi method
Scalar theta() const
theta method
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)
Amg::Vector3D makeDir(const double theta, const double phi)
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.
int main1()
Definition testRead.cxx:68