CbmRoot
Loading...
Searching...
No Matches
CbmKfTrackFitter.cxx
Go to the documentation of this file.
1/* Copyright (C) 2023-2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergey Gorbunov [committer] */
4
5#include "CbmKfTrackFitter.h"
6
7#include "CbmGlobalTrack.h"
9#include "CbmMuchPixelHit.h"
10#include "CbmMuchTrack.h"
11#include "CbmMvdHit.h"
12#include "CbmRecoSetupManager.h"
13#include "CbmStsAddress.h"
14#include "CbmStsHit.h"
15#include "CbmStsSetup.h"
16#include "CbmStsTrack.h"
17#include "CbmTofHit.h"
18#include "CbmTofTrack.h"
19#include "CbmTrdHit.h"
20#include "CbmTrdTrack.h"
21#include "FairRootManager.h"
22#include "KFParticleDatabase.h"
23#include "KfDefs.h"
24#include "KfToolsField.h"
25#include "KfTrackKalmanFilter.h"
26#include "KfTrackParam.h"
27#include "TClonesArray.h"
28#include "TDatabasePDG.h"
29
30using std::vector;
31using namespace std;
32using namespace cbm::algo;
33
34
35template<cbm::algo::kf::DoFitTime FlagFitTime>
39
40template<cbm::algo::kf::DoFitTime FlagFitTime>
44
45template<cbm::algo::kf::DoFitTime FlagFitTime>
47{
48 FairRootManager* ioman = FairRootManager::Instance();
49
50 if (!ioman) {
51 LOG(fatal) << fDebugPrefix << "no FairRootManager";
52 }
53
54 // Get hits
55
56 fInputMvdHits = dynamic_cast<const TClonesArray*>(ioman->GetObject("MvdHit"));
57 fInputStsHits = dynamic_cast<const TClonesArray*>(ioman->GetObject("StsHit"));
58 fInputTrdHits = dynamic_cast<const TClonesArray*>(ioman->GetObject("TrdHit"));
59 fInputMuchHits = dynamic_cast<const TClonesArray*>(ioman->GetObject("MuchHit"));
60 fInputTofHits = dynamic_cast<const TClonesArray*>(ioman->GetObject("TofHit"));
61
62 // Get global tracks
63 fInputGlobalTracks = dynamic_cast<const TClonesArray*>(ioman->GetObject("GlobalTrack"));
65 // Get detector tracks
66 fInputStsTracks = dynamic_cast<const TClonesArray*>(ioman->GetObject("StsTrack"));
67 fInputMuchTracks = dynamic_cast<const TClonesArray*>(ioman->GetObject("MuchTrack"));
68 fInputTrdTracks = dynamic_cast<const TClonesArray*>(ioman->GetObject("TrdTrack"));
69 fInputTofTracks = dynamic_cast<const TClonesArray*>(ioman->GetObject("TofTrack"));
70
73 // Check Detector interfaces
74 if (!cbm::RecoSetupManager::Instance()->IsInitialized()) {
75 LOG(fatal) << "cbm::RecoSetupManager not initialized";
76 }
77 const auto& recoSetup = cbm::RecoSetupManager::Instance()->GetSetup();
79 if (fInputMvdHits && !recoSetup.GetMvd()) {
80 LOG(fatal) << "RecoSetupUnit for MVD was not provided";
81 }
82 if (fInputStsHits && !recoSetup.GetSts()) {
83 LOG(fatal) << "RecoSetupUnit for STS was not provided";
84 }
85 if (fInputMuchHits && !recoSetup.GetMuch()) {
86 LOG(fatal) << "RecoSetupUnit for MUCH was not provided";
87 }
88 if (fInputTrdHits && !recoSetup.GetTrd()) {
89 LOG(fatal) << "RecoSetupUnit for TRD was not provided";
90 }
91 if (fInputTofHits && !recoSetup.GetTof()) {
92 LOG(fatal) << "RecoSetupUnit for TOF was not provided";
93 }
94
95 //auto CheckoutDetectorUnit = [] (const auto* node, auto moduleId) {
96 // if (node && !cbm::RecoSetupManager::Instance()->GetSetup().Get<moduleId>()) {
97 // LOG(fatal) << "RecoSetupUnit for " << moduleId << " was not provided";
98 // }
99 //};
100
101 //CheckoutDetectorUnit(fInputMvdHits, ECbmModuleId::kMvd);
102 //CheckoutDetectorUnit(fInputStsHits, ECbmModuleId::kSts);
103 //CheckoutDetectorUnit(fInputMuchHits, ECbmModuleId::kMuch);
104 //CheckoutDetectorUnit(fInputTrdHits, ECbmModuleId::kTrd);
105 //CheckoutDetectorUnit(fInputTofHits, ECbmModuleId::kTof);
106
108
109 fIsInitialized = true;
110}
111
112template<cbm::algo::kf::DoFitTime FlagFitTime>
114{
115 TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(pdg);
116 if (!particlePDG) {
117 LOG(fatal) << fDebugPrefix << "particle PDG " << pdg << " is not in the data base, please set the mass manually";
118 return;
119 }
120 fMass = particlePDG->Mass();
121 fIsElectron = (abs(pdg) == 11);
122}
123
124template<cbm::algo::kf::DoFitTime FlagFitTime>
126{
127 assert(mass >= 0.);
128 fMass = mass;
129}
130
131template<cbm::algo::kf::DoFitTime FlagFitTime>
133{
134 fIsElectron = isElectron;
135}
136
137template<cbm::algo::kf::DoFitTime FlagFitTime>
139 int stsTrackIndex, bool addMaterialNodesOutsideHitRange)
140{
141 trajectory.Clear();
142
143 if (!fIsInitialized) {
144 LOG(error) << fDebugPrefix << "CbmKfTrackFitter is not initialized!";
145 return false;
146 }
147
148 if (!fInputStsTracks) {
149 LOG(error) << fDebugPrefix << "Sts track array not found!";
150 return false;
151 }
152 if (stsTrackIndex >= fInputStsTracks->GetEntriesFast()) {
153 LOG(error) << fDebugPrefix << "Sts track index " << stsTrackIndex << " is out of range!";
154 return false;
155 }
156 auto* stsTrack = dynamic_cast<const CbmStsTrack*>(fInputStsTracks->At(stsTrackIndex));
157 if (!stsTrack) {
158 LOG(error) << fDebugPrefix << "Sts track is null!";
159 return false;
160 }
162 CbmGlobalTrack globalTrack;
163 globalTrack.SetStsTrackIndex(stsTrackIndex);
164 globalTrack.SetParamFirst(*dynamic_cast<const FairTrackParam*>(stsTrack->GetParamFirst()));
165
166 return CreateFromGlobalTrack(trajectory, globalTrack, addMaterialNodesOutsideHitRange);
167}
168
169template<cbm::algo::kf::DoFitTime FlagFitTime>
171 int globalTrackIndex, bool addMaterialNodesOutsideHitRange)
172{
173 trajectory.Clear();
174
175 if (!fIsInitialized) {
176 LOG(error) << fDebugPrefix << "CbmKfTrackFitter is not initialized!";
177 return false;
178 }
179
180 if (!fInputGlobalTracks) {
181 LOG(error) << fDebugPrefix << "Global track array not found!";
182 return false;
183 }
184
185 if (globalTrackIndex >= fInputGlobalTracks->GetEntriesFast()) {
186 LOG(error) << fDebugPrefix << "Global track index " << globalTrackIndex << " is out of range!";
187 return false;
188 }
189
190 auto* globalTrack = dynamic_cast<const CbmGlobalTrack*>(fInputGlobalTracks->At(globalTrackIndex));
191 if (!globalTrack) {
192 LOG(error) << fDebugPrefix << "Global track is null!";
193 return false;
194 }
195
196 return CreateFromGlobalTrack(trajectory, *globalTrack, addMaterialNodesOutsideHitRange);
197}
198
199template<cbm::algo::kf::DoFitTime FlagFitTime>
201 bool addMaterialNodesOutsideHitRange)
202{
203 trajectory.Clear();
204 if (!fIsInitialized) {
205 LOG(error) << fDebugPrefix << "CbmKfTrackFitter is not initialized!";
206 return false;
207 }
208
210 {
211 t.fNodes.resize(fKfSetup->GetNofLayers());
212 for (int i = 0; i < fKfSetup->GetNofLayers(); i++) {
213 auto& n = t.fNodes[i];
214 n = {};
215 n.materialLayer = i;
216 n.z = fKfSetup->GetMaterial(i).GetZref();
217 n.radThick = 0.;
218 n.isFitted = false;
219 n.isXySet = false;
220 n.isTimeSet = false;
224 }
225 }
226
227 // lambda to set the node from the pixel hit
228 auto setNode = [&](const CbmPixelHit& h, int stIdx, int hitIdx, ca::EDetectorID detId) -> typename Trajectory::Node* {
229 int iLayer = fKfSetup->GetIndexMap().LocalToGlobal(detId, stIdx);
230 if (iLayer < 0) {
231 return nullptr;
232 }
233 assert(iLayer >= 0 && iLayer < fKfSetup->GetNofLayers());
234 auto& n = t.fNodes[iLayer];
235 n.z = h.GetZ();
236 n.measurementXY.SetX(h.GetX());
237 n.measurementXY.SetY(h.GetY());
238 n.measurementXY.SetDx2(h.GetDx() * h.GetDx());
239 n.measurementXY.SetDy2(h.GetDy() * h.GetDy());
240 n.measurementXY.SetDxy(h.GetDxy());
241 n.measurementXY.SetNdfX(1);
242 n.measurementXY.SetNdfY(1);
243 n.isXySet = true;
244 n.measurementTime.SetT(h.GetTime());
245 n.measurementTime.SetDt2(h.GetTimeError() * h.GetTimeError());
246 n.measurementTime.SetNdfT(1);
247 n.isTimeSet = (detId != ca::EDetectorID::kMvd);
248 n.radThick = 0.;
250 Trajectory::SetHitAddress(n, h.GetAddress());
251 Trajectory::SetHitIndex(n, hitIdx);
252 return &n;
253 };
254
255 // Read MVD & STS hits
256
257 if (globalTrack.GetStsTrackIndex() >= 0) {
258
259 int stsTrackIndex = globalTrack.GetStsTrackIndex();
260
261 if (!fInputStsTracks) {
262 LOG(error) << fDebugPrefix << "Sts track array not found!";
263 return false;
264 }
265 if (stsTrackIndex >= fInputStsTracks->GetEntriesFast()) {
266 LOG(error) << fDebugPrefix << "Sts track index " << stsTrackIndex << " is out of range!";
267 return false;
268 }
269 auto* stsTrack = dynamic_cast<const CbmStsTrack*>(fInputStsTracks->At(stsTrackIndex));
270 if (!stsTrack) {
271 LOG(error) << fDebugPrefix << "Sts track is null!";
272 return false;
273 }
274
275 // Read MVD hits
276
277 int nMvdHits = stsTrack->GetNofMvdHits();
278 if (nMvdHits > 0) {
279 if (!fInputMvdHits) {
280 LOG(error) << fDebugPrefix << " Mvd hit array not found!";
281 return false;
282 }
283 const auto* pRecoUnit = cbm::RecoSetupManager::Instance()->GetSetup().GetMvd();
284 for (int ih = 0; ih < nMvdHits; ih++) {
285 int hitIndex = stsTrack->GetMvdHitIndex(ih);
286 if (hitIndex >= fInputMvdHits->GetEntriesFast()) {
287 LOG(error) << fDebugPrefix << " Mvd hit index " << hitIndex << " is out of range!";
288 return false;
289 }
290 const auto& hit = *dynamic_cast<const CbmMvdHit*>(fInputMvdHits->At(hitIndex));
291 setNode(hit, pRecoUnit->GetTrackingStationId(hit.GetAddress()), hitIndex, ca::EDetectorID::kMvd);
292 }
293 }
294
295 // Read STS hits
296
297 int nStsHits = stsTrack->GetNofStsHits();
298 if (nStsHits > 0) {
299 if (!fInputStsHits) {
300 LOG(error) << fDebugPrefix << " Sts hit array not found!";
301 return false;
302 }
303 const auto* pRecoUnit = cbm::RecoSetupManager::Instance()->GetSetup().GetSts();
304 for (int ih = 0; ih < nStsHits; ih++) {
305 int hitIndex = stsTrack->GetStsHitIndex(ih);
306 if (hitIndex >= fInputStsHits->GetEntriesFast()) {
307 LOG(error) << fDebugPrefix << " Sts hit index " << hitIndex << " is out of range!";
308 return false;
309 }
310 const auto& hit = *dynamic_cast<const CbmStsHit*>(fInputStsHits->At(hitIndex));
311 setNode(hit, pRecoUnit->GetTrackingStationId(hit.GetAddress()), hitIndex, ca::EDetectorID::kSts);
312 }
313 }
314 } // MVD & STS hits
315
316
317 // Read Much hits
318
319 if (globalTrack.GetMuchTrackIndex() >= 0) {
320 int muchTrackIndex = globalTrack.GetMuchTrackIndex();
321 if (!fInputMuchTracks) {
322 LOG(error) << fDebugPrefix << "Much track array not found!";
323 return false;
324 }
325 if (muchTrackIndex >= fInputMuchTracks->GetEntriesFast()) {
326 LOG(error) << fDebugPrefix << "Much track index " << muchTrackIndex << " is out of range!";
327 return false;
328 }
329 auto* track = dynamic_cast<const CbmMuchTrack*>(fInputMuchTracks->At(muchTrackIndex));
330 if (!track) {
331 LOG(error) << fDebugPrefix << "Much track is null!";
332 return false;
333 }
334 int nHits = track->GetNofHits();
335 if (nHits > 0) {
336 if (!fInputMuchHits) {
337 LOG(error) << fDebugPrefix << "Much hit array not found!";
338 return false;
339 }
340 const auto* pRecoUnit = cbm::RecoSetupManager::Instance()->GetSetup().GetMuch();
341 for (int ih = 0; ih < nHits; ih++) {
342 int hitIndex = track->GetHitIndex(ih);
343 if (hitIndex >= fInputMuchHits->GetEntriesFast()) {
344 LOG(error) << fDebugPrefix << "Much hit index " << hitIndex << " is out of range!";
345 return false;
346 }
347 const auto& hit = *dynamic_cast<const CbmMuchPixelHit*>(fInputMuchHits->At(hitIndex));
348 setNode(hit, pRecoUnit->GetTrackingStationId(hit.GetAddress()), hitIndex, ca::EDetectorID::kMuch);
349 }
350 }
351 }
352
353 // Read TRD hits
354
355 if (globalTrack.GetTrdTrackIndex() >= 0) {
356 int trdTrackIndex = globalTrack.GetTrdTrackIndex();
357 if (!fInputTrdTracks) {
358 LOG(error) << fDebugPrefix << "Trd track array not found!";
359 return false;
360 }
361 if (trdTrackIndex >= fInputTrdTracks->GetEntriesFast()) {
362 LOG(error) << fDebugPrefix << "Trd track index " << trdTrackIndex << " is out of range!";
363 return false;
364 }
365 auto* track = dynamic_cast<const CbmTrdTrack*>(fInputTrdTracks->At(trdTrackIndex));
366 if (!track) {
367 LOG(error) << fDebugPrefix << "Trd track is null!";
368 return false;
369 }
370 int nHits = track->GetNofHits();
371 if (nHits > 0) {
372 if (!fInputTrdHits) {
373 LOG(error) << fDebugPrefix << "Trd hit array not found!";
374 return false;
375 }
376 const auto* pRecoUnit = cbm::RecoSetupManager::Instance()->GetSetup().GetTrd();
377 for (int ih = 0; ih < nHits; ih++) {
378 int hitIndex = track->GetHitIndex(ih);
379 if (hitIndex >= fInputTrdHits->GetEntriesFast()) {
380 LOG(error) << fDebugPrefix << "Trd hit index " << hitIndex << " is out of range!";
381 return false;
382 }
383 const auto& hit = *dynamic_cast<const CbmTrdHit*>(fInputTrdHits->At(hitIndex));
384 auto* node = setNode(hit, pRecoUnit->GetTrackingStationId(hit.GetAddress()), hitIndex, ca::EDetectorID::kTrd);
385
386 if (node != nullptr && hit.GetClassType() == 1) {
388 }
389 }
390 }
391 }
392
393
394 // Read TOF hits
395
396 if (globalTrack.GetTofTrackIndex() >= 0) {
397 int tofTrackIndex = globalTrack.GetTofTrackIndex();
398 if (!fInputTofTracks) {
399 LOG(error) << fDebugPrefix << "Tof track array not found!";
400 return false;
401 }
402 if (tofTrackIndex >= fInputTofTracks->GetEntriesFast()) {
403 LOG(error) << fDebugPrefix << "Tof track index " << tofTrackIndex << " is out of range!";
404 return false;
405 }
406 auto* track = dynamic_cast<const CbmTofTrack*>(fInputTofTracks->At(tofTrackIndex));
407 if (!track) {
408 LOG(error) << fDebugPrefix << "Tof track is null!";
409 return false;
410 }
411
412 int nHits = track->GetNofHits();
413 if (nHits > 0) {
414 if (!fInputTofHits) {
415 LOG(error) << fDebugPrefix << "Tof hit array not found!";
416 return false;
417 }
418 const auto* pRecoUnit = cbm::RecoSetupManager::Instance()->GetSetup().GetTof();
419 for (int ih = 0; ih < nHits; ih++) {
420 int hitIndex = track->GetHitIndex(ih);
421 if (hitIndex >= fInputTofHits->GetEntriesFast()) {
422 LOG(error) << fDebugPrefix << "Tof hit index " << hitIndex << " is out of range!";
423 return false;
424 }
425 const auto& hit = *dynamic_cast<const CbmTofHit*>(fInputTofHits->At(hitIndex));
426 setNode(hit, pRecoUnit->GetTrackingStationId(hit.GetAddress()), hitIndex, ca::EDetectorID::kTof);
427 }
428 }
429 }
430
431 t.MakeConsistent();
432
433 if (!addMaterialNodesOutsideHitRange) { // TODO: dont create the nodes if they are not needed
434 int firstHitNode = t.fFirstMeasurementNodeId;
435 int lastHitNode = t.fLastMeasurementNodeId;
436 assert(firstHitNode >= 0 && lastHitNode >= 0);
437 t.fNodes.erase(t.fNodes.begin() + lastHitNode + 1, t.fNodes.end());
438 t.fNodes.erase(t.fNodes.begin(), t.fNodes.begin() + firstHitNode);
439 t.MakeConsistent();
440 }
441
442 trajectory = t;
443 return true;
444}
445
446
447template<cbm::algo::kf::DoFitTime FlagFitTime>
449{
450 // a special routine to filter the first measurement.
451 // the measurement errors are simply copied to the track covariance matrix
452
453 assert(n.isXySet);
454
455 const auto& mxy = n.measurementXY;
456 const auto& mt = n.measurementTime;
457
458 auto& tr = fFit.Tr();
459
460 if (fabs(tr.GetZ() - n.z) > 1.e-15) {
461 LOG(fatal) << fDebugPrefix << "Z mismatch: fitted track " << tr.GetZ() << " != node " << n.z;
462 }
463
464 tr.ResetErrors(mxy.Dx2(), mxy.Dy2(), 100., 100., 10., 1.e4, 1.e2);
465 tr.SetC10(mxy.Dxy());
466 tr.SetX(mxy.X());
467 tr.SetY(mxy.Y());
468 tr.SetZ(n.z);
469
470 if (fIgnorePoorCoordinates) { // TODO: take C10 correlation into account
471 if (mxy.NdfX() == 0) {
472 tr.SetX(n.paramDn.GetX());
473 tr.SetC00(1.e4);
474 }
475 if (mxy.NdfY() == 0) {
476 tr.SetY(n.paramDn.GetY());
477 tr.SetC11(1.e4);
478 tr.SetC10(0.);
479 }
480 }
481
482 tr.SetChiSq(0.);
483 tr.SetChiSqTime(0.);
484 tr.SetNdf(-5. + mxy.NdfX() + mxy.NdfY());
485 if (n.isTimeSet) {
486 tr.SetTime(mt.T());
487 tr.SetC55(mt.Dt2());
488 tr.SetNdfTime(-2 + 1);
489 }
490 else {
491 tr.SetNdfTime(-2);
492 }
494 tr.InitVelocityRange(0.5);
495}
496
497template<cbm::algo::kf::DoFitTime FlagFitTime>
499{
500 // add material effects
501 if (l.radThick <= 0.) {
502 return;
503 }
504
505 double tx = 0.5 * (l.linearizationDn.tx + l.linearizationUp.tx);
506 double ty = 0.5 * (l.linearizationDn.ty + l.linearizationUp.ty);
507 double msQp = 0.5 * (l.linearizationDn.qp + l.linearizationUp.qp);
508
510 msQp = fDefaultQpForMs;
511 }
512
514 fFit.MultipleScattering(l.radThick, tx, ty, msQp);
515 }
516
518 if (direction == kf::FitDirection::kDownstream) {
519 fFit.Linearization().qp = l.linearizationUp.qp;
520 }
521 else {
522 fFit.Linearization().qp = l.linearizationDn.qp;
523 }
524 fFit.EnergyLossCorrection(l.radThick, direction);
525 }
526}
527
528template<cbm::algo::kf::DoFitTime FlagFitTime>
530{
531 // (re)fit the track
532
533
534 if (fVerbosityLevel > 0) {
535 LOG(info) << fDebugPrefix << "-------- FitTrajectory ... ";
536 }
537
538
539 { // check input trajectory consistency
540
541 if (!fIsInitialized) {
542 LOG(error) << fDebugPrefix << "CbmKfTrackFitter is not initialized!";
543 return false;
544 }
545
546
547 if (t.IsFitted()) {
548 for (int in = t.GetFirstMeasurementNodeId(); in <= t.GetLastMeasurementNodeId(); in++) {
549 const auto& n = t.fNodes[in];
550 if (!n.isFitted) {
551 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fitted, but its node " << in
552 << " in the measured region is not fitted!";
553 }
554 if (n.materialLayer >= 0 && n.radThick < 0.) {
555 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fitted, but its node " << in
556 << " with material layer " << n.materialLayer
557 << " in the measured region does not have material budget set!";
558 }
559 }
560 }
561
562 if (t.IsFullyExtrapolated()) {
563 if (!t.IsFitted()) {
564 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fully extrapolated, but it is not fitted!";
565 }
566 for (unsigned int in = 0; in < t.fNodes.size(); in++) {
567 const auto& n = t.fNodes[in];
568 if (!n.isFitted) {
569 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fully extrapolated, but its node " << in
570 << " is not fitted!";
571 }
572 if (n.materialLayer >= 0 && n.radThick < 0.) {
573 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fully extrapolated, but its node " << in
574 << " with material layer " << n.materialLayer << " does not have material budget set!";
575 }
576 }
577 }
578
579 if (fIsMaterialFixed) { // check that the material budget is already set
580 if (!t.IsFitted()) {
581 LOG(fatal) << fDebugPrefix << "Material fixed flag is set, but the input trajectory is not fitted.";
582 }
583 if (!t.fIsFullyExtrapolated) {
584 LOG(fatal) << fDebugPrefix << "Material fixed flag is set, but the input trajectory is not extrapolated.";
585 }
586 }
587
588 } // check input trajectory consistency
589
590
591 bool ok = true;
592
593 bool wasFitted = t.IsFitted();
594
595 t.fIsFitted = false;
596 t.fIsFullyExtrapolated = false;
597
598 int nNodes = t.fNodes.size();
599
600 if (nNodes <= 0) {
601 LOG(warning) << fDebugPrefix << " no nodes found!";
602 return false;
603 }
604
605 if (t.GetNofMeasurements() <= 0) {
606 LOG(warning) << fDebugPrefix << "no nodes with measurements found!";
607 return false;
608 }
609
610 fFit.SetParticleMass(fMass);
611
613
614 std::vector<LinearizationAtNode> linearization(nNodes);
615
616 int firstHitNode = t.fFirstMeasurementNodeId;
617 int lastHitNode = t.fLastMeasurementNodeId;
618
619 // linearization initialization
620
621 if (wasFitted) { // take the linearization from the previously fitted trajectory
622 for (int i = firstHitNode; i <= lastHitNode; i++) {
623 linearization[i].linearizationDn = t.fNodes[i].paramDn;
624 linearization[i].linearizationUp = t.fNodes[i].paramUp;
625 linearization[i].radThick = t.fNodes[i].radThick;
626 }
627 }
628 else { // first approximation with straight line segments connecting the nodes
629 for (int i1 = firstHitNode, i2 = firstHitNode + 1; i2 <= lastHitNode; i2++) {
630 auto& n1 = t.fNodes[i1];
631 auto& n2 = t.fNodes[i2];
632 if (!n2.isXySet) {
633 continue;
634 }
635 double dz = n2.z - n1.z;
636 double dzi = (fabs(dz) > 1.e-4) ? 1. / dz : 0.;
638 double lz = n1.z;
639 l.x = n1.measurementXY.X();
640 l.y = n1.measurementXY.Y();
641 l.tx = (n2.measurementXY.X() - n1.measurementXY.X()) * dzi;
642 l.ty = (n2.measurementXY.Y() - n1.measurementXY.Y()) * dzi;
643 l.qp = 0.;
644 l.time = 0.;
646
647 for (int i = i1; i <= i2; i++) { // fill the nodes inbetween
648 auto& n = t.fNodes[i];
649 auto& nl = linearization[i];
650 l.x += l.tx * (n.z - lz);
651 l.y += l.ty * (n.z - lz);
652 lz = n.z;
653 if (i < i2 || i == lastHitNode) { // downstream parameters for i2 will be set later, except i2 == last hit node
654 nl.linearizationDn = l;
655 }
656 if (i > i1 || i == firstHitNode) { // upstream parameters for i1 are already set, except i1 == first hit node
657 nl.linearizationUp = l;
658 }
659 }
660 i1 = i2;
661 }
662 // compute material budget for each node
663 for (int in = firstHitNode; in <= lastHitNode; in++) {
664 auto& n = t.fNodes[in];
665 auto& l = linearization[in];
666 if (n.materialLayer >= 0) {
667 const kf::MaterialMap& map = fKfSetup->GetMaterial(n.materialLayer);
668 l.radThick = map.GetThicknessX0(l.linearizationDn.x, l.linearizationDn.y);
669 }
670 else {
671 l.radThick = 0.;
672 }
673 }
674 } // linearization initialization
675
676 t.fQaChi2Downstream = -1.;
677
678 auto printNode = [&](std::string str, int node) {
679 if (fVerbosityLevel > 0) {
680 LOG(info) << fDebugPrefix << str << ": node " << node << " chi2 " << fFit.Tr().GetChiSq() << " x "
681 << fFit.Tr().GetX() << " y " << fFit.Tr().GetY() << " z " << fFit.Tr().GetZ() << " tx "
682 << fFit.Tr().GetTx() << " ty " << fFit.Tr().GetTy() << " qp " << fFit.Tr().GetQp() << " time "
683 << fFit.Tr().GetTime();
684 }
685 };
686
687 // fit trajectory in the measured area in several iterations
688
689 for (int iter = 0; iter < fNofIterations && ok; iter++) {
690
691 if (fVerbosityLevel > 0) {
692 LOG(info) << fDebugPrefix << "---- Fit iteration " << iter << " ----";
693 }
694
695 { // fit downstream from the first to the last measurement
696
697 { // initialisation at the first measurement
698 auto& n = t.fNodes[firstHitNode];
699 assert(n.isXySet);
700 fFit.SetTrack(n.z, linearization[firstHitNode].linearizationDn);
702 printNode("fit downstream", firstHitNode);
703 }
704
705 for (int iNode = firstHitNode + 1; iNode <= lastHitNode && ok; iNode++) {
706
707 auto& n = t.fNodes[iNode];
708
709 // transport the partially fitted track to the current node
710 fFit.SetLinearization(linearization[iNode - 1].linearizationDn);
711 fFit.Extrapolate(n.z, field);
712
713 // measure the track at the current node
714 if (n.isXySet) {
715 fFit.FilterXY(n.measurementXY, fIgnorePoorCoordinates);
716 }
717 if (n.isTimeSet) {
718 fFit.FilterTime(n.measurementTime);
719 }
720 printNode("fit downstream", iNode);
721
722 // store the partially fitted track before the scattering
723 n.paramUp = fFit.Tr();
724
725 // add material effects
726 if (n.materialLayer >= 0) {
728 }
729
730 // store the partially fitted track after the scattering
731 n.paramDn = fFit.Tr();
732 }
733 } // fit downstream
734
735 if (!ok) {
736 break;
737 }
738
739 // store the chi2 for debugging purposes
740 t.fQaChi2Downstream = fFit.Tr().GetChiSq();
741
742 { // fit upstream with the Kalman Filter smoothing
743
744 { // initialization at the last measurement
745 auto& n = t.fNodes[lastHitNode];
746 assert(n.isXySet);
747 n.isFitted = true;
748 fFit.SetTrack(n.z, linearization[lastHitNode].linearizationUp);
750 printNode("fit upstream", lastHitNode);
751 }
752
753 for (int iNode = lastHitNode - 1; ok && (iNode > firstHitNode); iNode--) {
754
755 auto& n = t.fNodes[iNode];
756
757 // transport the partially fitted track to the current node
758 fFit.SetLinearization(linearization[iNode + 1].linearizationUp);
759 fFit.Extrapolate(n.z, field);
760
761 // combine partially fitted downstream and upstream tracks
762 ok = ok && Smooth(n.paramDn, fFit.Tr());
763
764 if (n.materialLayer >= 0) {
765 AddMaterialEffects(linearization[iNode], kf::FitDirection::kUpstream);
766 }
767
768 // combine partially fitted downstream and upstream tracks
769 ok = ok && Smooth(n.paramUp, fFit.Tr());
770 if (ok) {
771 n.isFitted = true;
772 }
773
774 // measure the track at the current node
775 if (n.isXySet) {
776 fFit.FilterXY(n.measurementXY, fIgnorePoorCoordinates);
777 }
778 if (n.isTimeSet) {
779 fFit.FilterTime(n.measurementTime);
780 }
781 printNode("fit upstream", iNode);
782 }
783
784 if (!ok) {
785 break;
786 }
787
788 { // the first measurement node
789 int iNode = firstHitNode;
790
791 auto& n = t.fNodes[iNode];
792
793 // transport the partially fitted track to the current node
794 fFit.SetLinearization(linearization[iNode + 1].linearizationUp);
795 fFit.Extrapolate(n.z, field);
796
797 // measure the track at the current node
798 if (n.isXySet) {
799 fFit.FilterXY(n.measurementXY, fIgnorePoorCoordinates);
800 }
801 if (n.isTimeSet) {
802 fFit.FilterTime(n.measurementTime);
803 }
804 printNode("fit upstream", iNode);
805 n.paramDn = fFit.Tr();
806
807 if (n.materialLayer >= 0) {
808 AddMaterialEffects(linearization[iNode], kf::FitDirection::kUpstream);
809 }
810 n.paramUp = fFit.Tr();
811 n.isFitted = true;
812 }
813 } // fit upstream
814
815 if (!ok) {
816 t.fIsFitted = false;
817 for (auto& n : t.fNodes) {
818 n.isFitted = false;
819 }
820 return false;
821 }
822
823 t.fIsFitted = true;
824
825 if (!fIsMaterialFixed) {
826 for (int in = firstHitNode; in <= lastHitNode; in++) {
827 auto& n = t.fNodes[in];
828 if (n.materialLayer >= 0) {
829 const kf::MaterialMap& map = fKfSetup->GetMaterial(n.materialLayer);
830 n.radThick = map.GetThicknessX0(n.paramDn.GetX(), n.paramDn.GetY());
831 }
832 else {
833 n.radThick = 0.;
834 }
835 }
836 }
837 } // fit iterations
838
839
840 { // extrapolate the fitted trajectory outside the measured area downstream
841 fFit.SetTrack(t.fNodes[lastHitNode].paramDn);
842 for (int i = lastHitNode + 1; i < nNodes; i++) {
843 auto& n = t.fNodes[i];
844 fFit.Extrapolate(n.z, field);
845 if (n.materialLayer >= 0) {
846 n.radThick = fKfSetup->GetMaterial(n.materialLayer).GetThicknessX0(fFit.Tr().GetX(), fFit.Tr().GetY());
847 }
848 n.paramUp = fFit.Tr();
849 if (n.materialLayer >= 0) {
851 l.linearizationUp = fFit.Tr();
852 l.linearizationDn = fFit.Tr();
853 l.radThick = n.radThick;
855 }
856 n.paramDn = fFit.Tr();
857 n.isFitted = true;
858 }
859 }
860
861 // TODO: check when the extrapolation is failing
862
863 { // extrapolate the fitted trajectory outside the measured area upstream
864 fFit.SetTrack(t.fNodes[firstHitNode].paramUp);
865 for (int i = firstHitNode - 1; i >= 0; i--) {
866 auto& n = t.fNodes[i];
867 fFit.Extrapolate(n.z, field);
868 n.paramDn = fFit.Tr();
869 if (n.materialLayer >= 0) {
870 n.radThick = fKfSetup->GetMaterial(n.materialLayer).GetThicknessX0(fFit.Tr().GetX(), fFit.Tr().GetY());
872 l.linearizationDn = fFit.Tr();
873 l.linearizationUp = fFit.Tr();
874 l.radThick = n.radThick;
876 }
877 n.paramUp = fFit.Tr();
878 n.isFitted = true;
879 }
880 }
881
882 // distribute the final chi2, ndf to all nodes
883
884 const auto& tt = fFit.Tr();
885
886 for (int iNode = 0; iNode < nNodes; iNode++) {
887 auto& n = t.fNodes[iNode];
888 n.paramDn.SetNdf(tt.GetNdf());
889 n.paramDn.SetNdfTime(tt.GetNdfTime());
890 n.paramDn.SetChiSq(tt.GetChiSq());
891 n.paramDn.SetChiSqTime(tt.GetChiSqTime());
892 n.paramUp.SetNdf(tt.GetNdf());
893 n.paramUp.SetNdfTime(tt.GetNdfTime());
894 n.paramUp.SetChiSq(tt.GetChiSq());
895 n.paramUp.SetChiSqTime(tt.GetChiSqTime());
896 }
897
898 t.fIsFullyExtrapolated = true;
899
900 return ok;
901}
902
903
904template<cbm::algo::kf::DoFitTime FlagFitTime>
906 kf::TrackParamD& outputParam)
907{
908
909 // fit the track upstream using linearization stored in the trajectory
910
911 outputParam = kf::TrackParamD();
912
913 if (fVerbosityLevel > 0) {
914 LOG(info) << fDebugPrefix << "-------- FitTrajectoryUpstream ... ";
915 }
916
917 { // check input trajectory consistency
918
919 if (!fIsInitialized) {
920 LOG(error) << fDebugPrefix << "CbmKfTrackFitter is not initialized!";
921 return false;
922 }
923
924 if (!t.IsFitted()) {
925 LOG(fatal) << fDebugPrefix << "the input trajectory is not fitted!";
926 }
927
928 if (!t.IsFullyExtrapolated()) {
929 LOG(fatal) << fDebugPrefix << "the input trajectory is not fully extrapolated!";
930 }
931
932 for (unsigned int in = 0; in < t.fNodes.size(); in++) {
933 const auto& n = t.fNodes[in];
934 if (!n.isFitted) {
935 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fully extrapolated, but its node " << in
936 << " is not fitted!";
937 }
938 if (n.materialLayer >= 0 && n.radThick < 0.) {
939 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fully extrapolated, but its node " << in
940 << " with material layer " << n.materialLayer << " does not have material budget set!";
941 }
942 }
943 } // check input trajectory consistency
944
945 bool ok = true;
946
947 int nNodes = t.fNodes.size();
948
949 if (nNodes <= 0) {
950 LOG(warning) << fDebugPrefix << " no nodes found!";
951 return false;
952 }
953
954 if (t.GetNofMeasurements() <= 0) {
955 LOG(warning) << fDebugPrefix << "no nodes with measurements found!";
956 return false;
957 }
958
959 fFit.SetParticleMass(fMass);
960
962
963 std::vector<LinearizationAtNode> linearization(nNodes);
964
965 int lastHitNode = t.fLastMeasurementNodeId;
966
967 // linearization initialization
968 for (int i = 0; i <= lastHitNode; i++) {
969 linearization[i].linearizationDn = t.fNodes[i].paramDn;
970 linearization[i].linearizationUp = t.fNodes[i].paramUp;
971 linearization[i].radThick = t.fNodes[i].radThick;
972 }
973
974 auto printNode = [&](std::string str, int node) {
975 if (fVerbosityLevel > 0) {
976 LOG(info) << fDebugPrefix << str << ": node " << node << " chi2 " << fFit.Tr().GetChiSq() << " x "
977 << fFit.Tr().GetX() << " y " << fFit.Tr().GetY() << " z " << fFit.Tr().GetZ() << " tx "
978 << fFit.Tr().GetTx() << " ty " << fFit.Tr().GetTy() << " qp " << fFit.Tr().GetQp() << " time "
979 << fFit.Tr().GetTime();
980 }
981 };
982
983 // fit upstream
984
985 { // initialization at the last measurement
986 const auto& n = t.fNodes[lastHitNode];
987 assert(n.isXySet);
988 fFit.SetTrack(n.paramUp);
990 printNode("fit upstream", lastHitNode);
991 }
992
993 for (int iNode = lastHitNode - 1; ok && (iNode >= 0); iNode--) {
994
995 const auto& n = t.fNodes[iNode];
996
997 // transport the partially fitted track to the current node
998 fFit.SetLinearization(linearization[iNode + 1].linearizationUp);
999 fFit.Extrapolate(n.z, field);
1000
1001 if (n.materialLayer >= 0) {
1002 AddMaterialEffects(linearization[iNode], kf::FitDirection::kUpstream);
1003 }
1004
1005 // measure the track at the current node
1006 if (n.isXySet) {
1007 fFit.FilterXY(n.measurementXY, fIgnorePoorCoordinates);
1008 }
1009 if (n.isTimeSet) {
1010 fFit.FilterTime(n.measurementTime);
1011 }
1012 printNode("fit upstream", iNode);
1013 }
1014
1015 if (ok) {
1016 outputParam = fFit.Tr();
1017 }
1018
1019 return ok;
1020}
1021
1022template<cbm::algo::kf::DoFitTime FlagFitTime>
1024 kf::TrackParamD& outputParam)
1025{
1026
1027 // fit the track downstream using linearization stored in the trajectory
1028
1029 outputParam = kf::TrackParamD();
1030
1031 if (fVerbosityLevel > 0) {
1032 LOG(info) << fDebugPrefix << "-------- FitTrajectoryDownstream ... ";
1033 }
1034
1035 { // check input trajectory consistency
1036
1037 if (!fIsInitialized) {
1038 LOG(error) << fDebugPrefix << "CbmKfTrackFitter is not initialized!";
1039 return false;
1040 }
1041
1042 if (!t.IsFitted()) {
1043 LOG(fatal) << fDebugPrefix << "the input trajectory is not fitted!";
1044 }
1045
1046 if (!t.IsFullyExtrapolated()) {
1047 LOG(fatal) << fDebugPrefix << "the input trajectory is not fully extrapolated!";
1048 }
1049
1050 for (unsigned int in = 0; in < t.fNodes.size(); in++) {
1051 const auto& n = t.fNodes[in];
1052 if (!n.isFitted) {
1053 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fully extrapolated, but its node " << in
1054 << " is not fitted!";
1055 }
1056 if (n.materialLayer >= 0 && n.radThick < 0.) {
1057 LOG(fatal) << fDebugPrefix << "the input trajectory is marked as fully extrapolated, but its node " << in
1058 << " with material layer " << n.materialLayer << " does not have material budget set!";
1059 }
1060 }
1061 } // check input trajectory consistency
1062
1063 bool ok = true;
1064
1065 int nNodes = t.fNodes.size();
1066
1067 if (nNodes <= 0) {
1068 LOG(warning) << fVerbosityLevel << " no nodes found!";
1069 return false;
1070 }
1071
1072 if (t.GetNofMeasurements() <= 0) {
1073 LOG(warning) << fVerbosityLevel << "no nodes with measurements found!";
1074 return false;
1075 }
1076
1077 fFit.SetParticleMass(fMass);
1078
1080
1081 std::vector<LinearizationAtNode> linearization(nNodes);
1082
1083 int firstHitNode = t.fFirstMeasurementNodeId;
1084
1085 // linearization initialization
1086 for (int i = firstHitNode; i < nNodes; i++) {
1087 linearization[i].linearizationDn = t.fNodes[i].paramDn;
1088 linearization[i].linearizationUp = t.fNodes[i].paramUp;
1089 linearization[i].radThick = t.fNodes[i].radThick;
1090 }
1091
1092 auto printNode = [&](std::string str, int node) {
1093 if (fVerbosityLevel > 0) {
1094 LOG(info) << fDebugPrefix << str << ": node " << node << " chi2 " << fFit.Tr().GetChiSq() << " x "
1095 << fFit.Tr().GetX() << " y " << fFit.Tr().GetY() << " z " << fFit.Tr().GetZ() << " tx "
1096 << fFit.Tr().GetTx() << " ty " << fFit.Tr().GetTy() << " qp " << fFit.Tr().GetQp() << " time "
1097 << fFit.Tr().GetTime();
1098 }
1099 };
1100
1101 // fit downstream
1102
1103 { // initialization at the first measurement
1104 const auto& n = t.fNodes[firstHitNode];
1105 assert(n.isXySet);
1106 fFit.SetTrack(n.paramDn);
1108 printNode("fit downstream", firstHitNode);
1109 }
1110
1111 for (int iNode = firstHitNode + 1; ok && (iNode < nNodes); iNode++) {
1112
1113 const auto& n = t.fNodes[iNode];
1114
1115 // transport the partially fitted track to the current node
1116 fFit.SetLinearization(linearization[iNode - 1].linearizationDn);
1117 fFit.Extrapolate(n.z, field);
1118
1119 if (n.materialLayer >= 0) {
1121 }
1122
1123 // measure the track at the current node
1124 if (n.isXySet) {
1125 fFit.FilterXY(n.measurementXY, fIgnorePoorCoordinates);
1126 }
1127 if (n.isTimeSet) {
1128 fFit.FilterTime(n.measurementTime);
1129 }
1130 printNode("fit downstream", iNode);
1131 }
1132
1133 if (ok) {
1134 outputParam = fFit.Tr();
1135 }
1136 return ok;
1137}
1138
1139
1140template<cbm::algo::kf::DoFitTime FlagFitTime>
1142{
1143 // TODO: move to the CaTrackFit class
1144
1145 constexpr int nPar = kf::TrackParamD::kNtrackParam;
1146 constexpr int nCov = kf::TrackParamD::kNcovParam;
1147
1148 double r[nPar] = {t1.X(), t1.Y(), t1.Tx(), t1.Ty(), t1.Qp(), t1.Time(), t1.Vi()};
1149 double m[nPar] = {t2.X(), t2.Y(), t2.Tx(), t2.Ty(), t2.Qp(), t2.Time(), t2.Vi()};
1150
1151 double S[nCov], S1[nCov], Tmp[nCov];
1152 for (int i = 0; i < nCov; i++) {
1153 S[i] = (t1.GetCovMatrix()[i] + t2.GetCovMatrix()[i]);
1154 }
1155
1156 int nullty = 0;
1157 int ifault = 0;
1158 cbm::algo::kf::utils::math::SymInv(S, nPar, S1, Tmp, &nullty, &ifault);
1159
1160 if (fVerbosityLevel > 0 && ((0 != ifault) || (0 != nullty))) {
1161 if (fVerbosityLevel > 0) {
1162 LOG(error) << fDebugPrefix << "matrix inversion failed! ifault " << ifault << " nullty " << nullty;
1163 for (int i = 0; i < nCov; i++) {
1164 LOG(error) << fDebugPrefix << "Cov1 [" << i << "] = " << t1.GetCovMatrix()[i] << " Cov2[" << i
1165 << "] = " << t2.GetCovMatrix()[i];
1166 }
1167 for (int i = 0; i < nCov; i++) {
1168 LOG(error) << fDebugPrefix << "S[" << i << "] = " << S[i] << " S1[" << i << "] = " << S1[i];
1169 }
1170 }
1171 return false;
1172 }
1173
1174 double dzeta[nPar];
1175
1176 for (int i = 0; i < nPar; i++) {
1177 dzeta[i] = m[i] - r[i];
1178 }
1179
1180 double C[nPar][nPar];
1181 double Si[nPar][nPar];
1182 for (int i = 0, k = 0; i < nPar; i++) {
1183 for (int j = 0; j <= i; j++, k++) {
1184 C[i][j] = t1.GetCovMatrix()[k];
1185 Si[i][j] = S1[k];
1186 C[j][i] = C[i][j];
1187 Si[j][i] = Si[i][j];
1188 }
1189 }
1190
1191 // K = C * S^{-1}
1192 double K[nPar][nPar];
1193 for (int i = 0; i < nPar; i++) {
1194 for (int j = 0; j < nPar; j++) {
1195 K[i][j] = 0.;
1196 for (int k = 0; k < nPar; k++) {
1197 K[i][j] += C[i][k] * Si[k][j];
1198 }
1199 }
1200 }
1201
1202 for (int i = 0, k = 0; i < nPar; i++) {
1203 for (int j = 0; j <= i; j++, k++) {
1204 double kc = 0.; // K*C[i][j]
1205 for (int l = 0; l < nPar; l++) {
1206 kc += K[i][l] * C[l][j];
1207 }
1208 t1.CovMatrix()[k] = t1.CovMatrix()[k] - kc;
1209 }
1210 }
1211
1212 for (int i = 0; i < nPar; i++) {
1213 double kd = 0.;
1214 for (int j = 0; j < nPar; j++) {
1215 kd += K[i][j] * dzeta[j];
1216 }
1217 r[i] += kd;
1218 }
1219 t1.X() = r[0];
1220 t1.Y() = r[1];
1221 t1.Tx() = r[2];
1222 t1.Ty() = r[3];
1223 t1.Qp() = r[4];
1224 t1.Time() = r[5];
1225 t1.Vi() = r[6];
1226
1227 double chi2 = 0.;
1228 double chi2Time = 0.;
1229 for (int i = 0; i < nPar; i++) {
1230 double SiDzeta = 0.;
1231 for (int j = 0; j < nPar; j++) {
1232 SiDzeta += Si[i][j] * dzeta[j];
1233 }
1234 if (i < 5) {
1235 chi2 += dzeta[i] * SiDzeta;
1236 }
1237 else {
1238 chi2Time += dzeta[i] * SiDzeta;
1239 }
1240 }
1241 t1.SetChiSq(chi2 + t1.GetChiSq() + t2.GetChiSq());
1242 t1.SetChiSqTime(chi2Time + t1.GetChiSqTime() + t2.GetChiSqTime());
1243 t1.SetNdf(5 + t1.GetNdf() + t2.GetNdf());
1244 t1.SetNdfTime(2 + t1.GetNdfTime() + t2.GetNdfTime());
1245 return true;
1246}
1247
1248template<cbm::algo::kf::DoFitTime FlagFitTime>
1250{
1251 // propagate the track to the given Z position
1252
1253 if (!fIsInitialized) {
1254 LOG(error) << fDebugPrefix << "CbmKfTrackFitter is not initialized!";
1255 return false;
1256 }
1257
1259 fFit.SetTrack(track);
1260 auto& tr = fFit.Tr();
1261
1263
1264 auto processMaterialLayer = [&](int i) {
1265 double zMaterial = fKfSetup->GetMaterial(i).GetZref();
1266
1267 fFit.Extrapolate(zMaterial, field);
1268
1269 double radThick = fKfSetup->GetMaterial(i).GetThicknessX0(tr.GetX(), tr.GetY());
1270 double msQp = tr.GetQp();
1272 msQp = fDefaultQpForMs;
1273 }
1275 fFit.MultipleScattering(radThick, tr.GetTx(), tr.GetTy(), msQp);
1276 }
1278 fFit.EnergyLossCorrection(radThick, direction);
1279 }
1280 };
1281
1282 if (direction == kf::FitDirection::kDownstream) {
1283 for (int i = 0; i < fKfSetup->GetNofLayers(); i++) {
1284 double zMaterial = fKfSetup->GetMaterial(i).GetZref();
1285 if (zMaterial <= tr.GetZ()) {
1286 continue; // skip upstream material layers
1287 }
1288 processMaterialLayer(i);
1289 if (zMaterial > z) {
1290 break;
1291 }
1292 }
1293 }
1294 else { // upstream
1295 for (int i = fKfSetup->GetNofLayers() - 1; i >= 0; i--) {
1296 double zMaterial = fKfSetup->GetMaterial(i).GetZref();
1297 if (zMaterial >= tr.GetZ()) {
1298 continue; // skip downstream material layers
1299 }
1300 if (zMaterial < z) {
1301 break;
1302 }
1303 processMaterialLayer(i);
1304 }
1305 }
1306
1307 fFit.Extrapolate(z, field);
1308 track = fFit.Tr();
1309 return true;
1310}
1311
1312
@ kNotExist
If not found.
Definition CbmDefs.h:68
@ kTrd2d
TRD-FASP Detector (FIXME)
Definition CbmDefs.h:58
Int_t nStsHits
A container for shared tracking geo setup.
Class for pixel hits in MUCH detector.
A manager for setup representation in CBM reconstruction.
Data class for a reconstructed hit in the STS.
Data class for STS tracks.
Class for hits in TRD detector.
Common constant definitions for the Kalman Filter library.
Tracking Field class (header)
Track fit utilities for the CA tracking based on the Kalman filter.
Some class C.
Generates beam ions for transport simulation.
int32_t GetStsTrackIndex() const
int32_t GetTofTrackIndex() const
int32_t GetMuchTrackIndex() const
void SetParamFirst(const FairTrackParam *parFirst)
int32_t GetTrdTrackIndex() const
void SetStsTrackIndex(int32_t iSts)
Trajectory with hit information stored in node user references.
static void SetHitAddress(Node &node, int address)
static void SetHitSystemId(Node &node, ECbmModuleId sysId)
static void SetHitIndex(Node &node, int index)
bool PropagateToZ(cbm::algo::kf::TrackParamD &track, double z)
propagate the track in the magnetic field taking material effects into account
bool CreateFromMvdStsTrack(Trajectory &trajectory, int stsTrackIndex, bool addMaterialNodesOutsideHitRange)
void AddMaterialEffects(const LinearizationAtNode &l, cbm::algo::kf::FitDirection direction)
std::string fDebugPrefix
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
bool Smooth(cbm::algo::kf::TrackParamD &t1, const cbm::algo::kf::TrackParamD &t2)
bool fIgnoreMultipleScattering
ignore the multiple scattering effects in the fit
bool FitTrajectoryDownstream(const cbm::algo::kf::Trajectory< double > &t, cbm::algo::kf::TrackParamD &parDn)
fit the trajectory downstream and return the track parameters at the last measurement node
bool fIsMaterialFixed
true if the radiation thickness is fixed to the nodes fRadThick value and should not be recalculated ...
void SetParticleHypothesis(int pid)
set particle hypothesis (mass and electron flag) via particle PDG
void FilterFirstMeasurement(const cbm::algo::kf::Trajectory< double >::Node &n)
std::shared_ptr< const cbm::algo::kf::Setup< double > > fKfSetup
bool fIgnoreEnergyLosses
ignore the energy loss effects in the fit
bool FitTrajectory(cbm::algo::kf::Trajectory< double > &t)
fit the trajectory
void SetMassHypothesis(double mass)
set particle mass
cbm::algo::kf::TrackKalmanFilter< double, cbm::algo::kf::FilterSettings< cbm::algo::kf::LinearizationFull, FlagFitTime > > fFit
const TClonesArray * fInputTrdHits
const TClonesArray * fInputTofHits
void SetElectronFlag(bool isElectron)
set electron flag (bremmstrallung will be applied)
const TClonesArray * fInputStsHits
bool CreateFromGlobalTrack(Trajectory &trajectory, int globalTrackIndex, bool addMaterialNodesOutsideHitRange)
const TClonesArray * fInputMvdHits
const TClonesArray * fInputMuchHits
const TClonesArray * fInputGlobalTracks
data class for a reconstructed 3-d hit in the STS
Definition CbmStsHit.h:35
int32_t GetNofMvdHits() const
Definition CbmStsTrack.h:87
virtual int32_t GetNofHits() const
Definition CbmTrack.h:58
data class for a reconstructed Energy-4D measurement in the TRD
Definition CbmTrdHit.h:40
const algo::RecoSetup & GetSetup() const
Setup accessor.
static RecoSetupManager * Instance()
Instance access.
const sts::RecoSetupUnit * GetSts() const
Access to STS reconstruction setup unit.
Definition RecoSetup.h:140
const mvd::RecoSetupUnit * GetMvd() const
Access to MVD reconstruction setup unit.
Definition RecoSetup.h:136
const trd::RecoSetupUnit * GetTrd() const
Access to TRD reconstruction setup unit.
Definition RecoSetup.h:148
const much::RecoSetupUnit * GetMuch() const
Access to MuCh reconstruction setup unit.
Definition RecoSetup.h:132
const tof::RecoSetupUnit * GetTof() const
Access to TOF reconstruction setup unit.
Definition RecoSetup.h:144
Magnetic field region, corresponding to a hit triplet.
static EFieldType fgOriginalFieldType
Global field type.
static FieldFn_t fgOriginalField
Global variable to store the field function (x,y,z)->(Bx,By,Bz)
A map of station thickness in units of radiation length (X0) to the specific point in XY plane.
I GetThicknessX0(const I &x, const I &y) const
Gets material thickness in units of radiational length X0.
void SetChiSqTime(T v)
Sets Chi-square of time measurements.
T Vi() const
Gets inverse velocity [ns/cm].
const CovMatrix_t & GetCovMatrix() const
Gets covariance matrix.
static constexpr int kNtrackParam
T Tx() const
Gets slope along x-axis.
void SetChiSq(T v)
Sets Chi-square of track fit model.
T X() const
Gets x position [cm].
void SetNdf(T v)
Sets NDF of track fit model.
T GetNdfTime() const
Gets NDF of time measurements.
T Y() const
Gets y position [cm].
T GetChiSqTime() const
Gets Chi-square of time measurements.
T Qp() const
Gets charge over momentum [ec/GeV].
T GetNdf() const
Gets NDF of track fit model.
T Time() const
Gets time [ns].
void SetNdfTime(T v)
Sets NDF of time measurements.
CovMatrix_t & CovMatrix()
Reference to covariance matrix.
T GetChiSq() const
Gets Chi-square of track fit model.
T Ty() const
Gets slope along y-axis.
The class describes the particle's trajectory along its entire length.
void Clear()
Clear the trajectory.
T fQaChi2Downstream
chi2 from the downstream fit iteration, needed for QA
bool fIsFitted
true if the trajectory at all the nodes between the first and the last measurements are fitted
bool IsFullyExtrapolated() const
Check if the trajectory is extrapolated beyond the first and last measurements.
int fFirstMeasurementNodeId
index of the first node with measurement
int GetNofMeasurements() const
Get number of nodes with measurements.
void MakeConsistent()
sort the nodes in Z, add missing material layers and set fFirstMeasureNode and fLastMeasureNode
bool IsFitted() const
Check if the trajectory is fitted.
std::vector< Node > fNodes
nodes on the trajectory
int GetLastMeasurementNodeId() const
Get index of the last node with measurement.
bool fIsFullyExtrapolated
true if the trajectory is successfully extrapolated beyond the first and last measurements
int fLastMeasurementNodeId
index of the last node with measurement
int GetFirstMeasurementNodeId() const
Get index of the first node with measurement.
static TrackingGeoSetupContainer & Instance()
Instance access.
std::shared_ptr< const algo::kf::Setup< double > > GetSetup() const
Accessor to the geometry setup.
EDetectorID
Enumeration for the tracking detector subsystems in CBM-CA.
Definition CbmDefs.h:216
constexpr ECbmModuleId ToCbmModuleId(EDetectorID detID)
Conversion map from EDetectorID to ECbmModuleId.
Definition CbmDefs.h:228
constexpr auto SpeedOfLightInv
Inverse speed of light [ns/cm].
Definition KfDefs.h:210
void SymInv(const double a[], const int n, double c[], double w[], int *nullty, int *ifault)
Definition KfUtils.cxx:212
TrackParam< double > TrackParamD
void SetOriginalCbmField()
pass the original magnetic field to L1Algo
Hash for CbmL1LinkKey.
double radThick
radiation thickness of the material associated with the node
cbm::algo::kf::LinearizationFull< double > linearizationDn
fitted track parameters downstream the node
cbm::algo::kf::LinearizationFull< double > linearizationUp
fitted track parameters upstream the node
T y
y coordinate at the linearization point
T ty
ty = py/pz at the linearization point
T x
x coordinate at the linearization point
T qp
qp = q/pz at the linearization point
T vi
inverse speed at the linearization point
T time
time at the linearization point
T tx
tx = px/pz at the linearization point
The class represent a node on the trajectory.
MeasurementXy< T > measurementXY
== Measurement information ( if present )
T z
Z coordinate of the node.
TrackParam< T > paramDn
fitted track parameters downstream the node
bool isTimeSet
true if the time measurement is set
MeasurementTime< T > measurementTime
time measurement at z