CbmRoot
Loading...
Searching...
No Matches
CbmBbaAlignTask.cxx
Go to the documentation of this file.
1/* Copyright (C) 2025 Johann Wolfgang Goethe-Universitaet Frankfurt, Frankfurt am Main
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Nora Bluhme [committer], Sergey Gorbunov */
4
9
10#include "CbmBbaAlignTask.h"
11
12#include "CbmBbaAlignmentBody.h"
13#include "CbmL1.h"
14#include "FairRootManager.h"
15#include "FairRunAna.h"
16#include "TClonesArray.h"
17#include "TFile.h"
18#include "TGeoManager.h"
19#include "TRandom.h"
20#include "bba/BBA.h"
21#include "bba/Parameter.h"
22
23#include <Logger.h>
24
25#include <TGeoManager.h>
26#include <TGeoMatrix.h>
27
28#include <cmath>
29#include <iomanip>
30#include <iostream>
31#include <sstream>
32#include <string>
33#include <vector>
34
35namespace
36{
37 using namespace cbm::algo;
38 constexpr double shiftToRotFactor = 10.; // factor to convert shifts [cm] to rotations [grad] for boundary settings
39 constexpr bool kMultipleScatteringInCostFunction =
40 false; // include multiple scattering in the cost function track refit
41 constexpr bool kMultipleScatteringInTrackSelection =
42 false; // include multiple scattering in the track selection refit
43} // namespace
44
45
46CbmBbaAlignTask::CbmBbaAlignTask(const char* name, Int_t iVerbose, TString histoFileName, size_t nMaxTracks)
47 : FairTask(name, iVerbose)
48 , fNmaxTracks(nMaxTracks)
49 , fHistoFileName(histoFileName)
50{
51 TFile* curFile = gFile;
52 TDirectory* curDirectory = gDirectory;
53
54 if (!(fHistoFileName == "")) {
55 fHistoFile = new TFile(fHistoFileName.Data(), "RECREATE");
56 }
57 else {
58 fHistoFile = gFile;
59 }
60
61 fHistoFile->cd();
62 fHistoDir = fHistoFile->mkdir("Bba");
63 fHistoDir->cd();
64
65 gFile = curFile;
66 gDirectory = curDirectory;
67}
68
69
71{
72 std::cout << "CbmBbaAlignTask::Init()" << std::endl;
73
74#ifdef HAVE_OMP
75 {
76 const char* env = std::getenv("OMP_NUM_THREADS");
77 if (env) {
78 fNthreads = TString(env).Atoi();
79 }
80 // ensure that at least one thread is set
81 if (fNthreads < 1) {
82 fNthreads = 1;
83 }
84 LOG(info) << "BBA: running with " << fNthreads << " threads";
85 }
86#else
87 {
88 fNthreads = 1;
89 LOG(info) << "BBA: OpenMP not available, running with single thread";
90 }
91#endif
92
93 // FairRootManager manages the root input/output
94 FairRootManager* ioman = FairRootManager::Instance();
95 if (!ioman) {
96 LOG(fatal) << "CbmBbaAlignTask: no FairRootManager";
97 return kFATAL;
98 }
99
100 // initialize mvd-sts track input
101 fInputStsTracks = static_cast<TClonesArray*>(ioman->GetObject("StsTrack"));
102 if (!fInputStsTracks) {
103 LOG(error) << "CbmBbaAlignTask::Init: STS track array not found!";
104 return kERROR;
105 }
106 else {
107 LOG(info) << "CbmBbaAlignTask::Init: STS track array found.";
108 }
109
110 // initialize fitter
111 fFitter.Init();
112 fFitter.SetIgnorePoorCoordinates(true);
113
114 //fFitter.SetMaxExtrapolationStep(70.); // less granular extrapolation for performance
115 fFitter.SetIgnoreMultipleScattering(!kMultipleScatteringInTrackSelection);
116
117 // initialize the number of tracking stations from the CbmStsTrackingInterface
118 // (TODO we may need to use only active stations from the L1 setup)
119
120 const auto* pStsIfs = cbm::RecoSetupManager::Instance()->GetSetup().GetSts();
121 if (!pStsIfs) {
122 LOG(fatal) << "CbmBbaAlignTask::Init: STS RecoSetupUnit not found! Initialize "
123 "CbmSetup::Instance()->LoadSetup(setup) before running the alignment task.";
124 return kFATAL;
125 }
126 fNtrackingStations = pStsIfs->GetNofTrackingStations();
127
128 LOG(info) << "CbmBbaAlignTask::Init: Number of STS tracking stations from interface: " << fNtrackingStations;
129
130 return kSUCCESS;
131}
132
133
134void CbmBbaAlignTask::Exec(Option_t* /*unused*/)
135{
136 std::cout << "CbmBbaAlignTask::Exec()" << std::endl;
137
138 LOG(info) << "BBA: exec event N " << fNevents;
139 fNevents++;
140
141 LOG(info) << "CbmBbaAlignTask::Exec: STS track array found with size: " << fInputStsTracks->GetEntries();
142
143
144 // select tracks for alignment and store them
145 // fFitter.SetDefaultMomentumForMs(0.1); // not needed for STS tracks with magnetic field
146
148}
149
151{
152 std::cout << "CbmBbaAlignTask::Finish()" << std::endl;
153 LOG(info) << "BBA: start the global alignment procedure with " << fTracks.size() << " tracks ...";
154
155 // fix the material radiation thickness to avoid the chi2 rattling at the material map bin boundaries
156 fFitter.SetFixMaterial(true);
157
158 // Initializations we can only do here, after the tracks are selected
159 fSensors = SensorsFromTracks(fTracks); // create the list of sensors from the tracks
161 CreateAndSetAlignmentBodies(fAlignmentMode, fSensors); // create the list of alignment bodies from the sensors
162 SetReferences(fSensors, fTracks); // bind the sensors and alignment bodies to the track nodes
163 InitializeHistograms(); // initialize histograms for the alignment
164
165 LOG(info) << "BBA: " << fSensors.size() << " sensors, " << fAlignmentBodies.size() << " alignment bodies";
166
167 LOG(debug) << "\n Sensors: ";
168 for (unsigned int is = 0; is < fSensors.size(); is++) {
169 auto& s = fSensors[is];
170 LOG(debug) << "Sensor " << is << " sys " << s.fSystemId << " sta " << s.fTrackingStation << " body "
171 << s.fAlignmentBody;
172 }
173 LOG(info) << "\n Alignment bodies: ";
174 for (unsigned int ib = 0; ib < fAlignmentBodies.size(); ib++) {
175 auto& b = fAlignmentBodies[ib];
176 LOG(info) << "Body: " << ib << " station: " << b.GetTrackingStation();
177 }
178
179 // "load" the alignment parameters
180 std::vector<bba::Parameter> par = CreateAlignmentParameters();
181
182 // create artificial misalignement
183 if (fSimulatedMisalignmentRange <= 0.) {
184 LOG(info) << "no simulated misalignment";
185 fParMC = std::vector<double>(kNdfBody * fAlignmentBodies.size(), 0.);
186 }
187 else {
188 LOG(info) << "Simulated misalignment range: " << fSimulatedMisalignmentRange;
189 fParMC = SimulateMisalignment(par, fTracks, fAlignmentBodies); // apply the misalignment to the hits
190 }
191
192 // create bba object and set parameters
193 bba::BBA alignment;
194 alignment.setParameters(par);
195 alignment.setChi2([this](const std::vector<double>& p) { return CostFunction(p); });
196 alignment.printInfo();
197
198 // extract the (initial) start parameters from bba to verify the fitter/cost function and calculate the initial cost
199 fParStart = alignment.getResult();
200
201 {
202 // calculate the initial cost function
203 // (before alignment)
204 LOG(debug) << "calculate initial cost function first time ...";
205 auto tracksCopy = fTracks; // store the initial (misaligned) tracks
206 CostFunction(fParStart, tracksCopy); // run the fitter
207
208 // reject bad tracks (caused by artificial misalignement) and recalculate the initial cost function
209 unsigned tracks_rejected = 0;
210 for (unsigned int itr = 0; itr < tracksCopy.size(); itr++) {
211 auto& t = tracksCopy[itr];
212 double ndf = t.fFittedTrackParam.GetNdf();
213 double chi2 = t.fFittedTrackParam.GetChiSq();
214 if (ndf < 0. || chi2 < 0. || !std::isfinite(ndf) || !std::isfinite(chi2)) {
215 fTracks[itr].fIsActive = false; // we deactivat the original track
216 tracks_rejected++;
217 }
218 }
219 LOG(info) << "reject " << tracks_rejected << " bad tracks and recalculate the initial cost function...";
220 }
221 {
222 auto initialTracks = fTracks; // store the remaining initial (misaligned) tracks
223 fCostInitial = CostFunction(fParStart, initialTracks); // recalculate the cost function with the remaining tracks
224 // plot the residuals before alignment (after applying the first guessed start parameters)
226 }
227
228 fFixedNdf = -1; //fNdfTotal; TODO: why here?
229
230 LOG(debug) << "calculate ideal cost function second time...";
231 fCostIdeal = CostFunction(fParMC); // we have to do this after rejecting bad tracks
232
233 // run the actual alignment ////////////////////
234 LOG(info) << "BBA: start the alignment procedure ...";
235 LOG(info) << " true (MC) parameters: " << PrintParameters(fParMC);
236 LOG(info) << " initial parameters: " << PrintParameters(fParStart);
237 LOG(info) << " Cost function for the true parameters: " << fCostIdeal;
238 LOG(info) << " Cost function for the initial parameters: " << fCostInitial;
239 alignment.align(); // loops until convergence
240
241 auto alignedTracks = fTracks;
242 double costResult =
243 CostFunction(alignment.getResult(),
244 alignedTracks); // apply the alignment parameters to the hits and calculate the cost function
245
246 LOG(info) << "BBA: alignment procedure finished ...";
247
248
249 LOG(info) << "BBA: alignment results: ";
250 LOG(info) << " aligned parameters: " << PrintParameters(alignment.getResult());
251 LOG(info) << " difference to MC parameters: " << PrintParameters(DiffParameters(alignment.getResult(), fParMC));
252 LOG(info) << " RMSE to MC parameters: " << PrintRMSE(par, fParMC, alignment.getResult());
253 LOG(info) << " Number of cost function calls: " << fNcallsCost;
254 LOG(info) << " Cost function for the initial parameters: " << fCostInitial;
255 LOG(info) << " Cost function for the true parameters: " << fCostIdeal;
256 LOG(info) << " Cost function for the final parameters: " << costResult
257 << ", diff to true cost: " << costResult - fCostIdeal
258 << ", diff to initial cost: " << costResult - fCostInitial;
259
260 // fill histograms after alignment
261 FillHistograms(alignedTracks, fHistoAfterAlignment);
262
263 // TODO: we may need to run the cost function again several times, at least this is done in the original task
264
265
266 // prepare the output alignment parameters
267 LOG(info) << "BBA: creating alignment matrices for the output ...";
268 std::map<std::string, TGeoHMatrix> alignmentMatrices = CreateAlignmentMatrices(alignment.getResult());
269
270 // write the alignment matrices to the output file
271 TFile* misalignmentMatrixRootfile = new TFile(fMatrixOutFileName, "RECREATE");
272 if (misalignmentMatrixRootfile->IsOpen()) {
273 gDirectory->WriteObject(&alignmentMatrices, "AlignmentMatrices");
274 misalignmentMatrixRootfile->Write();
275 misalignmentMatrixRootfile->Close();
276 }
277
278 // write histograms to file
279 TDirectory* curr = gDirectory;
280 TFile* currentFile = gFile;
281 // Open output file and write histograms
282
283 fHistoFile->cd();
285 if (!(fHistoFileName == "")) {
286 fHistoFile->Close();
287 fHistoFile->Delete();
288 }
289 gFile = currentFile;
290 gDirectory = curr;
291
292} // CbmBbaAlignTask::Finish()
293
294
295unsigned CbmBbaAlignTask::SelectTracks(TClonesArray* inputTracks, std::vector<TrackContainer>& Tracks)
296{
297 // debug statistics
298 unsigned num_accepted = 0;
299 unsigned num_rejected_create_failed = 0;
300 unsigned num_rejected_fit = 0;
301 unsigned num_rejected_hitNumber = 0;
302 unsigned num_rejected_infiniteQp = 0;
303 unsigned num_rejected_momentum = 0;
304 unsigned num_fix_rad_max = 0;
305 unsigned num_fix_rad_min = 0;
306 unsigned num_rejected_fit_node = 0;
307 unsigned num_rejected_traj = 0;
308 int numPosMomentum = 0;
309 int numNegMomentum = 0;
310
311 fFitter.SetFixMaterial(false);
312
313 // loop over all STS tracks and ...
314 for (int iTr = 0; iTr < inputTracks->GetEntriesFast(); iTr++) {
315 if (Tracks.size() >= fNmaxTracks) break;
316 //const CbmStsTrack* stsTrack = dynamic_cast<CbmStsTrack*>(inputTracks->At(iTr));
317 //assert(stsTrack);
318 // ... create a track container for the track
319 TrackContainer t; // TODO: refactor track container to class with setters
320 if (!fFitter.CreateFromMvdStsTrack(t.fTrack, iTr, true)) {
321 num_rejected_create_failed++;
322 continue;
323 }
324 t.MakeConsistent();
325
326 // ... fit the track to initialize the track parameters
327 if (!fFitter.FitTrajectory(t.fTrack)) {
328 num_rejected_fit++;
329 continue;
330 }
331
332 if (!fFitter.FitTrajectoryUpstream(t.fTrack, t.fFittedTrackParam)) {
333 num_rejected_fit++;
334 continue;
335 }
336
337 const auto& par = t.fFittedTrackParam;
338
340 num_rejected_hitNumber++;
341 continue; // cut: all tracking stations must have a hit
342 }
343 if (!std::isfinite(par.GetQp())) {
344 num_rejected_infiniteQp++;
345 continue; // cut: Q/p must be finite
346 }
347 if (fabs(par.GetQp()) > 3) {
348 num_rejected_momentum++;
349 continue; // cut: momentum > 1 GeV
350 }
351
352 // correct the material radiation thickness for a case of too large/small values
353 for (unsigned int i = 0; i < t.fTrack.GetNofNodes(); i++) {
354 auto& n = t.fTrack.GetNodeReference(i);
355 if (!n.isFitted) {
356 t.fIsActive = false;
357 num_rejected_fit_node++;
358 break;
359 }
360 if (n.radThick > 0.01) {
361 LOG(debug) << "CbmBbaAlignTask: radiation thickness is too large: " << n.radThick;
362 num_fix_rad_max++;
363 n.radThick = 0.01;
364 }
365 if (n.radThick < 0.001) {
366 LOG(debug) << "CbmBbaAlignTask: radiation thickness is too small: " << n.radThick;
367 num_fix_rad_min++;
368 n.radThick = 0.001;
369 }
370 }
371 if (!t.fIsActive) continue;
372
373
374 // ensure that all the hits are not too much deviated from the trajectory
375 // (to be improved)
376 const double cutX = 8.;
377 const double cutY = 8.;
378 for (unsigned int i = 0; i < t.fTrack.GetNofNodes(); i++) {
379 // copy the track to avoid modifying the original one
380 auto t_copy = t.fTrack;
381 auto& n = t_copy.GetNode(i);
382 if (!n.isXySet) {
383 continue;
384 }
385 t_copy.DisableMeasurementAtNode(i);
386 if (!fFitter.FitTrajectory(t_copy)) {
387 t.fIsActive = false;
388 num_rejected_traj++;
389 break;
390 }
391 double x_residual = n.measurementXY.X() - n.paramDn.X(); // this should be the difference vector
392 double y_residual = n.measurementXY.Y() - n.paramDn.Y();
393 double x_pull = x_residual / sqrt(n.measurementXY.Dx2() + n.paramDn.GetCovariance(0, 0));
394 double y_pull = y_residual / sqrt(n.measurementXY.Dy2() + n.paramDn.GetCovariance(1, 1));
395 if (!n.isFitted || (n.measurementXY.NdfX() > 0. && fabs(x_pull) > cutX)
396 || (n.measurementXY.NdfY() > 0. && fabs(y_pull) > cutY)) {
397 t.fIsActive = false;
398 num_rejected_traj++;
399 break;
400 }
401 }
402
403 // copy the accepted track to track vector
404 if (t.fIsActive) {
405 Tracks.push_back(t);
406 Tracks.back().StoreOriginalHitPositions();
407 if (par.GetQp() > 0.) {
408 numPosMomentum++;
409 }
410 else {
411 numNegMomentum++;
412 }
413 num_accepted++;
414 }
415 }
416
417 // Debug output
418 if (num_rejected_create_failed != 0) {
419 LOG(warn) << "failed to create " << num_rejected_create_failed << " tracks";
420 }
421 if (num_rejected_fit != 0) {
422 LOG(warn) << "failed to fit " << num_rejected_fit << " tracks";
423 }
424 if (num_rejected_hitNumber != 0) {
425 LOG(info) << "rejected " << num_rejected_hitNumber << " tracks for insufficient number of hits";
426 }
427 if (num_rejected_infiniteQp != 0) {
428 LOG(warn) << "rejected " << num_rejected_infiniteQp << " tracks for infinite Q/p";
429 }
430 if (num_rejected_momentum != 0) {
431 LOG(info) << "rejected " << num_rejected_momentum << " tracks for low momentum";
432 }
433 if (num_fix_rad_max != 0) {
434 LOG(warn) << "CbmBbaAlignTask: radiation thickness is too large " << num_fix_rad_max << " times";
435 }
436 if (num_fix_rad_min != 0) {
437 LOG(warn) << "CbmBbaAlignTask: radiation thickness is too small " << num_fix_rad_min << " times";
438 }
439 if (num_rejected_fit_node != 0) {
440 LOG(warn) << "Rejected fit node " << num_rejected_fit_node << " tracks";
441 }
442 if (num_rejected_traj != 0) {
443 LOG(warn) << "Rejected " << num_rejected_traj << " tracks for hits deviating from the trajectory";
444 }
445
446 LOG(info) << "BBA: selected " << num_accepted << " (" << Tracks.size() << " total) tracks for alignment, "
447 << numPosMomentum << " positive and " << numNegMomentum << " negative momentum tracks";
448
449
450 return num_accepted;
451}
452
453std::vector<CbmBbaAlignTask::Sensor> CbmBbaAlignTask::SensorsFromTracks(const std::vector<TrackContainer>& tracks) const
454{
455 // create the set of sensors and pack into sorted vector
456 // loop over all hits and extract the sensors from the hits
457 std::set<Sensor> sensorSet;
458 std::shared_ptr<const cbm::GeoNodeMap> geoNodeMap = cbm::RecoSetupManager::Instance()->GetGeoNodeMap();
459 for (auto& t : tracks) {
460 for (auto& n : t.fTrack.GetNodes()) {
461 if (!n.isXySet) {
462 continue;
463 }
464 Sensor s;
466 // TODO: get the station index from n.fHitSystemId, n.fHitAddress
467 s.fTrackingStation = n.materialLayer;
468 if (n.materialLayer < 0) {
469 LOG(fatal) << "CbmBbaAlignTask::SensorsFromTracks: negative material layer in track node! for "
471 }
472 if (s.fSystemId == ECbmModuleId::kSts) {
473 s.fNodePath = geoNodeMap->GetNodePath(Trajectory::GetHitAddress(n)); // NOTE: for STS gives a path to a sensor
474 }
475 sensorSet.insert(s);
476 }
477 }
478
479 // pack sensors into a vector and sort them
480 std::vector<Sensor> sensors(sensorSet.begin(), sensorSet.end());
481 // TODO: isn't the set sorted correctly already?
482 // NOTE: the sensors are automatically sorted inside std::set, no sorting is needed here (SZh)
483 std::sort(sensors.begin(), sensors.end(), [](const Sensor& a, const Sensor& b) { return a < b; });
484
485 LOG(info) << "BBA: found " << sensors.size() << " sensors used by selected tracks:";
486
487 return sensors;
488}
489
490
492 std::vector<Sensor>& sensors) const
493{
494 std::vector<cbm::bba::AlignmentBody> alignmentBodies;
495 // bind alignment bodies to sensors or stations
496 switch (mode) {
497 case station: // one alignment body per tracking station
498 //alignmentBodies.resize(fNtrackingStations);
499 for (int i = 0; i < fNtrackingStations; i++) {
500 //alignmentBodies[i].SetTrackingStation(i);
501 double z = 0;
502 switch (i) {
503 case 0: z = -14.; break;
504 case 1: z = -4.; break;
505 case 2: z = 6.; break;
506 case 3: z = 16.; break;
507 case 4: z = 26.; break;
508 case 5: z = 36.; break;
509 case 6: z = 46.; break;
510 case 7: z = 56.; break;
511 default: z = 0.; break;
512 }
513 alignmentBodies.emplace_back(cbm::bba::AlignmentBody(0., 0., z, 0., 0., 0.));
514 alignmentBodies.back().SetTrackingStation(i);
515 }
516 for (auto& s : sensors) {
517 s.fAlignmentBody = s.fTrackingStation;
518 }
519 break;
520 case sensor: // one alignment body per sensor
521 alignmentBodies.clear();
522 alignmentBodies.reserve(sensors.size());
523
524 for (unsigned int i = 0; i < sensors.size(); i++) {
525 auto& s = sensors[i];
526 alignmentBodies.emplace_back(cbm::bba::AlignmentBody(s.fNodePath));
527 s.fAlignmentBody = i;
528 alignmentBodies.back().SetTrackingStation(s.fTrackingStation);
529 }
530 break;
531 }
532
533 return alignmentBodies;
534}
535
536
537void CbmBbaAlignTask::SetReferences(const std::vector<Sensor>& sensors, std::vector<TrackContainer>& tracks) const
538{
539 // bind the sensors and alignment bodies to the track nodes
540 std::shared_ptr<const cbm::GeoNodeMap> geoNodeMap = cbm::RecoSetupManager::Instance()->GetGeoNodeMap();
541 for (auto& t : tracks) {
542 for (unsigned int i = 0; i < t.fTrack.GetNofNodes(); i++) {
543 const auto& n = t.fTrack.GetNode(i);
544 if (!n.isXySet) {
545 continue;
546 }
547 // create the sensor we want to find
548 Sensor s;
550 if (n.materialLayer < 0) {
551 LOG(fatal) << "CbmBbaAlignTask::SetReferences: negative material layer in track node! for "
553 }
554 s.fTrackingStation = n.materialLayer;
555 if (s.fSystemId == ECbmModuleId::kSts) {
556 s.fNodePath = geoNodeMap->GetNodePath(Trajectory::GetHitAddress(n));
557 }
558 // find the sensor in the vector and set the reference to sensor index
559 auto iter =
560 std::lower_bound(sensors.begin(), sensors.end(), s, [](const Sensor& a, const Sensor& b) { return a < b; });
561 assert(iter != sensors.end());
562 assert(*iter == s);
563 int iSensor = std::distance(sensors.begin(), iter);
564 t.fTrack.SetSensorId(i, iSensor); // store the sensor index in the node
565 t.fTrack.SetAlignmentBodyId(i,
566 sensors.at(iSensor).fAlignmentBody); // store the alignment body index in the node
567 }
568 }
569}
570
571std::vector<bba::Parameter> CbmBbaAlignTask::CreateAlignmentParameters() const
572{
573 int nParameters = kNdfBody * fAlignmentBodies.size(); // x, y, z
574 std::vector<bba::Parameter> par(nParameters);
575
576 // initialize all parameters
577 for (int ip = 0; ip < nParameters; ip++) {
578 bba::Parameter& p = par[ip];
579 p.SetID(ip); // ID requires newer BBA version
580 p.SetActive(1);
581 p.SetValue(0.);
582 if (ip % kNdfBody < 3) {
583 p.SetBoundaryMin(-fSimulatedMisalignmentRange);
584 p.SetBoundaryMax(fSimulatedMisalignmentRange);
585 }
586 else {
587 p.SetBoundaryMin(-fSimulatedMisalignmentRange * shiftToRotFactor); // in degrees
588 p.SetBoundaryMax(fSimulatedMisalignmentRange * shiftToRotFactor);
589 }
590 if (ip % kNdfBody < 3) {
591 p.SetStepMin(1.e-6);
592 p.SetStepMax(0.1);
593 p.SetStep(1.e-2);
594 }
595 else {
596 p.SetStepMin(1.e-5);
597 p.SetStepMax(0.5);
598 p.SetStep(1.e-1);
599 }
600 }
601
602 // fix first and last station and x of middle station
603 for (unsigned int ib = 0; ib < fAlignmentBodies.size(); ib++) {
604 auto& b = fAlignmentBodies[ib];
605 if (b.GetTrackingStation() == 0) { // the first station
606 par[kNdfBody * ib + 0].SetActive(0);
607 par[kNdfBody * ib + 1].SetActive(0);
608 par[kNdfBody * ib + 2].SetActive(0);
609 par[kNdfBody * ib + 3].SetActive(0);
610 par[kNdfBody * ib + 4].SetActive(0);
611 par[kNdfBody * ib + 5].SetActive(0);
612 continue;
613 }
614 if (b.GetTrackingStation() == fNtrackingStations - 1) { // the last station
615 par[kNdfBody * ib + 0].SetActive(0);
616 par[kNdfBody * ib + 1].SetActive(0);
617 par[kNdfBody * ib + 2].SetActive(0);
618 par[kNdfBody * ib + 3].SetActive(0);
619 par[kNdfBody * ib + 4].SetActive(0);
620 par[kNdfBody * ib + 5].SetActive(0);
621 continue;
622 }
623 if (b.GetTrackingStation() == 4) {
624 par[kNdfBody * ib + 0].SetActive(0);
625 par[kNdfBody * ib + 1].SetActive(0);
626 par[kNdfBody * ib + 2].SetActive(0);
627 par[kNdfBody * ib + 3].SetActive(0);
628 par[kNdfBody * ib + 4].SetActive(0);
629 par[kNdfBody * ib + 5].SetActive(0);
630 continue;
631 }
632 // par[kNdfBody * ib + 5].SetActive(0); // fix gamma for all stations
633 }
634 return par;
635}
636
637std::vector<double> CbmBbaAlignTask::InvertParameters(std::vector<double> par) const
638{
639 for (unsigned int i = 0; i < par.size(); i++) {
640 par[i] = -par[i];
641 }
642 return par;
643}
644
645std::vector<double> CbmBbaAlignTask::DiffParameters(const std::vector<double>& par1,
646 const std::vector<double>& par2) const
647{
648 if (par1.size() != par2.size()) {
649 LOG(fatal) << "CbmBbaAlignTask::DiffParameters: parameter vectors have different sizes!";
650 }
651 std::vector<double> diff(par1.size(), 0.);
652 for (unsigned int i = 0; i < par1.size(); i++) {
653 diff[i] = par1[i] - par2[i];
654 }
655 return diff;
656}
657
658std::string CbmBbaAlignTask::PrintParameters(const std::vector<double>& par) const
659{
660 std::stringstream ss;
661 ss << "BBA: alignment parameters:";
662 for (unsigned int is = 0; is < fAlignmentBodies.size(); is++) {
663 auto& b = fAlignmentBodies[is];
664 ss << "\nBody " << is << " sta " << b.GetTrackingStation() << ": x " << std::setprecision(10)
665 << par[kNdfBody * is + 0] << " y " << par[kNdfBody * is + 1] << " z " << par[kNdfBody * is + 2]
666 << " alpha: " << par[kNdfBody * is + 3] << " beta: " << par[kNdfBody * is + 4]
667 << " gamma: " << par[kNdfBody * is + 5];
668 }
669 return ss.str();
670}
671
672std::string CbmBbaAlignTask::PrintRMSE(const std::vector<bba::Parameter>& par, const std::vector<double>& parMC,
673 const std::vector<double>& parValues) const
674{
675 std::vector<double> rmse(kNdfBody, 0.); // RMSE for each parameter species (x, y, z)
676 std::vector<unsigned int> active(kNdfBody, 0);
677 for (unsigned int is = 0; is < fAlignmentBodies.size(); is++) {
678 unsigned int indexX = kNdfBody * is + 0;
679 unsigned int indexY = kNdfBody * is + 1;
680 unsigned int indexZ = kNdfBody * is + 2;
681 unsigned int indexA = kNdfBody * is + 3;
682 unsigned int indexB = kNdfBody * is + 4;
683 unsigned int indexC = kNdfBody * is + 5;
684 if (par[indexX].IsActive()) {
685 double dx = parValues[indexX] - parMC[indexX];
686 rmse[0] += dx * dx;
687 active[0]++;
688 }
689 if (par[indexY].IsActive()) {
690 double dy = parValues[indexY] - parMC[indexY];
691 rmse[1] += dy * dy;
692 active[1]++;
693 }
694 if (par[indexZ].IsActive()) {
695 double dz = parValues[indexZ] - parMC[indexZ];
696 rmse[2] += dz * dz;
697 active[2]++;
698 }
699 if (par[indexA].IsActive()) {
700 double da = parValues[indexA] - parMC[indexA];
701 rmse[3] += da * da;
702 active[3]++;
703 }
704 if (par[indexB].IsActive()) {
705 double db = parValues[indexB] - parMC[indexB];
706 rmse[4] += db * db;
707 active[4]++;
708 }
709 if (par[indexC].IsActive()) {
710 double dc = parValues[indexC] - parMC[indexC];
711 rmse[5] += dc * dc;
712 active[5]++;
713 }
714 }
715 for (unsigned int i = 0; i < kNdfBody; i++) {
716 rmse[i] = sqrt(rmse[i] / active[i]);
717 }
718 std::stringstream ss;
719 ss << "BBA: RMSE of alignment parameters:";
720 for (unsigned int i = 0; i < kNdfBody; i++) {
721 const char* label = "xyzabc";
722 ss << "\n" << label[i] << ": " << std::setprecision(10) << rmse[i] << " (" << active[i] << " active)";
723 }
724 return ss.str();
725}
726
727std::vector<double> CbmBbaAlignTask::SimulateMisalignment(const std::vector<bba::Parameter>& par,
728 std::vector<TrackContainer>& tracks,
729 std::vector<cbm::bba::AlignmentBody>& AlignmentBodies) const
730{
731 gRandom->SetSeed(fRandomSeed);
733 double dRot = d * shiftToRotFactor;
734 std::vector<double> par_misaligned(kNdfBody * AlignmentBodies.size(), 0.);
735
736 for (unsigned int is = 0; is < AlignmentBodies.size(); is++) {
737 const bba::Parameter& px = par[kNdfBody * is + 0];
738 const bba::Parameter& py = par[kNdfBody * is + 1];
739 const bba::Parameter& pz = par[kNdfBody * is + 2];
740 const bba::Parameter& pa = par[kNdfBody * is + 3];
741 const bba::Parameter& pb = par[kNdfBody * is + 4];
742 const bba::Parameter& pc = par[kNdfBody * is + 5];
743
744 // +- d cm misalignment
745 if (px.IsActive()) {
746 par_misaligned.at(kNdfBody * is + 0) = gRandom->Uniform(2. * d) - d;
747 }
748 if (py.IsActive()) {
749 par_misaligned.at(kNdfBody * is + 1) = gRandom->Uniform(2. * d) - d;
750 }
751 if (pz.IsActive()) {
752 par_misaligned.at(kNdfBody * is + 2) = gRandom->Uniform(2. * d) - d;
753 }
754 if (pa.IsActive()) {
755 par_misaligned.at(kNdfBody * is + 3) = gRandom->Uniform(2. * (dRot)) - (dRot);
756 }
757 if (pb.IsActive()) {
758 par_misaligned.at(kNdfBody * is + 4) = gRandom->Uniform(2. * (dRot)) - (dRot);
759 }
760 if (pc.IsActive()) {
761 par_misaligned.at(kNdfBody * is + 5) = gRandom->Uniform(2. * (dRot)) - (dRot);
762 }
763 }
764 //
765 ApplyAlignment(par_misaligned, tracks, AlignmentBodies, true);
766 // Store the hit positions after applying the misalignment as original hit positions:
767 for (auto& t : tracks) {
768 t.StoreOriginalHitPositions();
769 }
770 return par_misaligned;
771}
772
774{
775 TDirectory* curDirectory = gDirectory;
776 int nHistos = fAlignmentBodies.size();
777
778 fHistoDir->cd();
779 for (int i = -1; i < nHistos; i++) {
780 const char* histName = Form("Station%d", i);
781 const char* histTitle = Form(", Station %d", i);
782 if (i == -1) {
783 histName = "All";
784 histTitle = ", all Stations";
785 }
786 //fHistoDir->mkdir(n1);
787 //fHistoDir->cd(n1);
788
789 int nBins = 301;
790 double sizeRX = 0.1;
791 double sizeRY = 0.1;
792 double sizePX = 10.;
793 double sizePY = 10.;
794
795 fHistoBeforeAlignment.fResidualsX.push_back(std::make_unique<TH1F>(
796 Form("%s_X_Res_BeforeAli", histName), Form("X-Residuals Before Alignment%s", histTitle), nBins, -sizeRX, sizeRX));
797 fHistoBeforeAlignment.fResidualsY.push_back(std::make_unique<TH1F>(
798 Form("%s_Y_Res_BeforeAli", histName), Form("Y-Residuals Before Alignment%s", histTitle), nBins, -sizeRY, sizeRY));
799
800 fHistoBeforeAlignment.fPullsX.push_back(std::make_unique<TH1F>(
801 Form("%s_X_Pull_BeforeAli", histName), Form("X-Pulls Before Alignment%s", histTitle), nBins, -sizePX, sizePX));
802 fHistoBeforeAlignment.fPullsY.push_back(std::make_unique<TH1F>(
803 Form("%s_Y_Pull_BeforeAli", histName), Form("Y-Pulls Before Alignment%s", histTitle), nBins, -sizePY, sizePY));
804
805
806 fHistoAfterAlignment.fResidualsX.push_back(std::make_unique<TH1F>(
807 Form("%s_X_Res_AfterAli", histName), Form("X-Residuals After Alignment%s", histTitle), nBins, -sizeRX, sizeRX));
808 fHistoAfterAlignment.fResidualsY.push_back(std::make_unique<TH1F>(
809 Form("%s_Y_Res_AfterAli", histName), Form("Y-Residuals After Alignment%s", histTitle), nBins, -sizeRY, sizeRY));
810
811 fHistoAfterAlignment.fPullsX.push_back(std::make_unique<TH1F>(
812 Form("%s_X_Pull_AfterAli", histName), Form("X-Pulls After Alignment%s", histTitle), nBins, -sizePX, sizePX));
813 fHistoAfterAlignment.fPullsY.push_back(std::make_unique<TH1F>(
814 Form("%s_Y_Pull_AfterAli", histName), Form("Y-Pulls After Alignment%s", histTitle), nBins, -sizePY, sizePY));
815 }
816
817 for (int i = 0; i < nHistos + 1; i++) {
818 // set line colors
819 fHistoAfterAlignment.fResidualsX[i]->SetLineColor(kRed);
820 fHistoAfterAlignment.fResidualsY[i]->SetLineColor(kRed);
821 fHistoAfterAlignment.fPullsX[i]->SetLineColor(kRed);
822 fHistoAfterAlignment.fPullsY[i]->SetLineColor(kRed);
823
824 // set histograms to dynamic binning
825 fHistoBeforeAlignment.fResidualsX[i]->SetCanExtend(TH1::kXaxis);
826 fHistoBeforeAlignment.fResidualsY[i]->SetCanExtend(TH1::kXaxis);
827 fHistoBeforeAlignment.fPullsX[i]->SetCanExtend(TH1::kXaxis);
828 fHistoBeforeAlignment.fPullsY[i]->SetCanExtend(TH1::kXaxis);
829
830 fHistoAfterAlignment.fResidualsX[i]->SetCanExtend(TH1::kXaxis);
831 fHistoAfterAlignment.fResidualsY[i]->SetCanExtend(TH1::kXaxis);
832 fHistoAfterAlignment.fPullsX[i]->SetCanExtend(TH1::kXaxis);
833 fHistoAfterAlignment.fPullsY[i]->SetCanExtend(TH1::kXaxis);
834 }
835
836 gDirectory = curDirectory;
837}
838
840{
841 if (!obj->IsFolder())
842 obj->Write();
843 else {
844 TDirectory* cur = gDirectory;
845 TFile* currentFile = gFile;
846
847 TDirectory* sub = cur->GetDirectory(obj->GetName());
848 sub->cd();
849 TList* listSub = (dynamic_cast<TDirectory*>(obj))->GetList();
850 TIter it(listSub);
851 while (TObject* obj1 = it()) {
853 }
854 cur->cd();
855 gFile = currentFile;
856 gDirectory = cur;
857 }
858}
859
860void CbmBbaAlignTask::FillHistograms(const std::vector<TrackContainer>& tracks, Histograms& histo)
861{
862 // calculate the residuals for all tracks at each TrajectoryNode
863 for (const auto& t : tracks) {
864 if (!t.fIsActive) continue;
865 for (unsigned int in = 0; in < t.fTrack.GetNofNodes(); in++) {
866 // copy the track to avoid modifying the original one
867 auto tr = t.fTrack;
868 const auto& node = tr.GetNode(in);
869 if (!node.isXySet) {
870 continue;
871 }
872 tr.DisableMeasurementAtNode(in);
873
874 fFitter.FitTrajectory(tr);
875
876 if (!node.isFitted) { // TODO understand why this is needed
877 continue;
878 }
879
880 int alignmentBody = Trajectory::GetAlignmentBodyId(node);
881
882 double x_residual = node.measurementXY.X() - node.paramDn.X();
883 double y_residual = node.measurementXY.Y() - node.paramDn.Y();
884 double x_pull = x_residual / sqrt(node.measurementXY.Dx2() + node.paramDn.GetCovariance(0, 0));
885 double y_pull = y_residual / sqrt(node.measurementXY.Dy2() + node.paramDn.GetCovariance(1, 1));
886
887 if (node.measurementXY.NdfX() > 0) {
888 histo.fResidualsX[0]->Fill(x_residual);
889 histo.fPullsX[0]->Fill(x_pull);
890 }
891 if (node.measurementXY.NdfY() > 0) {
892 histo.fResidualsY[0]->Fill(y_residual);
893 histo.fPullsY[0]->Fill(y_pull);
894 }
895
896 // TODO: why can we drop the check for NdfX/Y > 0 here?
897 histo.fResidualsX[alignmentBody + 1]->Fill(x_residual);
898 histo.fResidualsY[alignmentBody + 1]->Fill(y_residual);
899
900 histo.fPullsX[alignmentBody + 1]->Fill(x_pull);
901 histo.fPullsY[alignmentBody + 1]->Fill(y_pull);
902 }
903 }
904}
905
906void CbmBbaAlignTask::SetAlignment(const std::vector<double>& par,
907 std::vector<cbm::bba::AlignmentBody>& AlignmentBodies) const
908{
909 // apply alignment parameters to the alignment bodies
910 for (unsigned int ib = 0; ib < AlignmentBodies.size(); ib++) {
911 double dx = par[kNdfBody * ib + 0];
912 double dy = par[kNdfBody * ib + 1];
913 double dz = par[kNdfBody * ib + 2];
914 double da = par[kNdfBody * ib + 3];
915 double db = par[kNdfBody * ib + 4];
916 double dc = par[kNdfBody * ib + 5];
917 AlignmentBodies[ib].SetParameters(dx, dy, dz, da, db, dc);
918 }
919}
920
921void CbmBbaAlignTask::ApplyAlignment(const std::vector<double>& par, std::vector<TrackContainer>& tracks,
922 std::vector<cbm::bba::AlignmentBody>& AlignmentBodies, bool invert = false) const
923{
924 SetAlignment(par, AlignmentBodies);
925 // apply alignment parameters to the hits
926 for (TrackContainer& t : tracks) {
927 for (unsigned int in = 0; in < t.fTrack.GetNofNodes(); in++) {
928 auto& node = t.fTrack.GetNodeReference(in);
929 if (!node.isXySet) {
930 continue;
931 }
932
933 int AlignmentBodyIdx = Trajectory::GetAlignmentBodyId(node);
934 if (AlignmentBodyIdx < 0) {
935 LOG(fatal) << "BBA: ApplyAlignment: node has no alignment body! ";
936 continue;
937 }
938 std::array<double, 3> alignedHit;
939 if (!invert) {
940 alignedHit = AlignmentBodies[AlignmentBodyIdx].ApplyAlignmentToHit(t.fOriginalHitPositions[in]);
941 }
942 else {
943 alignedHit = AlignmentBodies[AlignmentBodyIdx].ApplyInverseAlignmentToHit(t.fOriginalHitPositions[in]);
944 }
945
946 // store the shift in z to shift the track parameters accordingly
947 double dz = alignedHit[2] - node.z;
949 node.measurementXY.SetX(alignedHit[0]);
950 node.measurementXY.SetY(alignedHit[1]);
951 node.z = alignedHit[2];
952
953 // shift the fitted track to the Z position of the hit
954 {
955 auto& p = node.paramDn;
956 p.SetX(p.X() + p.Tx() * dz);
957 p.SetY(p.Y() + p.Ty() * dz);
958 p.SetZ(node.z);
959 }
960 {
961 auto& p = node.paramUp;
962 p.SetX(p.X() + p.Tx() * dz);
963 p.SetY(p.Y() + p.Ty() * dz);
964 p.SetZ(node.z);
965 }
966 }
967 }
968}
969
970double CbmBbaAlignTask::CostFunction(const std::vector<double>& par)
971{
972 auto tracksCopy = fTracks;
973 return CostFunction(par, tracksCopy);
974}
975
976double CbmBbaAlignTask::CostFunction(const std::vector<double>& par, std::vector<TrackContainer>& tracks)
977{
978 // apply new parameters to the hits of a copy of tracks
980 double chi2Total = 0.;
981 long ndfTotal = 0;
982
984 fit.SetIgnoreMultipleScattering(!kMultipleScatteringInCostFunction);
985
986#pragma omp parallel for firstprivate(fit) reduction(+ : chi2Total, ndfTotal) num_threads(fNthreads)
987 for (unsigned int itr = 0; itr < tracks.size(); itr++) {
988 auto& t = tracks[itr];
989 if (!t.fIsActive) continue;
990
991 // fit.SetDebugInfo(" track " + std::to_string(itr));
992
993 for (unsigned int in = 0; in < t.fTrack.GetNofNodes(); in++) {
994 const auto& node = t.fTrack.GetNode(in);
995 if (!node.isFitted) {
996 LOG(fatal) << "BBA: Cost function: aligned node is not fitted! ";
997 }
998 }
999 bool ok = fit.FitTrajectoryUpstream(t.fTrack, t.fFittedTrackParam);
1000 double chi2 = t.fFittedTrackParam.GetChiSq();
1001 double ndf = t.fFittedTrackParam.GetNdf();
1002 if (!ok || !std::isfinite(chi2) || chi2 <= 0. || ndf <= 0.) {
1003 // TODO: deactivate the track and continue
1004 LOG(fatal) << "BBA: fit failed! ";
1005 chi2 = 0.;
1006 ndf = 0.;
1007 }
1008 chi2Total += chi2;
1009 ndfTotal += (int) ndf;
1010 }
1011
1012 double cost = chi2Total / (ndfTotal + 1);
1013 if (fFixedNdf > 0 && ndfTotal != fFixedNdf) {
1014 cost = 1.e30;
1015 }
1016
1017 // monitoring
1018 if (++fNcallsCost % 100 == 0) {
1019 LOG(info) << "Cost function called " << fNcallsCost << " times, current cost: " << cost
1020 << ", diff to ideal cost: " << cost - fCostIdeal << ", ndf: " << ndfTotal << ", chi2: " << chi2Total;
1021 LOG(info) << PrintParameters(DiffParameters(par, fParMC));
1022 }
1023
1024 return cost;
1025}
1026
1027// This function creates an alignment node with the given path and alignment parameters.
1028// It takes the global alignment parameters
1029std::pair<std::string, TGeoHMatrix> CbmBbaAlignTask::CreateAlignmentNode(std::string path, double shiftX, double shiftY,
1030 double shiftZ, double rotX, double rotY,
1031 double rotZ) const
1032{
1033 if (path.empty()) {
1034 LOG(fatal) << "Alignment node path is empty!";
1035 }
1036 if (path[0] != '/') {
1037 // LOG(error)
1038 // << "Alignment node path provided by the Cbm***TrackingInterface is not global. It must start with \"/\" " << path[0] << " in the path ";
1039 }
1040
1041 // alignment matrix in global coordinates
1042 TGeoHMatrix alignmentMatrix;
1043 alignmentMatrix.SetDx(shiftX);
1044 alignmentMatrix.SetDy(shiftY);
1045 alignmentMatrix.SetDz(shiftZ);
1046 alignmentMatrix.RotateX(rotX);
1047 alignmentMatrix.RotateY(rotY);
1048 alignmentMatrix.RotateZ(rotZ);
1049
1050 // Get global transformation matrix (position and rotation) of the TGeoNode at the given path
1051 if (!gGeoManager->cd(path.c_str())) {
1052 LOG(fatal) << "Failed to cd to path " << path;
1053 }
1054 const TGeoNode* node = gGeoManager->GetCurrentNode();
1055 if (!node) {
1056 LOG(fatal) << "Failed to find TGeoNode at path " << path;
1057 }
1058 TGeoHMatrix nominalGlobal = *(gGeoManager->GetCurrentMatrix());
1059 TGeoHMatrix alignedGlobal =
1060 alignmentMatrix
1061 * nominalGlobal; // TODO: make sure that the order of multiplication is correct and nominalTransformation is not altered here!
1062
1063 // get nominal transformation matrix of the mother volume
1064 gGeoManager->CdUp();
1065 TGeoHMatrix motherGlobal = *(gGeoManager->GetCurrentMatrix());
1066 // get aligned local matrix alignedLocal:
1067 // alignedGlobal = motherGlobal * alignedLocal;
1068 TGeoHMatrix alignedLocal = motherGlobal.Inverse() * alignedGlobal;
1069
1070 //extract the local alignment matrix
1071 // get original local matrix of the node
1072 TGeoHMatrix origLocal = *node->GetMatrix();
1073 // if the node matrix already contains some alignment, replace it with the original unaligned matrix
1074 {
1075 bool found = false;
1076 TObjArray* pNodes = gGeoManager->GetListOfPhysicalNodes();
1077 for (int i = 0; i < pNodes->GetEntriesFast(); i++) {
1078 const TGeoPhysicalNode* pnode = dynamic_cast<const TGeoPhysicalNode*>(pNodes->At(i));
1079 if (pnode->GetNode() == node) {
1080 // there is a physical node for this geo node -> the node already has some alignment
1081 found = true;
1082 origLocal = *pnode->GetOriginalMatrix();
1083 break;
1084 }
1085 }
1086 if (!found) {
1087 LOG(debug) << "Failed to find physical node for node " << path;
1088 }
1089 else {
1090 LOG(debug) << "Found physical node for node " << path;
1091 }
1092 }
1093
1094 // calculate the local alignment matrix alignmentLocal that includes the existing alignment
1095 // alignedLocal = alignmentLocal * origLocal
1096 TGeoHMatrix alignmentLocal = alignedLocal * origLocal.Inverse(); // TODO: check the order of multiplication!!
1097 alignmentLocal.SetName("aligned with bba (local)");
1098 origLocal.SetName("original local matrix of sensor");
1099 alignmentMatrix.SetName("alignment matrix (global)");
1100
1101 if (fair::Logger::GetConsoleSeverity() == fair::Severity::debug) {
1102 LOG(debug) << "Write alignment matrix for the node " << path << ":";
1103 alignmentMatrix.Print();
1104 origLocal.Print();
1105 alignmentLocal.Print();
1106 }
1107
1108 return {path, alignmentLocal}; // return the path and the alignment matrix in local coordinates
1109}
1110
1111// Create a pair of sensor path and alignment matrix in local coordinates for each sensor
1112std::map<std::string, TGeoHMatrix> CbmBbaAlignTask::CreateAlignmentMatrices(const std::vector<double>& par) const
1113{
1114 // create alignment matrices from the parameters
1115 std::map<std::string, TGeoHMatrix> alignmentMatrices;
1116 for (auto& s : fSensors) {
1117 // get the alignment body index
1118 int i = s.fAlignmentBody;
1119 assert(i < (int) fAlignmentBodies.size());
1120 if (i < 0) continue; // skip sensors without alignment body
1121 if (s.fNodePath.empty()) continue; // skip sensors without node path
1122 alignmentMatrices.insert(CreateAlignmentNode(s.fNodePath, par[i * kNdfBody + 0], par[i * kNdfBody + 1],
1123 par[i * kNdfBody + 2], 0., 0., 0.));
1124 }
1125 return alignmentMatrices;
1126}
1127
1128
1130{
1131 fNmvdHits = 0;
1132 fNstsHits = 0;
1133 fNmuchHits = 0;
1134 fNtrd1dHits = 0;
1135 fNtrd2dHits = 0;
1136 fNtofHits = 0;
1137 for (const auto& n : fTrack.GetNodes()) {
1138 switch (Trajectory::GetHitSystemId(n)) {
1139 case ECbmModuleId::kMvd: fNmvdHits++; break;
1140 case ECbmModuleId::kSts: fNstsHits++; break;
1141 case ECbmModuleId::kMuch: fNmuchHits++; break;
1142 case ECbmModuleId::kTrd: fNtrd1dHits++; break;
1143 case ECbmModuleId::kTrd2d: fNtrd2dHits++; break;
1144 case ECbmModuleId::kTof: fNtofHits++; break;
1145 default: break;
1146 }
1147 }
1148}
1149
1151{
1152 fOriginalHitPositions.clear();
1153 for (const auto& n : fTrack.GetNodes()) {
1154 if (n.isXySet) {
1155 fOriginalHitPositions.push_back({n.measurementXY.X(), n.measurementXY.Y(), n.z});
1156 }
1157 else {
1158 fOriginalHitPositions.push_back({0., 0., 0.});
1159 }
1160 }
1161}
TClonesArray * tracks
Task class for alignment.
Alignment body class for the BBA alignment.
@ kMvd
Micro-Vertex Detector.
Definition CbmDefs.h:47
@ kTrd
Transition Radiation Detector.
Definition CbmDefs.h:51
@ kTof
Time-of-flight Detector.
Definition CbmDefs.h:52
@ kSts
Silicon Tracking System.
Definition CbmDefs.h:48
@ kTrd2d
TRD-FASP Detector (FIXME)
Definition CbmDefs.h:58
@ kMuch
Muon detection system.
Definition CbmDefs.h:50
friend fvec sqrt(const fvec &a)
int Int_t
static int GetAlignmentBodyId(const Node &node)
std::vector< double > fParStart
std::vector< cbm::bba::AlignmentBody > CreateAndSetAlignmentBodies(AlignmentMode mode, std::vector< Sensor > &sensors) const
TClonesArray * fInputStsTracks
void ApplyAlignment(const std::vector< double > &par, std::vector< TrackContainer > &tracks, std::vector< cbm::bba::AlignmentBody > &AlignmentBodies, bool invert) const
double CostFunction(const std::vector< double > &par, std::vector< TrackContainer > &tracks)
std::vector< bba::Parameter > CreateAlignmentParameters() const
std::vector< double > fParMC
std::vector< Sensor > fSensors
unsigned SelectTracks(TClonesArray *inputTracks, std::vector< TrackContainer > &tracks)
void SetAlignment(const std::vector< double > &par, std::vector< cbm::bba::AlignmentBody > &AlignmentBodies) const
std::vector< double > InvertParameters(std::vector< double > par) const
void Exec(Option_t *opt)
AlignmentMode fAlignmentMode
std::vector< double > DiffParameters(const std::vector< double > &par1, const std::vector< double > &par2) const
Histograms fHistoBeforeAlignment
std::string PrintParameters(const std::vector< double > &par) const
void SetReferences(const std::vector< Sensor > &sensors, std::vector< TrackContainer > &tracks) const
std::vector< double > SimulateMisalignment(const std::vector< bba::Parameter > &par, std::vector< TrackContainer > &tracks, std::vector< cbm::bba::AlignmentBody > &AlignmentBodies) const
std::vector< TrackContainer > fTracks
std::vector< cbm::bba::AlignmentBody > fAlignmentBodies
std::pair< std::string, TGeoHMatrix > CreateAlignmentNode(std::string path, double shiftX, double shiftY, double shiftZ, double rotX, double rotY, double rotZ) const
TDirectory * fHistoDir
CbmKfTrackFitter< cbm::algo::kf::DoFitTime::N > fFitter
double fSimulatedMisalignmentRange
CbmBbaAlignTask(const char *name="CbmBbaAlignTask", Int_t iVerbose=0, TString histoFileName="./CbmBbaAlignmentHisto.root", size_t nMaxTracks=1000)
void WriteObjectsCurFile(TObject *obj)
void FillHistograms(const std::vector< TrackContainer > &tracks, Histograms &histo)
std::map< std::string, TGeoHMatrix > CreateAlignmentMatrices(const std::vector< double > &par) const
Histograms fHistoAfterAlignment
std::string PrintRMSE(const std::vector< bba::Parameter > &par, const std::vector< double > &parMC, const std::vector< double > &parValues) const
std::vector< Sensor > SensorsFromTracks(const std::vector< TrackContainer > &tracks) const
static ECbmModuleId GetHitSystemId(const Node &node)
static int GetHitAddress(const Node &node)
bool FitTrajectoryUpstream(const cbm::algo::kf::Trajectory< double > &t, cbm::algo::kf::TrackParamD &parUp)
fit the trajectory upstream and return the track parameters at the first measurement node
void SetIgnoreMultipleScattering(bool ignore=true)
ignore the multiple scattering effects in the fit
const algo::RecoSetup & GetSetup() const
Setup accessor.
static RecoSetupManager * Instance()
Instance access.
std::shared_ptr< const GeoNodeMap > GetGeoNodeMap() const
Access to geo node map.
const sts::RecoSetupUnit * GetSts() const
Access to STS reconstruction setup unit.
Definition RecoSetup.h:140
size_t GetNofNodes() const
Get number of nodes on the trajectory.
Node & GetNodeReference(const size_t index)
Get reference to the node by its index.
const Node & GetNode(const size_t index) const
Get const reference to the node by its index.
alignment body accessor and property handler
std::vector< std::unique_ptr< TH1F > > fResidualsY
std::vector< std::unique_ptr< TH1F > > fPullsY
std::vector< std::unique_ptr< TH1F > > fResidualsX
std::vector< std::unique_ptr< TH1F > > fPullsX
cbm::algo::kf::TrackParamD fFittedTrackParam
std::vector< std::array< double, 3 > > fOriginalHitPositions