Project
Loading...
Searching...
No Matches
AlignmentSpec.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
18
19#include <cmath>
20#include <string>
21#include <tuple>
22#include <vector>
23#include <chrono>
24#include <iostream>
25#include <filesystem>
26#include <sstream>
27
28#include <TCanvas.h>
29#include <TChain.h>
30#include <TDatabasePDG.h>
31#include <TF1.h>
32#include <TFile.h>
33#include <TGraph.h>
34#include <TGraphErrors.h>
35#include <TGeoMatrix.h>
36#include <TH1F.h>
37#include <TH2F.h>
38#include <TLegend.h>
39#include <TLine.h>
40#include <TMatrixD.h>
41#include <TSystem.h>
42#include <TTree.h>
43#include <TTreeReader.h>
44#include <TTreeReaderValue.h>
45
52#include "Framework/Lifetime.h"
53#include "Framework/Output.h"
54#include "Framework/Task.h"
55#include "Framework/Logger.h"
56
71#include "MathUtils/Cartesian.h"
72#include "MCHAlign/Aligner.h"
74#include "MCHTracking/Track.h"
80
81namespace o2
82{
83namespace mch
84{
85
86using namespace std;
87using namespace o2::framework;
88using namespace o2;
89
91{
92 public:
93 const int fgNDetElemCh[10] = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26};
94 const int fgSNDetElemCh[11] = {0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156};
95 const int fgNDetElemHalfCh[20] = {2, 2, 2, 2, 2, 2, 2, 2, 9,
96 9, 9, 9, 13, 13, 13, 13, 13, 13, 13, 13};
97 const int fgSNDetElemHalfCh[21] = {0, 3, 6, 9, 12, 15, 18, 21, 24, 34, 44, 54, 64,
98 78, 92, 106, 120, 134, 148, 162, 176};
99 const int fgDetElemHalfCh[20][13] =
100 {
101 {100, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
102 {101, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
103
104 {200, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
105 {201, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
106
107 {300, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
108 {301, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
109
110 {400, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
111 {401, 402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
112
113 {500, 501, 502, 503, 504, 514, 515, 516, 517, 0, 0, 0, 0},
114 {505, 506, 507, 508, 509, 510, 511, 512, 513, 0, 0, 0, 0},
115
116 {600, 601, 602, 603, 604, 614, 615, 616, 617, 0, 0, 0, 0},
117 {605, 606, 607, 608, 609, 610, 611, 612, 613, 0, 0, 0, 0},
118
119 {700, 701, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725},
120 {707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719},
121
122 {800, 801, 802, 803, 804, 805, 806, 820, 821, 822, 823, 824, 825},
123 {807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819},
124
125 {900, 901, 902, 903, 904, 905, 906, 920, 921, 922, 923, 924, 925},
126 {907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919},
127
128 {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1020, 1021, 1022, 1023, 1024, 1025},
129 {1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019}
130
131 };
132 std::vector<double> params;
133 std::vector<double> errors;
134 std::vector<double> pulls;
135
136 constexpr double pi() { return 3.14159265358979323846; }
137
138 //_________________________________________________________________________________________________
139 AlignmentTask(shared_ptr<base::GRPGeomRequest> req) : mCCDBRequest(req) {}
140
141 //_________________________________________________________________________________________________
143 {
144
145 LOG(info) << "Initializing aligner";
146 // Initialize alignment algorithm
147
148 int numberOfGlobalParam = 624;
149 double default_value = 0;
150 params = std::vector<double>(numberOfGlobalParam, default_value);
151 errors = std::vector<double>(numberOfGlobalParam, default_value);
152 pulls = std::vector<double>(numberOfGlobalParam, default_value);
153
154 doAlign = ic.options().get<bool>("do-align");
155 if (doAlign) {
156 LOG(info) << "Alignment mode";
157 } else {
158 LOG(info) << "No alignment mode, only residuals will be stored";
159 }
160
161 doReAlign = ic.options().get<bool>("do-realign");
162
163 if (mCCDBRequest) {
164 LOG(info) << "Loading magnetic field and reference geometry from CCDB";
166 } else {
167
168 LOG(info) << "Loading magnetic field and reference geometry from input files";
169
170 auto grpFile = ic.options().get<string>("grp-file");
171 if (std::filesystem::exists(grpFile)) {
172 const auto grp = parameters::GRPObject::loadFrom(grpFile);
177 } else {
178 LOG(fatal) << "No GRP file";
179 }
180
181 IdealGeoFileName = ic.options().get<string>("geo-file-ideal");
182 if (std::filesystem::exists(IdealGeoFileName)) {
183 base::GeometryManager::loadGeometry(IdealGeoFileName.c_str());
184 transformation = geo::transformationFromTGeoManager(*gGeoManager);
185 for (int i = 0; i < 156; i++) {
186 int iDEN = GetDetElemId(i);
187 transformIdeal[iDEN] = transformation(iDEN);
188 }
189 } else {
190 LOG(fatal) << "No ideal geometry";
191 }
192
193 RefGeoFileName = ic.options().get<string>("geo-file-ref");
194 if (std::filesystem::exists(RefGeoFileName)) {
195 base::GeometryManager::loadGeometry(RefGeoFileName.c_str());
196 transformation = geo::transformationFromTGeoManager(*gGeoManager);
197 for (int i = 0; i < 156; i++) {
198 int iDEN = GetDetElemId(i);
199 transformRef[iDEN] = transformation(iDEN);
200 }
201 } else {
202 LOG(fatal) << "No reference geometry";
203 }
204
205 if (doReAlign) {
206 LOG(info) << "Re-alignment mode";
207 LOG(info) << "Loading re-alignment geometry";
208 NewGeoFileName = ic.options().get<string>("geo-file-new");
209 if (std::filesystem::exists(NewGeoFileName)) {
210 base::GeometryManager::loadGeometry(NewGeoFileName.c_str());
211 transformation = geo::transformationFromTGeoManager(*gGeoManager);
212 for (int i = 0; i < 156; i++) {
213 int iDEN = GetDetElemId(i);
214 transformNew[iDEN] = transformation(iDEN);
215 }
216 } else {
217 LOG(fatal) << "No re-alignment geometry";
218 }
219 }
220 }
221
222 auto doEvaluation = ic.options().get<bool>("do-evaluation");
223 mAlign.SetDoEvaluation(doEvaluation);
224
225 // Variation range for parameters
226 auto AllowX = ic.options().get<float>("variation-x");
227 auto AllowY = ic.options().get<float>("variation-y");
228 auto AllowPhi = ic.options().get<float>("variation-phi");
229 auto AllowZ = ic.options().get<float>("variation-z");
230 mAlign.SetAllowedVariation(0, AllowX);
231 mAlign.SetAllowedVariation(1, AllowY);
232 mAlign.SetAllowedVariation(2, AllowPhi);
233 mAlign.SetAllowedVariation(3, AllowZ);
234
235 // Sigma XY
236 auto SigmaX = ic.options().get<float>("sigma-x");
237 auto SigmaY = ic.options().get<float>("sigma-y");
238 mAlign.SetSigmaXY(SigmaX, SigmaY);
239
240 // Configuration for track fitter
241 const auto& trackerParam = TrackerParam::Instance();
242 trackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion);
243 trackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY);
244 trackFitter.smoothTracks(true);
245 trackFitter.useChamberResolution();
246 mImproveCutChi2 = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement;
247
248 // Fix chambers
249 TString chambersString = ic.options().get<string>("fix-chamber");
250 std::unique_ptr<TObjArray> objArray(chambersString.Tokenize(","));
251 if (objArray->GetEntries() > 0) {
252 for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) {
253 LOG(info) << Form("%s%d", "Fixing chamber: ", std::stoi(objArray->At(iVar)->GetName()));
254 mAlign.FixChamber(std::stoi(objArray->At(iVar)->GetName()));
255 }
256 }
257
258 // Fix DEs
259 TString DEString = ic.options().get<string>("fix-de");
260 TString MaskDEString = ic.options().get<string>("mask-fix-de");
261 std::unique_ptr<TObjArray> objArrayDE(DEString.Tokenize(","));
262 std::unique_ptr<TObjArray> objArrayMask(MaskDEString.Tokenize(","));
263 if (objArrayDE->GetEntries() > 0) {
264 if (objArrayDE->GetEntries() != objArrayMask->GetEntries()) {
265 LOG(fatal) << "Inconsistent size of DEs and Masks!";
266 }
267 for (int iVar = 0; iVar < objArrayDE->GetEntries(); ++iVar) {
268 LOG(info) << Form("%s%d%s%d", "Fixing DE: ", std::stoi(objArrayDE->At(iVar)->GetName()), " with mask: ", std::stoi(objArrayMask->At(iVar)->GetName()));
269 mAlign.FixDetElem(std::stoi(objArrayDE->At(iVar)->GetName()), std::stoi(objArrayMask->At(iVar)->GetName()));
270 }
271 }
272
273 doMatched = ic.options().get<bool>("matched");
274 outFileName = ic.options().get<string>("output");
275 readFromRec = ic.options().get<bool>("use-record");
276
277 if (readFromRec) {
278 mAlign.SetReadOnly();
279 LOG(info) << "Reading records as input";
280 }
281 mAlign.init();
282
283 ic.services().get<CallbackService>().set<CallbackService::Id::Stop>([this]() {
284 LOG(info) << "Alignment duration = " << mElapsedTime.count() << " s";
285 });
286 }
287
288 //_________________________________________________________________________________________________
290 {
292 if (mCCDBRequest && base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
293
294 if (matcher == framework::ConcreteDataMatcher("GLO", "GRPMAGFIELD", 0)) {
298 }
299
300 if (matcher == framework::ConcreteDataMatcher("GLO", "GEOMALIGN", 0)) {
301 LOG(info) << "Loading reference geometry from CCDB";
302 transformation = geo::transformationFromTGeoManager(*gGeoManager);
303 for (int i = 0; i < 156; i++) {
304 int iDEN = GetDetElemId(i);
305 transformRef[iDEN] = transformation(iDEN);
306 }
307 }
308 }
309 }
310
311 //_________________________________________________________________________________________________
312 void processWithMatching(vector<ROFRecord>& mchROFs, vector<TrackMCH>& mchTracks, vector<Cluster>& mchClusters,
313 vector<dataformats::TrackMCHMID>& muonTracks)
314 {
315 // processing for each track
316 for (const auto& mchROF : mchROFs) {
317
318 for (int iMCHTrack = mchROF.getFirstIdx();
319 iMCHTrack <= mchROF.getLastIdx(); ++iMCHTrack) {
320 // MCH-MID matching
321 if (!FindMuon(iMCHTrack, muonTracks)) {
322 continue;
323 }
324
325 auto mchTrack = mchTracks.at(iMCHTrack);
326 int id_track = iMCHTrack;
327 int nb_clusters = mchTrack.getNClusters();
328
329 // Track selection, considering only tracks having at least 10 clusters
330 if (nb_clusters <= 9) {
331 continue;
332 }
333
334 // Format conversion from TrackMCH to Track(MCH internal use)
335 mch::Track convertedTrack = MCHFormatConvert(mchTrack, mchClusters, doReAlign);
336
337 // Erase removable track
338 if (RemoveTrack(convertedTrack)) {
339 continue;
340 }
341
342 // Track processing, saving residuals
343 mAlign.ProcessTrack(convertedTrack, transformation, doAlign, weightRecord);
344 }
345 }
346 }
347
348 //_________________________________________________________________________________________________
349 void processWithOutMatching(vector<ROFRecord>& mchROFs, vector<TrackMCH>& mchTracks, vector<Cluster>& mchClusters)
350 {
351
352 // processing for each track
353 for (const auto& mchROF : mchROFs) {
354
355 for (int iMCHTrack = mchROF.getFirstIdx();
356 iMCHTrack <= mchROF.getLastIdx(); ++iMCHTrack) {
357
358 auto mchTrack = mchTracks.at(iMCHTrack);
359 int id_track = iMCHTrack;
360 int nb_clusters = mchTrack.getNClusters();
361
362 // Track selection, saving only tracks having exactly 10 clusters
363 if (nb_clusters <= 9) {
364 continue;
365 }
366
367 // Format conversion from TrackMCH to Track(MCH internal use)
368 Track convertedTrack = MCHFormatConvert(mchTrack, mchClusters, doReAlign);
369
370 // Erase removable track
371 if (RemoveTrack(convertedTrack)) {
372 continue;
373 }
374
375 // Track processing, saving residuals
376 mAlign.ProcessTrack(convertedTrack, transformation, doAlign, weightRecord);
377 }
378 }
379 }
380
381 //_________________________________________________________________________________________________
383 {
384 auto tStart = std::chrono::high_resolution_clock::now();
385 LOG(info) << "Starting alignment process";
386 if (doMatched) {
387 LOG(info) << "Using MCH-MID matched tracks";
388 }
389 if (mCCDBRequest) {
390
391 LOG(info) << "Checking CCDB updates with processing context";
393
394 auto geoIdeal = pc.inputs().get<TGeoManager*>("geomIdeal");
395 LOG(info) << "Loading ideal geometry from CCDB";
396 transformation = geo::transformationFromTGeoManager(*geoIdeal);
397 for (int i = 0; i < 156; i++) {
398 int iDEN = GetDetElemId(i);
399 transformIdeal[iDEN] = transformation(iDEN);
400 }
401 }
402
403 if (!readFromRec) {
404 // Loading input data
405 LOG(info) << "Loading MCH tracks";
406 auto [fMCH, mchReader] = LoadData(mchFileName, "o2sim");
407 TTreeReaderValue<vector<ROFRecord>> mchROFs = {*mchReader, "trackrofs"};
408 TTreeReaderValue<vector<TrackMCH>> mchTracks = {*mchReader, "tracks"};
409 TTreeReaderValue<vector<Cluster>> mchClusters = {*mchReader, "trackclusters"};
410
411 if (doMatched) {
412 LOG(info) << "Loading MID tracks";
413 auto [fMUON, muonReader] = LoadData(muonFileName.c_str(), "o2sim");
414 TTreeReaderValue<vector<dataformats::TrackMCHMID>> muonTracks = {*muonReader, "tracks"};
415 int nTF = muonReader->GetEntries(false);
416 if (mchReader->GetEntries(false) != nTF) {
417 LOG(error) << mchFileName << " and " << muonFileName << " do not contain the same number of TF";
418 exit(-1);
419 }
420
421 LOG(info) << "Starting track processing";
422 while (mchReader->Next() && muonReader->Next()) {
423 int id_event = mchReader->GetCurrentEntry();
424 processWithMatching(*mchROFs, *mchTracks, *mchClusters, *muonTracks);
425 }
426 } else {
427 LOG(info) << "Starting track processing";
428 while (mchReader->Next()) {
429 int id_event = mchReader->GetCurrentEntry();
430 processWithOutMatching(*mchROFs, *mchTracks, *mchClusters);
431 }
432 }
433 }
434
435 // Global fit
436 if (doAlign) {
437 mAlign.GlobalFit(params, errors, pulls);
438 }
439 auto tEnd = std::chrono::high_resolution_clock::now();
440 mElapsedTime = tEnd - tStart;
441
442 // Generate new geometry w.r.t alignment results
443 if (doAlign) {
444
445 LOG(info) << "Generating aligned geometry using global parameters";
446 vector<detectors::AlignParam> ParamAligned;
447 mAlign.ReAlign(ParamAligned, params);
448
449 TFile* FileAlign = TFile::Open("AlignParam.root", "RECREATE");
450 FileAlign->cd();
451 FileAlign->WriteObjectAny(&ParamAligned, "std::vector<o2::detectors::AlignParam>", "alignment");
452 FileAlign->Close();
453
454 string Geo_file;
455
456 if (doReAlign) {
457 Geo_file = Form("%s%s", "o2sim_geometry_ReAlign", ".root");
458 } else {
459 Geo_file = Form("%s%s", "o2sim_geometry_Align", ".root");
460 }
461
462 // Store aligned geometry
463 gGeoManager->Export(Geo_file.c_str());
464
465 // Store param plots
466 drawHisto(params, errors, pulls, outFileName);
467
468 // Export align params in ideal frame
469 TransRef(ParamAligned);
470 }
471
472 mAlign.terminate();
473
474 pc.services().get<ControlService>().endOfStream();
475 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
476 }
477
478 private:
479 //_________________________________________________________________________________________________
480 void TransRef(vector<detectors::AlignParam>& ParamsTrack)
481 {
482 LOG(info) << "Transforming align params to the frame of ideal geometry";
483 vector<o2::detectors::AlignParam> ParamsRef;
485
486 for (int hc = 0; hc < 20; hc++) {
487
488 ParamsRef.emplace_back(ParamsTrack.at(fgSNDetElemHalfCh[hc]));
489
490 for (int de = 0; de < fgNDetElemHalfCh[hc]; de++) {
491
492 int iDEN = fgDetElemHalfCh[hc][de];
493 o2::detectors::AlignParam param_Track = ParamsTrack.at(fgSNDetElemHalfCh[hc] + 1 + de);
494
495 LOG(debug) << Form("%s%s", "Processing DET Elem: ", (param_Track.getSymName()).c_str());
496
497 TGeoHMatrix delta_track;
498 TGeoRotation r("Rotation/Track", param_Track.getPsi() / pi() * 180.0, param_Track.getTheta() / pi() * 180.0, param_Track.getPhi() / pi() * 180.0);
499 delta_track.SetRotation(r.GetRotationMatrix());
500 delta_track.SetDx(param_Track.getX());
501 delta_track.SetDy(param_Track.getY());
502 delta_track.SetDz(param_Track.getZ());
503
504 TGeoHMatrix transRef = transformIdeal[iDEN];
505 TGeoHMatrix transTrack = doReAlign ? transformNew[iDEN] : transformRef[iDEN];
506 TGeoHMatrix transRefTrack = transTrack * transRef.Inverse();
507 TGeoHMatrix delta_ref = delta_track * transRefTrack;
508
509 param_Ref.setSymName((param_Track.getSymName()).c_str());
510 param_Ref.setGlobalParams(delta_ref);
511 param_Ref.applyToGeometry();
512 ParamsRef.emplace_back(param_Ref);
513 }
514 }
515
516 TFile* fOut = TFile::Open("AlignParam@ideal.root", "RECREATE");
517 fOut->WriteObjectAny(&ParamsRef, "std::vector<o2::detectors::AlignParam>", "alignment");
518 fOut->Close();
519 }
520
521 //_________________________________________________________________________________________________
522 Track MCHFormatConvert(TrackMCH& mchTrack, vector<Cluster>& mchClusters, bool doReAlign)
523 {
524
525 Track convertedTrack = Track();
526
527 // Get clusters for current track
528 int id_cluster_first = mchTrack.getFirstClusterIdx();
529 int id_cluster_last = mchTrack.getLastClusterIdx();
530
531 for (int id_cluster = id_cluster_first;
532 id_cluster < id_cluster_last + 1; ++id_cluster) {
533
534 Cluster* cluster = &(mchClusters.at(id_cluster));
535 const int DEId_cluster = cluster->getDEId();
536 const int CId_cluster = cluster->getChamberId();
537 const int ind_cluster = cluster->getClusterIndex();
538
539 // Transformations to new geometry from reference geometry
540 if (doReAlign) {
541
544
545 master.SetXYZ(cluster->getX(), cluster->getY(), cluster->getZ());
546
547 transformRef[cluster->getDEId()].MasterToLocal(master, local);
548 transformNew[cluster->getDEId()].LocalToMaster(local, master);
549
550 cluster->x = master.x();
551 cluster->y = master.y();
552 cluster->z = master.z();
553 }
554 convertedTrack.createParamAtCluster(*cluster);
555 }
556
557 return Track(convertedTrack);
558 }
559
560 //_________________________________________________________________________________________________
561 bool RemoveTrack(Track& track)
562 {
563
564 bool removeTrack = false;
565
566 try {
567 trackFitter.fit(track, false);
568 } catch (exception const& e) {
569 removeTrack = true;
570 return removeTrack;
571 }
572
573 auto itStartingParam = std::prev(track.rend());
574
575 while (true) {
576
577 try {
578 trackFitter.fit(track, true, false, (itStartingParam == track.rbegin()) ? nullptr : &itStartingParam);
579 } catch (exception const&) {
580 removeTrack = true;
581 break;
582 }
583
584 double worstLocalChi2 = -1.0;
585
586 track.tagRemovableClusters(0x1F, false);
587
588 auto itWorstParam = track.end();
589
590 for (auto itParam = track.begin(); itParam != track.end(); ++itParam) {
591 if (itParam->getLocalChi2() > worstLocalChi2) {
592 worstLocalChi2 = itParam->getLocalChi2();
593 itWorstParam = itParam;
594 }
595 }
596
597 if (worstLocalChi2 < mImproveCutChi2) {
598 break;
599 }
600
601 if (!itWorstParam->isRemovable()) {
602 removeTrack = true;
603 track.removable();
604 break;
605 }
606
607 auto itNextParam = track.removeParamAtCluster(itWorstParam);
608 auto itNextToNextParam = (itNextParam == track.end()) ? itNextParam : std::next(itNextParam);
609 itStartingParam = track.rbegin();
610
611 if (track.getNClusters() < 10) {
612 removeTrack = true;
613 break;
614 } else {
615 while (itNextToNextParam != track.end()) {
616 if (itNextToNextParam->getClusterPtr()->getChamberId() != itNextParam->getClusterPtr()->getChamberId()) {
617 itStartingParam = std::make_reverse_iterator(++itNextParam);
618 break;
619 }
620 ++itNextToNextParam;
621 }
622 }
623 }
624
625 if (!removeTrack) {
626 for (auto& param : track) {
627 param.setParameters(param.getSmoothParameters());
628 param.setCovariances(param.getSmoothCovariances());
629 }
630 }
631
632 return removeTrack;
633 }
634
635 //_________________________________________________________________________________________________
636 void drawHisto(std::vector<double>& params, std::vector<double>& errors, std::vector<double>& pulls, string outFileName)
637 {
638
639 TH1F* hPullX = new TH1F("hPullX", "hPullX", 201, -10, 10);
640 TH1F* hPullY = new TH1F("hPullY", "hPullY", 201, -10, 10);
641 TH1F* hPullZ = new TH1F("hPullZ", "hPullZ", 201, -10, 10);
642 TH1F* hPullPhi = new TH1F("hPullPhi", "hPullPhi", 201, -10, 10);
643
644 double deNumber[156];
645
646 double alignX[156];
647 double alignY[156];
648 double alignZ[156];
649 double alignPhi[156];
650 double pullX[156];
651 double pullY[156];
652 double pullZ[156];
653 double pullPhi[156];
654
655 for (int iDEN = 0; iDEN < 156; iDEN++) {
656 deNumber[iDEN] = iDEN + 0.5;
657 alignX[iDEN] = params[iDEN * 4];
658 alignY[iDEN] = params[iDEN * 4 + 1];
659 alignZ[iDEN] = params[iDEN * 4 + 3];
660 alignPhi[iDEN] = params[iDEN * 4 + 2];
661 pullX[iDEN] = pulls[iDEN * 4];
662 pullY[iDEN] = pulls[iDEN * 4 + 1];
663 pullZ[iDEN] = pulls[iDEN * 4 + 3];
664 pullPhi[iDEN] = pulls[iDEN * 4 + 2];
665 if (params[iDEN * 4]) {
666
667 hPullX->Fill(pulls[iDEN * 4]);
668 hPullY->Fill(pulls[iDEN * 4 + 1]);
669 hPullZ->Fill(pulls[iDEN * 4 + 3]);
670 hPullPhi->Fill(pulls[iDEN * 4 + 2]);
671 }
672 }
673
674 TGraph* graphAlignX = new TGraph(156, deNumber, alignX);
675 TGraph* graphAlignY = new TGraph(156, deNumber, alignY);
676 TGraph* graphAlignZ = new TGraph(156, deNumber, alignZ);
677 TGraph* graphAlignPhi = new TGraph(156, deNumber, alignPhi);
678 // TGraph* graphAlignYZ = new TGraph(156, alignY, alignZ);
679
680 TGraph* graphPullX = new TGraph(156, deNumber, pullX);
681 TGraph* graphPullY = new TGraph(156, deNumber, pullY);
682 TGraph* graphPullZ = new TGraph(156, deNumber, pullZ);
683 TGraph* graphPullPhi = new TGraph(156, deNumber, pullPhi);
684
685 graphAlignX->SetMarkerStyle(24);
686 graphPullX->SetMarkerStyle(25);
687
688 // graphAlignX->Draw("AP");
689
690 graphAlignY->SetMarkerStyle(24);
691 graphPullY->SetMarkerStyle(25);
692
693 // graphAlignY->Draw("Psame");
694
695 graphAlignZ->SetMarkerStyle(24);
696 graphPullZ->SetMarkerStyle(25);
697
698 // graphAlignZ->Draw("AP");
699 graphAlignPhi->SetMarkerStyle(24);
700 graphPullPhi->SetMarkerStyle(25);
701
702 // graphAlignYZ->SetMarkerStyle(24);
703 // graphAlignYZ->Draw("P goff");
704
705 // Saving plots
706 string PlotFiles_name = Form("%s%s", outFileName.c_str(), "_results.root");
707 TFile* PlotFiles = TFile::Open(PlotFiles_name.c_str(), "RECREATE");
708 PlotFiles->WriteObjectAny(hPullX, "TH1F", "hPullX");
709 PlotFiles->WriteObjectAny(hPullY, "TH1F", "hPullY");
710 PlotFiles->WriteObjectAny(hPullZ, "TH1F", "hPullZ");
711 PlotFiles->WriteObjectAny(hPullPhi, "TH1F", "hPullPhi");
712 PlotFiles->WriteObjectAny(graphAlignX, "TGraph", "graphAlignX");
713 PlotFiles->WriteObjectAny(graphAlignY, "TGraph", "graphAlignY");
714 PlotFiles->WriteObjectAny(graphAlignZ, "TGraph", "graphAlignZ");
715 // PlotFiles->WriteObjectAny(graphAlignYZ, "TGraph", "graphAlignYZ");
716
717 TCanvas* cvn1 = new TCanvas("cvn1", "cvn1", 1200, 1600);
718 // cvn1->Draw();
719 cvn1->Divide(1, 4);
720 TLine limLine(4, -5, 4, 5);
721 TH1F* aHisto = new TH1F("aHisto", "AlignParam", 161, 0, 160);
722 aHisto->SetXTitle("Det. Elem. Number");
723 for (int i = 1; i < 5; i++) {
724 cvn1->cd(i);
725 double Range[4] = {5.0, 1.0, 5.0, 0.01};
726 switch (i) {
727 case 1:
728 aHisto->SetYTitle("#delta_{#X} (cm)");
729 aHisto->GetYaxis()->SetRangeUser(-5.0, 5.0);
730 aHisto->DrawCopy("goff");
731 graphAlignX->Draw("Psame goff");
732 limLine.DrawLine(4, -Range[i - 1], 4, Range[i - 1]);
733 limLine.DrawLine(8, -Range[i - 1], 8, Range[i - 1]);
734 limLine.DrawLine(12, -Range[i - 1], 12, Range[i - 1]);
735 limLine.DrawLine(16, -Range[i - 1], 16, Range[i - 1]);
736 limLine.DrawLine(16 + 18, -Range[i - 1], 16 + 18, Range[i - 1]);
737 limLine.DrawLine(16 + 2 * 18, -Range[i - 1], 16 + 2 * 18, Range[i - 1]);
738 limLine.DrawLine(16 + 2 * 18 + 26, -Range[i - 1], 16 + 2 * 18 + 26, Range[i - 1]);
739 limLine.DrawLine(16 + 2 * 18 + 2 * 26, -Range[i - 1], 16 + 2 * 18 + 2 * 26, Range[i - 1]);
740 limLine.DrawLine(16 + 2 * 18 + 3 * 26, -Range[i - 1], 16 + 2 * 18 + 3 * 26, Range[i - 1]);
741 break;
742 case 2:
743 aHisto->SetYTitle("#delta_{#Y} (cm)");
744 aHisto->GetYaxis()->SetRangeUser(-1.0, 1.0);
745 aHisto->DrawCopy("goff");
746 graphAlignY->Draw("Psame goff");
747 limLine.DrawLine(4, -Range[i - 1], 4, Range[i - 1]);
748 limLine.DrawLine(8, -Range[i - 1], 8, Range[i - 1]);
749 limLine.DrawLine(12, -Range[i - 1], 12, Range[i - 1]);
750 limLine.DrawLine(16, -Range[i - 1], 16, Range[i - 1]);
751 limLine.DrawLine(16 + 18, -Range[i - 1], 16 + 18, Range[i - 1]);
752 limLine.DrawLine(16 + 2 * 18, -Range[i - 1], 16 + 2 * 18, Range[i - 1]);
753 limLine.DrawLine(16 + 2 * 18 + 26, -Range[i - 1], 16 + 2 * 18 + 26, Range[i - 1]);
754 limLine.DrawLine(16 + 2 * 18 + 2 * 26, -Range[i - 1], 16 + 2 * 18 + 2 * 26, Range[i - 1]);
755 limLine.DrawLine(16 + 2 * 18 + 3 * 26, -Range[i - 1], 16 + 2 * 18 + 3 * 26, Range[i - 1]);
756 break;
757 case 3:
758 aHisto->SetYTitle("#delta_{#Z} (cm)");
759 aHisto->GetYaxis()->SetRangeUser(-5.0, 5.0);
760 aHisto->DrawCopy("goff");
761 graphAlignZ->Draw("Psame goff");
762 limLine.DrawLine(4, -Range[i - 1], 4, Range[i - 1]);
763 limLine.DrawLine(8, -Range[i - 1], 8, Range[i - 1]);
764 limLine.DrawLine(12, -Range[i - 1], 12, Range[i - 1]);
765 limLine.DrawLine(16, -Range[i - 1], 16, Range[i - 1]);
766 limLine.DrawLine(16 + 18, -Range[i - 1], 16 + 18, Range[i - 1]);
767 limLine.DrawLine(16 + 2 * 18, -Range[i - 1], 16 + 2 * 18, Range[i - 1]);
768 limLine.DrawLine(16 + 2 * 18 + 26, -Range[i - 1], 16 + 2 * 18 + 26, Range[i - 1]);
769 limLine.DrawLine(16 + 2 * 18 + 2 * 26, -Range[i - 1], 16 + 2 * 18 + 2 * 26, Range[i - 1]);
770 limLine.DrawLine(16 + 2 * 18 + 3 * 26, -Range[i - 1], 16 + 2 * 18 + 3 * 26, Range[i - 1]);
771 break;
772 case 4:
773 aHisto->SetYTitle("#delta_{#varphi} (cm)");
774 aHisto->GetYaxis()->SetRangeUser(-0.01, 0.01);
775 aHisto->DrawCopy("goff");
776 graphAlignPhi->Draw("Psame goff");
777 limLine.DrawLine(4, -Range[i - 1], 4, Range[i - 1]);
778 limLine.DrawLine(8, -Range[i - 1], 8, Range[i - 1]);
779 limLine.DrawLine(12, -Range[i - 1], 12, Range[i - 1]);
780 limLine.DrawLine(16, -Range[i - 1], 16, Range[i - 1]);
781 limLine.DrawLine(16 + 18, -Range[i - 1], 16 + 18, Range[i - 1]);
782 limLine.DrawLine(16 + 2 * 18, -Range[i - 1], 16 + 2 * 18, Range[i - 1]);
783 limLine.DrawLine(16 + 2 * 18 + 26, -Range[i - 1], 16 + 2 * 18 + 26, Range[i - 1]);
784 limLine.DrawLine(16 + 2 * 18 + 2 * 26, -Range[i - 1], 16 + 2 * 18 + 2 * 26, Range[i - 1]);
785 limLine.DrawLine(16 + 2 * 18 + 3 * 26, -Range[i - 1], 16 + 2 * 18 + 3 * 26, Range[i - 1]);
786 break;
787 }
788 }
789
790 PlotFiles->WriteObjectAny(cvn1, "TCanvas", "AlignParam");
791 PlotFiles->Close();
792 }
793
794 //_________________________________________________________________________________________________
795 tuple<TFile*, TTreeReader*> LoadData(const string fileName, const string treeName)
796 {
798
799 TFile* f = TFile::Open(fileName.c_str(), "READ");
800 if (!f || f->IsZombie()) {
801 LOG(error) << "Opening file " << fileName << " failed";
802 exit(-1);
803 }
804
805 TTreeReader* r = new TTreeReader(treeName.c_str(), f);
806 if (r->IsZombie()) {
807 LOG(error) << "Tree " << treeName << " not found";
808 exit(-1);
809 }
810
811 return std::make_tuple(f, r);
812 }
813
814 //_________________________________________________________________________________________________
815 bool FindMuon(int iMCHTrack, vector<dataformats::TrackMCHMID>& muonTracks)
816 {
818 for (const auto& muon : muonTracks) {
819 // cout << "Muon track index: " << muon.getMCHRef().getIndex()<<endl;
820 if (muon.getMCHRef().getIndex() == iMCHTrack) {
821 return true;
822 }
823 }
824 return false;
825 }
826
827 //_________________________________________________________________________________________________
828 int GetDetElemNumber(int iDetElemId)
829 {
831 // get chamber and element number in chamber
832 const int iCh = iDetElemId / 100;
833 const int iDet = iDetElemId % 100;
834
835 // make sure detector index is valid
836 if (!(iCh > 0 && iCh <= 10 && iDet < fgNDetElemCh[iCh - 1])) {
837 LOG(fatal) << "Invalid detector element id: " << iDetElemId;
838 }
839
840 // add number of detectors up to this chamber
841 return iDet + fgSNDetElemCh[iCh - 1];
842 }
843
844 //_________________________________________________________________________________________________
845 int GetDetElemId(int iDetElemNumber)
846 {
847 // make sure detector number is valid
848 if (!(iDetElemNumber >= fgSNDetElemCh[0] &&
849 iDetElemNumber < fgSNDetElemCh[10])) {
850 LOG(fatal) << "Invalid detector element number: " << iDetElemNumber;
851 }
853 // get chamber and element number in chamber
854 int iCh = 0;
855 int iDet = 0;
856 for (int i = 1; i <= 10; i++) {
857 if (iDetElemNumber < fgSNDetElemCh[i]) {
858 iCh = i;
859 iDet = iDetElemNumber - fgSNDetElemCh[i - 1];
860 break;
861 }
862 }
863
864 // make sure detector index is valid
865 if (!(iCh > 0 && iCh <= 10 && iDet < fgNDetElemCh[iCh - 1])) {
866 LOG(fatal) << "Invalid detector element id: " << 100 * iCh + iDet;
867 }
868
869 // add number of detectors up to this chamber
870 return 100 * iCh + iDet;
871 }
872
873 const string mchFileName{"mchtracks.root"};
874 const string muonFileName{"muontracks.root"};
875 string outFileName{"Alignment"};
876 string IdealGeoFileName{""};
877 string RefGeoFileName{""};
878 string NewGeoFileName{""};
879 bool doAlign{false};
880 bool doReAlign{false};
881 bool doMatched{false};
882 bool readFromRec{false};
883 const double weightRecord{1.0};
884 Aligner mAlign{};
885 shared_ptr<base::GRPGeomRequest> mCCDBRequest{};
886
887 map<int, math_utils::Transform3D> transformRef{}; // reference geometry w.r.t track data
888 map<int, math_utils::Transform3D> transformNew{}; // new geometry
889 map<int, math_utils::Transform3D> transformIdeal{}; // Ideal geometry
890
891 geo::TransformationCreator transformation{};
892 TrackFitter trackFitter{};
893 double mImproveCutChi2{};
894
895 std::chrono::duration<double> mElapsedTime{};
896};
897
898//_________________________________________________________________________________________________
900{
901 vector<framework::InputSpec> inputSpecs{};
902 inputSpecs.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0);
903 inputSpecs.emplace_back("geomIdeal", "GLO", "GEOMIDEAL", 0, Lifetime::Condition, framework::ccdbParamSpec("GLO/Config/Geometry"));
904
905 vector<framework::OutputSpec> outputSpecs{};
906 auto ccdbRequest = disableCCDB ? nullptr : std::make_shared<base::GRPGeomRequest>(false, // orbitResetTime
907 false, // GRPECS=true
908 false, // GRPLHCIF
909 true, // GRPMagField
910 false, // askMatLUT
912 inputSpecs);
913
914 return DataProcessorSpec{
915 "mch-alignment",
916 inputSpecs,
917 outputSpecs,
918 AlgorithmSpec{o2::framework::adaptFromTask<AlignmentTask>(ccdbRequest)},
919 Options{{"geo-file-ref", VariantType::String, o2::base::NameConf::getAlignedGeomFileName(), {"Name of the reference geometry file"}},
920 {"geo-file-new", VariantType::String, "", {"Name of the new geometry file"}},
921 {"geo-file-ideal", VariantType::String, o2::base::NameConf::getGeomFileName(), {"Name of the ideal geometry file"}},
922 {"grp-file", VariantType::String, o2::base::NameConf::getGRPFileName(), {"Name of the grp file"}},
923 {"do-align", VariantType::Bool, false, {"Switch for alignment, otherwise only residuals will be stored"}},
924 {"do-evaluation", VariantType::Bool, false, {"Option for saving residuals for evaluation"}},
925 {"do-realign", VariantType::Bool, false, {"Switch for re-alignment using another geometry"}},
926 {"matched", VariantType::Bool, false, {"Switch for using MCH-MID matched tracks"}},
927 {"fix-chamber", VariantType::String, "", {"Chamber fixing, ex 1,2,3"}},
928 {"use-record", VariantType::Bool, false, {"Option for directly using record in alignment if provided"}},
929 {"variation-x", VariantType::Float, 2.0, {"Allowed variation for x axis in cm"}},
930 {"variation-y", VariantType::Float, 0.3, {"Allowed variation for y axis in cm"}},
931 {"variation-phi", VariantType::Float, 0.002, {"Allowed variation for phi axis in rad"}},
932 {"variation-z", VariantType::Float, 2.0, {"Allowed variation for z axis in cm"}},
933 {"sigma-x", VariantType::Float, 1000.0, {"Sigma cut along X"}},
934 {"sigma-y", VariantType::Float, 1000.0, {"Sigma cut along Y"}},
935 {"fix-de", VariantType::String, "", {"DE fixing, ex 101,1019"}},
936 {"mask-fix-de", VariantType::String, "", {"Mask for DE d.o.f fixing, ex 0,2,4"}},
937 {"output", VariantType::String, "Alignment", {"Option for name of output file"}}}};
938}
939
940} // namespace mch
941} // namespace o2
Definition of the base alignment parameters class.
Definition of alignment process for muon spectrometer.
Definition of the MCH cluster minimal structure.
Definition of the Names Generator class.
Definition of the GeometryManager class.
Definition of the MCH track for internal use.
int32_t i
Helper for geometry and GRP related CCDB requests.
Header of the General Run Parameters object.
Configurable parameters for MCH tracking.
Definition of a class to fit a track to a set of clusters.
Definition of the MCH ROFrame record.
Definition of the Names Generator class.
Definition of tools for track extrapolation.
Definition of the MUON track.
Definition of the MCH track.
Definition of the MCH track parameters for internal use.
std::ostringstream debug
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
static void loadGeometry(std::string_view geomFilePath="", bool applyMisalignment=false, bool preferAlignedFile=true)
static std::string getAlignedGeomFileName(const std::string_view prefix="")
Definition NameConf.cxx:46
static std::string getGeomFileName(const std::string_view prefix="")
Definition NameConf.cxx:40
static std::string getGRPFileName(const std::string_view prefix=STANDARDSIMPREFIX)
Definition NameConf.cxx:58
static int initFieldFromGRP(const o2::parameters::GRPMagField *grp, bool verbose=false)
void setGlobalParams(double x, double y, double z, double psi, double theta, double phi)
================ methods for direct setting of delta params
double getTheta() const
Definition AlignParam.h:49
void setSymName(const char *m)
set symbolic name of the volume
Definition AlignParam.h:64
const std::string & getSymName() const
return symbolic name of the volume
Definition AlignParam.h:45
double getPhi() const
iparamater's getters
Definition AlignParam.h:47
double getPsi() const
Definition AlignParam.h:48
bool applyToGeometry() const
apply object to geoemetry
ServiceRegistryRef services()
Definition InitContext.h:34
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
HMPID cluster implementation.
Definition Cluster.h:27
void SetBFieldOn(bool value)
Set flag for Magnetic field On/Off.
Definition Aligner.h:199
void SetAllowedVariation(int iPar, double value)
Definition Aligner.cxx:1267
void ReAlign(std::vector< o2::detectors::AlignParam > &params, std::vector< double > &misAlignments)
Definition Aligner.cxx:1322
void SetReadOnly()
Definition Aligner.h:314
void GlobalFit(std::vector< double > &params, std::vector< double > &errors, std::vector< double > &pulls)
perform global fit
Definition Aligner.cxx:1298
void SetDoEvaluation(bool value)
set to true to do refit evaluation
Definition Aligner.h:205
void init(TString DataRecFName="millerecords.root", TString ConsRecFName="milleconstraints.root")
Definition Aligner.cxx:195
void FixChamber(int iCh, unsigned int parameterMask=ParAll)
Definition Aligner.cxx:577
void ProcessTrack(Track &track, const o2::mch::geo::TransformationCreator &transformation, Bool_t doAlignment, Double_t weight=1)
Definition Aligner.cxx:376
void FixDetElem(int iDetElemId, unsigned int parameterMask=ParAll)
Definition Aligner.cxx:609
void SetSigmaXY(double sigmaX, double sigmaY)
Definition Aligner.cxx:1284
std::vector< double > pulls
const int fgSNDetElemCh[11]
const int fgNDetElemHalfCh[20]
void processWithOutMatching(vector< ROFRecord > &mchROFs, vector< TrackMCH > &mchTracks, vector< Cluster > &mchClusters)
const int fgSNDetElemHalfCh[21]
std::vector< double > params
void init(framework::InitContext &ic)
void finaliseCCDB(framework::ConcreteDataMatcher &matcher, void *obj)
AlignmentTask(shared_ptr< base::GRPGeomRequest > req)
void processWithMatching(vector< ROFRecord > &mchROFs, vector< TrackMCH > &mchTracks, vector< Cluster > &mchClusters, vector< dataformats::TrackMCHMID > &muonTracks)
constexpr double pi()
const int fgDetElemHalfCh[20][13]
void run(framework::ProcessingContext &pc)
std::vector< double > errors
static void useExtrapV2(bool extrapV2=true)
Switch to Runge-Kutta extrapolation v2.
Definition TrackExtrap.h:50
static bool isFieldON()
Return true if the field is switched ON.
Definition TrackExtrap.h:47
static void setField()
void setChamberResolution(double ex, double ey)
Definition TrackFitter.h:91
void useChamberResolution()
Use the chamber resolution instead of cluster resolution during the fit.
Definition TrackFitter.h:54
void setBendingVertexDispersion(double ey)
Set the vertex dispersion in y direction used for the track covariance seed.
Definition TrackFitter.h:44
void smoothTracks(bool smooth)
Enable/disable the smoother (and the saving of related parameters)
Definition TrackFitter.h:47
void fit(Track &track, bool smooth=true, bool finalize=true, std::list< TrackParam >::reverse_iterator *itStartingParam=nullptr, bool skipLocalChi2Calculation=false)
track for internal use
Definition Track.h:33
static GRPObject * loadFrom(const std::string &grpFileName="")
GLdouble f
Definition glcorearb.h:310
GLenum const GLfloat * params
Definition glcorearb.h:272
GLboolean r
Definition glcorearb.h:1233
GLenum GLfloat param
Definition glcorearb.h:271
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
o2::track::TrackParCov Track
TransformationCreator transformationFromTGeoManager(const TGeoManager &geo)
std::function< o2::math_utils::Transform3D(int detElemId)> TransformationCreator
o2::framework::DataProcessorSpec getAlignmentSpec(bool disableCCDB=false)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
std::vector< o2::mch::ROFRecord > mchROFs
uint16_t de
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"