CbmRoot
Loading...
Searching...
No Matches
CaTripletConstructor.cxx
Go to the documentation of this file.
1/* Copyright (C) 2010-2021 Frankfurt Institute for Advanced Studies, Goethe-Universitaet Frankfurt, Frankfurt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Igor Kulakov [committer], Maksym Zyzak, Valentina Akishina */
4
6
7#include "CaDefines.h"
8#include "CaFramework.h"
9#include "CaGridArea.h"
10
11#include <algorithm>
12#include <iostream>
13// #include "CaToolsDebugger.h"
15#include "KfTrackKalmanFilter.h"
16#include "KfTrackParam.h"
17
18// using cbm::ca::tools::Debugger;
19
20namespace cbm::algo::ca
21{
23 WindowData& wData, const fscal mass, const ca::TrackingMode& mode)
24 : fFramework(framework)
25 , fParameters(pars)
26 , fSetup(fParameters.GetActiveSetup())
27 , fField(fSetup.GetField())
28 , frWData(wData)
29 , fDefaultMass(mass)
30 , fTrackingMode(mode)
31 {
32 // FIXME: SZh 24.08.2022
33 // This approach is suitable only for a case, when all the stations inside a magnetic field come right before
34 // all the stations outside of the field!
35 // TODO: Rewrite, when the underlying data types are finalized
37 std::lower_bound(fSetup.GetActiveLayers().cbegin(), fSetup.GetActiveLayers().cbegin() + fSetup.GetNofLayers(),
38 0, // we are looking for the first zero element
39 [](const auto& s, int edge) { return s.IsInField() > edge; })
40 - fSetup.GetActiveLayers().cbegin();
41
42 fIsTargetField = !frWData.TargB().IsZero();
43 }
44
45
46 bool TripletConstructor::InitStations(int istal, int istam, int istar)
47 {
48 fIstaL = istal;
49 fIstaM = istam;
50 fIstaR = istar;
51
52 if (fIstaM >= fSetup.GetNofLayers()) {
53 return false;
54 }
55 fStaL = &fSetup.GetActiveLayer(fIstaL);
56 fStaM = &fSetup.GetActiveLayer(fIstaM);
57 fStaR = &fSetup.GetActiveLayer(fIstaR);
58
59 { // two stations for approximating the field between the target and the left hit
60 const int sta1 = (fNfieldStations <= 1) ? 1 : std::clamp(fIstaL, 1, fNfieldStations - 1);
61 const int sta0 = sta1 / 2; // station between fIstaL and the target
62
63 assert(0 <= sta0 && sta0 < sta1 && sta1 < fSetup.GetNofLayers());
64 fFldStaTL = {sta0, sta1};
65 }
66
67 { // three stations for approximating the field between the left and the right hit
68
69 int sta0 = fIstaL;
70 int sta1 = fIstaM;
71 int sta2 = fIstaM + 1;
72 if (sta2 >= fSetup.GetNofLayers()) {
73 sta2 = fIstaM;
74 sta1 = fIstaM - 1;
75 sta0 = (sta1 <= 0) ? 0 : std::clamp(sta0, 0, sta1 - 1);
76 }
77 if (fSetup.GetNofLayers() >= 3) {
78 assert(0 <= sta0 && sta0 < sta1 && sta1 < sta2 && sta2 < fSetup.GetNofLayers());
79 }
80
81 fFldStaLR = {sta0, sta1, sta2};
82 }
83 return true;
84 }
85
86
87 void TripletConstructor::CreateTripletsForHit(Vector<ca::Triplet>& tripletsOut, int istal, int istam, int istar,
88 ca::HitIndex_t iHitL)
89 {
90 if (!InitStations(istal, istam, istar)) {
91 tripletsOut.clear();
92 return;
93 }
94
96 fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass);
97 fit.Linearization().qp = frWData.CurrentIteration()->GetMaxQp();
98
99 fIhitL = iHitL;
100 const auto& hitl = frWData.Hit(fIhitL);
101
102 // fit a straight line through the target and the left hit.
103 TrackParamV& T = fit.Tr();
104 {
107 //kf::FieldValue<fvec> lB, mB, cB, rB _fvecalignment; currently not used
108 //kf::FieldValue<fvec> l_B_global, centB_global _fvecalignment; currently not used
109
110 // get the magnetic field along the track.
111 // (suppose track is straight line with origin in the target)
112 {
113 const fvec dzli = 1.f / (hitl.Z() - fSetup.GetTarget().GetZ());
114
115 T.X() = hitl.X();
116 T.Y() = hitl.Y();
117 T.Z() = hitl.Z();
118 T.Tx() = (hitl.X() - fSetup.GetTarget().GetX()) * dzli;
119 T.Ty() = (hitl.Y() - fSetup.GetTarget().GetY()) * dzli;
120 T.Qp() = fvec(0.);
121 T.Time() = hitl.T();
123
124 const fvec maxSlopePV = frWData.CurrentIteration()->GetMaxSlopePV();
125 const fvec maxQp = frWData.CurrentIteration()->GetMaxQp();
126 const fvec txErr2 = maxSlopePV * maxSlopePV / fvec(9.);
127 const fvec qpErr2 = maxQp * maxQp / fvec(9.);
128
129 T.ResetErrors(1., 1., txErr2, txErr2, qpErr2, (fStaL->IsTimeMeasured() ? hitl.dT2() : 1.e6), 1.e10);
130 T.InitVelocityRange(1. / frWData.CurrentIteration()->GetMaxQp());
131
132 T.C00() = hitl.dX2();
133 T.C10() = hitl.dXY();
134 T.C11() = hitl.dY2();
135 T.Ndf() = (frWData.CurrentIteration()->GetPrimaryFlag()) ? fvec(2.) : fvec(0.);
136 T.NdfTime() = (fStaL->IsTimeMeasured() ? 0 : -1);
137 }
138
139 // NDF = number of track parameters (6: x, y, tx, ty, qp, time)
140 // - number of measured parameters (3: x, y, time) on station or (2: x, y) on target
141
142 // field made by the left hit, the target and the station istac in-between.
143 // is used for extrapolation to the target and to the middle hit
145 {
146 kf::FieldValue<fvec> B0 = fField.GetFieldValueForLine(fFldStaTL[0], T);
147 kf::FieldValue<fvec> B1 = fField.GetFieldValueForLine(fFldStaTL[1], T);
148 fld0.Set(frWData.TargB(), B0, B1);
149 }
150
151 { // field, made by the left hit, the middle station and the right station
152 // Will be used for extrapolation to the right hit
153 kf::FieldValue<fvec> B0 = fField.GetFieldValueForLine(fFldStaLR[0], T);
154 kf::FieldValue<fvec> B1 = fField.GetFieldValueForLine(fFldStaLR[1], T);
155 kf::FieldValue<fvec> B2 = fField.GetFieldValueForLine(fFldStaLR[2], T);
156 fFldL.Set(B0, B1, B2);
157 }
158
159 // add the target constraint
160 {
161 std::array<fvec, 5> Jx, Jy;
162 fit.GetMeasurementModelAtZline(fSetup.GetTarget().GetZ(), fld0, Jx, Jy);
163 fit.FilterExtrapolatedXY(frWData.TargetMeasurement(), Jx, Jy);
164 }
165 fit.MultipleScattering(fSetup.GetMaterial(fIstaL).GetThicknessX0(T.GetX(), T.GetY()));
166
167 // extrapolate to the middle hit
168 fit.ExtrapolateLineInField(fStaM->GetZref(), fFldL);
169 }
170
172 auto FindDoubletHits = [&]() {
173 const bool matchMc = fParameters.GetConfig().DevMatchDoubletsViaMc();
174 McMatch mc = matchMc ? fFramework.GetMcMatchForCaHit(hitl.Id()) : McMatch();
175 fDoubletData.second.clear();
176 if (mc.IsEmpty() && matchMc) {
177 return;
178 }
179 CollectHits(fDoubletData.second, fit, fIstaM, frWData.CurrentIteration()->GetDoubletChi2Cut(), mc,
180 fParameters.GetConfig().GetMaxDoubletsPerSinglet());
181 };
182
183 FindDoubletHits();
184 FindDoublets(fit);
185
186 //D.Smith 28.8.24: Moving this upward (before doublet finding) changes QA output slightly
187 if (fIstaR >= fSetup.GetNofLayers()) {
188 tripletsOut.clear();
189 return;
190 }
191
193 FindTriplets();
194 SelectTriplets(tripletsOut);
195 }
196
197
199 {
200 // ---- Add the middle hits to parameters estimation ----
202 Vector<ca::HitIndex_t>& hitsM = fDoubletData.second;
203
204 tracks.clear();
205 tracks.reserve(hitsM.size());
206
207 const bool isMomentumFitted = (fIsTargetField || (fStaL->IsInField()) || (fStaM->IsInField()));
208
209 const TrackParamV Tr = fit.Tr(); // copy contents of fit
210
211 auto it2 = hitsM.begin();
212 for (auto it = hitsM.begin(); it != hitsM.end(); it++) {
213
214 const ca::HitIndex_t indM = *it;
215 const ca::Hit& hitm = frWData.Hit(indM);
216
217 if (frWData.IsHitSuppressed(indM)) {
218 continue;
219 }
220
221 TrackParamV& T2 = fit.Tr();
222 T2 = Tr;
223 fit.Linearization().qp = fvec(0.f);
224
225 fvec z_2 = hitm.Z();
226 kf::MeasurementXy<fvec> m_2(hitm.X(), hitm.Y(), hitm.dX2(), hitm.dY2(), hitm.dXY(), fvec::One(), fvec::One());
227 fvec t_2 = hitm.T();
228 fvec dt2_2 = hitm.dT2();
229
230 // add the middle hit
231 fit.ExtrapolateNoField(z_2);
232 fit.FilterXY(m_2);
233 fit.FilterTime(t_2, dt2_2, fmask(fStaM->IsTimeMeasured()));
234 fit.Linearization().qp = isMomentumFitted ? fit.Tr().GetQp() : frWData.CurrentIteration()->GetMaxQp();
235 fit.MultipleScattering(fSetup.GetMaterial(fIstaM).GetThicknessX0(T2.GetX(), T2.Y()));
236 fit.Linearization().qp = fit.Tr().GetQp();
237
238 // check if there are other hits close to the doublet on the same station
239 if (ca::kMcbm != fTrackingMode) {
240 // TODO: SG: adjust cuts, put them to parameters
241
242 const fscal tx = T2.Tx()[0];
243 const fscal ty = T2.Ty()[0];
244 const fscal tt = T2.Vi()[0] * sqrt(1. + tx * tx + ty * ty); // dt/dl * dl/dz
245
246 for (auto itClone = it + 1; itClone != hitsM.end(); itClone++) {
247
248 const int indClone = *itClone;
249 const ca::Hit& hitClone = frWData.Hit(indClone);
250
251 const fscal dz = hitClone.Z() - T2.Z()[0];
252
253 if ((fStaM->IsTimeMeasured()) && (T2.NdfTime()[0] >= 0)) {
254 const fscal dt = T2.Time()[0] + tt * dz - hitClone.T();
255 if (!(fabs(dt) <= 3.5 * sqrt(T2.C55()[0]) + hitClone.RangeT())) {
256 continue;
257 }
258 }
259
260 const fscal dx = T2.GetX()[0] + tx * dz - hitClone.X();
261 if (!(fabs(dx) <= 3.5 * sqrt(T2.C00()[0]) + hitClone.RangeX())) {
262 continue;
263 }
264
265 const fscal dy = T2.Y()[0] + ty * dz - hitClone.Y();
266 if (!(fabs(dy) <= 3.5 * sqrt(T2.C11()[0]) + hitClone.RangeY())) {
267 continue;
268 }
269
270 if (fParameters.GetConfig().DevSuppressOverlapHitsViaMc()) {
271 const auto& hitl = frWData.Hit(fIhitL);
272 auto mc = fFramework.GetMcMatchForCaHit(hitl.Id());
273 if ((mc != fFramework.GetMcMatchForCaHit(hitm.Id()))
274 || (mc != fFramework.GetMcMatchForCaHit(hitClone.Id()))) {
275 continue;
276 }
277 }
278
279 frWData.SuppressHit(indClone);
280 }
281 }
282
283 tracks.push_back(T2);
284 *it2 = indM;
285 it2++;
286 } // it
287 hitsM.shrink(std::distance(hitsM.begin(), it2));
288 }
289
290
292 {
293 //auto& [tracks_2, hitsM_2] = doublets; TO DO: Reactivate when MacOS compiler bug is fixed.
294 Vector<TrackParamV>& tracks_2 = fDoubletData.first;
295 Vector<ca::HitIndex_t>& hitsM_2 = fDoubletData.second;
296
297 Vector<ca::HitIndex_t>& hitsM_3 = std::get<1>(fTripletData);
298 Vector<ca::HitIndex_t>& hitsR_3 = std::get<2>(fTripletData);
299
303 fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass);
304 fit.Linearization().qp = fvec(0.);
305
306 {
307 const int maxTriplets = hitsM_2.size() * fParameters.GetConfig().GetMaxTripletsPerDoublet();
308 hitsM_3.clear();
309 hitsR_3.clear();
310 hitsM_3.reserve(maxTriplets);
311 hitsR_3.reserve(maxTriplets);
312 }
313 // ---- Add the middle hits to parameters estimation. Propagate to right station. ----
314
315 const double maxSlope = frWData.CurrentIteration()->GetMaxSlope();
316 const double tripletChi2Cut = frWData.CurrentIteration()->GetTripletChi2Cut();
317 for (unsigned int i2 = 0; i2 < hitsM_2.size(); i2++) {
318
319 fit.SetTrack(tracks_2[i2]);
320 TrackParamV& T2 = fit.Tr();
321
322 // extrapolate to the right hit station
323 fit.Extrapolate(fStaR->GetZref(), fFldL);
324
325 if constexpr (fDebugDublets) {
326 ca::HitIndex_t iwhit[2] = {fIhitL, hitsM_2[i2]};
327 ca::HitIndex_t ihit[2] = {frWData.Hit(iwhit[0]).Id(), frWData.Hit(iwhit[1]).Id()};
328
329 const int ih0 = ihit[0];
330 const int ih1 = ihit[1];
331 const ca::Hit& h0 = frWData.Hit(iwhit[0]);
332 const ca::Hit& h1 = frWData.Hit(iwhit[1]);
333
334 LOG(info) << "\n====== Extrapolated Doublet : "
335 << " iter " << frWData.CurrentIteration()->GetName() << " hits: {" << fIstaL << "/" << ih0 << " "
336 << fIstaM << "/" << ih1 << " " << fIstaR << "/?} xyz: {" << h0.X() << " " << h0.Y() << " " << h0.Z()
337 << "}, {" << h1.X() << " " << h1.Y() << " " << h1.Z() << "} chi2 " << T2.GetChiSq()[0] << " ndf "
338 << T2.Ndf()[0] << " chi2time " << T2.ChiSqTime()[0] << " ndfTime " << T2.NdfTime()[0];
339 LOG(info) << " extr. track: " << T2.ToString(0);
340 }
341
342 // ---- Find the triplets(right hit). Reformat data in the portion of triplets. ----
343 McMatch mc;
344
345 auto rejectDoublet = [&]() -> bool {
346 if (ca::TrackingMode::kSts == fTrackingMode && (T2.C44()[0] < 0)) {
347 return true;
348 }
349 if (T2.C00()[0] < 0 || T2.C11()[0] < 0 || T2.C22()[0] < 0 || T2.C33()[0] < 0 || T2.C55()[0] < 0) {
350 return true;
351 }
352 if (fabs(T2.Tx()[0]) > maxSlope) {
353 return true;
354 }
355 if (fabs(T2.Ty()[0]) > maxSlope) {
356 return true;
357 }
358 if (fParameters.GetConfig().DevMatchTripletsViaMc()) {
359 mc = fFramework.GetMcMatchForCaHit(frWData.Hit(fIhitL).Id());
360 auto mc1 = fFramework.GetMcMatchForCaHit(frWData.Hit(hitsM_2[i2]).Id());
361 if (mc.IsEmpty() || mc != mc1) {
362 return true;
363 }
364 }
365 return false;
366 };
367 const bool isDoubletGood = !rejectDoublet();
368
369 if constexpr (fDebugDublets) {
370 if (isDoubletGood) {
371 LOG(info) << " extrapolated doublet accepted";
372 }
373 else {
374 LOG(info) << " extrapolated doublet rejected";
375 LOG(info) << "======== end of extrapolated doublet ==== \n";
376 }
377 }
378
379 if (!isDoubletGood) {
380 continue;
381 }
382
383 Vector<ca::HitIndex_t> collectedHits;
384 CollectHits(collectedHits, fit, fIstaR, tripletChi2Cut, mc, fParameters.GetConfig().GetMaxTripletsPerDoublet());
385
386 if (static_cast<int>(collectedHits.size()) >= fParameters.GetConfig().GetMaxTripletsPerDoublet()) {
387 // FU, 28.08.2024, Comment the following log lines since it spams the output
388 // of our tests and finally results in crashes on run4
389 // LOG(debug) << "Ca: GetMaxTripletPerDoublets==" << fParameters.GetMaxTripletPerDoublets()
390 // << " reached in findTripletsStep0()";
391 // reject already created triplets for this doublet
392 collectedHits.clear();
393 }
394 if constexpr (fDebugDublets) {
395 LOG(info) << " collected " << collectedHits.size() << " hits on the right station ";
396 }
397 for (ca::HitIndex_t& irh : collectedHits) {
398 if constexpr (fDebugDublets) {
399 const ca::Hit& h = frWData.Hit(irh);
400 ca::HitIndex_t ihit = h.Id();
401 LOG(info) << " hit " << ihit << " " << h.ToString();
402 }
403 if (frWData.IsHitSuppressed(irh)) {
404 if constexpr (fDebugDublets) {
405 LOG(info) << " the hit is suppressed";
406 }
407 continue;
408 }
409 // pack the triplet
410 hitsM_3.push_back(hitsM_2[i2]);
411 hitsR_3.push_back(irh);
412 } // search area
413 if constexpr (fDebugDublets) {
414 LOG(info) << "======== end of extrapolated doublet ==== \n";
415 }
416 } // i2
417 }
418
420 {
421 constexpr int nIterations = 2;
422
424 Vector<ca::HitIndex_t>& hitsM = std::get<1>(fTripletData);
425 Vector<ca::HitIndex_t>& hitsR = std::get<2>(fTripletData);
426 assert(hitsM.size() == hitsR.size());
427
428 tracks.clear();
429 tracks.reserve(hitsM.size());
430
432 if constexpr (fDebugTriplets) {
433 //cbm::ca::tools::Debugger::Instance().AddNtuple(
434 // "triplets", "ev:iter:i0:x0:y0:z0:i1:x1:y1:z1:i2:x2:y2:z2:mc:sta:p:vx:vy:vz:chi2:ndf:chi2time:ndfTime");
435 }
436
438 fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass);
439
440 // prepare data
441 constexpr int NHits = 3; // triplets
442 const int ista[NHits] = {fIstaL, fIstaM, fIstaR};
443
444 std::array<kf::ActiveLayer<fvec>, NHits> sta = {fSetup.GetActiveLayer(ista[0]), fSetup.GetActiveLayer(ista[1]),
445 fSetup.GetActiveLayer(ista[2])};
446
447 const bool isMomentumFitted = ((fStaL->IsInField()) || (fStaM->IsInField()) || (fStaR->IsInField()));
448 const fvec ndfTrackModel = 4 + (isMomentumFitted ? 1 : 0); // straight line or track with momentum
449
450 for (size_t i3 = 0; i3 < hitsM.size(); ++i3) {
451
452 // prepare data
453 const ca::HitIndex_t iwhit[NHits] = {fIhitL, hitsM[i3], hitsR[i3]};
454
455 const ca::HitIndex_t ihit[NHits] = {frWData.Hit(iwhit[0]).Id(), frWData.Hit(iwhit[1]).Id(),
456 frWData.Hit(iwhit[2]).Id()};
457
458 if (fParameters.GetConfig().DevMatchTripletsViaMc()) {
459 int mc1 = fFramework.GetBestMcTrackIdForCaHit(ihit[0]);
460 int mc2 = fFramework.GetBestMcTrackIdForCaHit(ihit[1]);
461 int mc3 = fFramework.GetBestMcTrackIdForCaHit(ihit[2]);
462 if ((mc1 != mc2) || (mc1 != mc3)) {
463 // D.S.: Added to preserve the ordering when switching from index-based
464 // access to push_back(). Discuss with SZ.
465 tracks.push_back(TrackParamV());
466 continue;
467 }
468 }
469
470 fscal x[NHits], y[NHits], z[NHits], t[NHits];
471 fscal dt2[NHits];
472 kf::MeasurementXy<fvec> mxy[NHits];
473
474 for (int ih = 0; ih < NHits; ++ih) {
475 const ca::Hit& hit = frWData.Hit(iwhit[ih]);
476 mxy[ih] = kf::MeasurementXy<fvec>(hit.X(), hit.Y(), hit.dX2(), hit.dY2(), hit.dXY(), fvec::One(), fvec::One());
477
478 x[ih] = hit.X();
479 y[ih] = hit.Y();
480 z[ih] = hit.Z();
481 t[ih] = hit.T();
482 dt2[ih] = hit.dT2();
483 };
484
485 // find the field along the track
486
490
491 fvec tx[3] = {(x[1] - x[0]) / (z[1] - z[0]), (x[2] - x[0]) / (z[2] - z[0]), (x[2] - x[1]) / (z[2] - z[1])};
492 fvec ty[3] = {(y[1] - y[0]) / (z[1] - z[0]), (y[2] - y[0]) / (z[2] - z[0]), (y[2] - y[1]) / (z[2] - z[1])};
493
494 for (int ih = 0; ih < NHits; ++ih) {
495 fvec dz = (sta[ih].GetZref() - z[ih]);
496 B[ih] = fField.GetFieldValue(ista[ih], x[ih] + tx[ih] * dz, y[ih] + ty[ih] * dz);
497 };
498
499 fld.Set(B[0], B[1], B[2]);
500 fldTarget.Set(frWData.TargB(), B[0], B[1]);
501
502 TrackParamV& T = fit.Tr();
503
504 // initial parameters
505 {
506 fvec dz01 = 1. / (z[1] - z[0]);
507 T.Tx() = (x[1] - x[0]) * dz01;
508 T.Ty() = (y[1] - y[0]) * dz01;
509 T.Qp() = 0.;
510 T.Vi() = 0.;
511 }
512
513 // repeat several times in order to improve the precision
514 for (int iiter = 0; iiter < nIterations; ++iiter) {
515
516 auto fitTrack = [&](int startIdx, int endIdx, int step, kf::FitDirection direction) {
517 const fvec maxQp = frWData.CurrentIteration()->GetMaxQp();
519 lin.qp = T.Qp();
520 lin.qp(lin.qp > maxQp) = maxQp;
521 lin.qp(lin.qp < -maxQp) = -maxQp;
522 fit.SetLinearization(lin);
523
524 int ih0 = startIdx;
525 T.X() = x[ih0];
526 T.Y() = y[ih0];
527 T.Z() = z[ih0];
528 T.Time() = t[ih0];
529 T.Qp() = 0.;
531
532 T.ResetErrors(1., 1., 1., 1., 100., (sta[ih0].IsTimeMeasured() ? dt2[ih0] : 1.e6), 1.e2);
533 T.C00() = mxy[ih0].Dx2();
534 T.C10() = mxy[ih0].Dxy();
535 T.C11() = mxy[ih0].Dy2();
536 T.InitVelocityRange(0.5);
537
538 T.Ndf() = -ndfTrackModel + 2;
539 T.NdfTime() = sta[ih0].IsTimeMeasured() ? 0 : -1;
540
541 if (startIdx == 0) { //only for the forward fit
542 //fit.FilterWithTargetAtLine(fSetup.GetTarget().GetZ(), frWData.TargetMeasurement(), fldTarget);
543 std::array<fvec, 5> Jx, Jy;
544 fit.GetMeasurementModelAtZline(fSetup.GetTarget().GetZ(), fldTarget, Jx, Jy);
545 fit.FilterExtrapolatedXY(frWData.TargetMeasurement(), Jx, Jy);
546 }
547
548 for (int ih = startIdx + step; ih != endIdx; ih += step) {
549 fit.Extrapolate(z[ih], fld);
550 auto radThick = fSetup.GetMaterial(ista[ih]).GetThicknessX0(T.X(), T.Y());
551 fit.MultipleScattering(radThick);
552 fit.EnergyLossCorrection(radThick, direction);
553 fit.FilterXY(mxy[ih]);
554 fit.FilterTime(t[ih], dt2[ih], fmask(sta[ih].IsTimeMeasured()));
555 }
556 };
557
558 // Fit downstream
559 fitTrack(0, NHits, 1, kf::FitDirection::kDownstream);
560
561 if (iiter == nIterations - 1) break;
562
563 // Fit upstream
564 fitTrack(NHits - 1, -1, -1, kf::FitDirection::kUpstream);
565 } // for iiter
566
567 tracks.push_back(T);
568
569 if constexpr (fDebugTriplets) {
570 int ih0 = ihit[0];
571 int ih1 = ihit[1];
572 int ih2 = ihit[2];
573 int mc1 = fFramework.GetBestMcTrackIdForCaHit(ih0);
574 int mc2 = fFramework.GetBestMcTrackIdForCaHit(ih1);
575 int mc3 = fFramework.GetBestMcTrackIdForCaHit(ih2);
576
577 if (1 || (mc1 >= 0) && (mc1 == mc2) && (mc1 == mc3)) {
578 const ca::Hit& h0 = frWData.Hit(iwhit[0]);
579 const ca::Hit& h1 = frWData.Hit(iwhit[1]);
580 const ca::Hit& h2 = frWData.Hit(iwhit[2]);
581 //const CbmL1MCTrack& mctr = CbmL1::Instance()->GetMcTracks()[mc1];
582 LOG(info) << "== fitted triplet: "
583 << " iter " << frWData.CurrentIteration()->GetName() << " hits: {" << fIstaL << "/" << ih0 << " "
584 << fIstaM << "/" << ih1 << " " << fIstaR << "/" << ih2 << "} xyz: {" << h0.X() << " " << h0.Y()
585 << " " << h0.Z() << "}, {" << h1.X() << " " << h1.Y() << " " << h1.Z() << "}, {" << h2.X() << ", "
586 << h2.Y() << ", " << h2.Z() << "} chi2 " << T.GetChiSq()[0] << " ndf " << T.Ndf()[0] << " chi2time "
587 << T.ChiSqTime()[0] << " ndfTime " << T.NdfTime()[0];
588 /*
589 cbm::ca::tools::Debugger::Instance().FillNtuple(
590 "triplets", mctr.iEvent, frAlgo.fCurrentIterationIndex, ih0, h0.X(), h0.Y(), h0.Z(), ih1, h1.X(), h1.Y(),
591 h1.Z(), ih2, h2.X(), h2.Y(), h2.Z(), mc1, fIstaL, mctr.p, mctr.x, mctr.y, mctr.z, (fscal) T.GetChiSq()[0],
592 (fscal) T.Ndf()[0], (fscal) T.ChiSqTime()[0], (fscal) T.NdfTime()[0]);
593 */
594 }
595 }
596 } //i3
597 } // FindTriplets
598
599
601 {
604
606 Vector<ca::HitIndex_t>& hitsM = std::get<1>(fTripletData);
607 Vector<ca::HitIndex_t>& hitsR = std::get<2>(fTripletData);
608
609 bool isMomentumFitted = ((fStaL->IsInField()) || (fStaM->IsInField()) || (fStaR->IsInField()));
610
611 tripletsOut.clear();
612 tripletsOut.reserve(hitsM.size());
613
614 for (size_t i3 = 0; i3 < hitsM.size(); ++i3) {
615
616 TrackParamV& T3 = tracks[i3];
617
618 // TODO: SG: normalize chi2, separate cuts on time and space
619
620 const fscal chi2 = T3.GetChiSq()[0] + T3.GetChiSqTime()[0];
621
622 const ca::HitIndex_t ihitl = fIhitL;
623 const ca::HitIndex_t ihitm = hitsM[i3];
624 const ca::HitIndex_t ihitr = hitsR[i3];
625
626 CBMCA_DEBUG_ASSERT(ihitl < frWData.HitStartIndexOnStation(fIstaL + 1));
627 CBMCA_DEBUG_ASSERT(ihitm < frWData.HitStartIndexOnStation(fIstaM + 1));
628 CBMCA_DEBUG_ASSERT(ihitr < frWData.HitStartIndexOnStation(fIstaR + 1));
629
630 if (!frWData.CurrentIteration()->GetTrackFromTripletsFlag()) {
631 if (chi2 > frWData.CurrentIteration()->GetTripletFinalChi2Cut()) {
632 continue;
633 }
634 }
635 // assert(std::isfinite(chi2) && chi2 > 0);
636
637 if (!std::isfinite(chi2) || chi2 < 0) {
638 continue;
639 }
640 //if (!T3.IsEntryConsistent(true, 0)) { continue; }
641
642 fscal qp = T3.Qp()[0];
643 fscal Cqp = T3.C44()[0];
644
645 // TODO: SG: a magic correction that comes from the legacy code
646 // removing it leads to a higher ghost ratio
647 Cqp += 0.001;
648
649 tripletsOut.emplace_back(ihitl, ihitm, ihitr, fIstaL, fIstaM, fIstaR, 0, 0, 0, chi2, qp, Cqp, T3.Tx()[0],
650 T3.C22()[0], T3.Ty()[0], T3.C33()[0], isMomentumFitted);
651 }
652 }
653
654
656 const int iSta, const double chi2Cut, const McMatch& mc, const int maxNhits)
657 {
659 collectedHits.clear();
660 collectedHits.reserve(maxNhits);
661
662 const kf::ActiveLayer<fvec>& sta = fSetup.GetActiveLayer(iSta);
663
664 TrackParamV& T = fit.Tr();
665 //LOG(info) << T.chi2[0] ;
666 T.ChiSq() = 0.;
667
668 // if make it bigger the found hits will be rejected later because of the chi2 cut.
669 const fvec Pick_m22 = (fvec(chi2Cut) - T.GetChiSq());
670 const fscal timeError2 = T.C55()[0];
671 const fscal time = T.Time()[0];
672
673 const auto& grid = frWData.Grid(iSta);
674 const fvec maxDZ = frWData.CurrentIteration()->GetMaxDZ();
675 ca::GridArea area(grid, T.X()[0], T.Y()[0],
676 (sqrt(Pick_m22 * T.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(T.Tx()))[0],
677 (sqrt(Pick_m22 * T.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(T.Ty()))[0]);
678 if constexpr (fDebugCollectHits) {
679 LOG(info) << "search area: " << T.X()[0] << " " << T.Y()[0] << " "
680 << (sqrt(Pick_m22 * T.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(T.Tx()))[0] << " "
681 << (sqrt(Pick_m22 * T.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(T.Ty()))[0];
682 }
683 if (fParameters.GetConfig().DevIgnoreHitSearchAreas()) {
685 }
686
687 // loop over station hits (index incremented in condition)
688 for (ca::HitIndex_t ih = 0; area.GetNextObjectId(ih) && ((int) collectedHits.size() < maxNhits);) {
689
690 if (frWData.IsHitSuppressed(ih)) {
691 continue;
692 }
693
694 const ca::Hit& hit = frWData.Hit(ih);
695 if constexpr (fDebugCollectHits) {
696 LOG(info) << "hit in the search area: " << hit.ToString();
697 LOG(info) << " check the hit.. ";
698 }
699
700 if (!mc.IsEmpty()) { // match via MC
701 if (mc != fFramework.GetMcMatchForCaHit(hit.Id())) {
702 if constexpr (fDebugCollectHits) {
703 LOG(info) << " hit mc does not match";
704 }
705 continue;
706 }
707 }
708
709 // check time-boundaries
710
711 //TODO: move hardcoded cuts to parameters
712 if (sta.IsTimeMeasured() && (T.NdfTime()[0] >= 0)) {
713 if (fabs(time - hit.T()) > 1.4 * (3.5 * sqrt(timeError2) + hit.RangeT())) {
714 if constexpr (fDebugCollectHits) {
715 LOG(info) << " hit time does not match";
716 }
717 continue;
718 }
719 // if (fabs(time - hit.T()) > 30) continue;
720 }
721
722 // - check whether hit belong to the window ( track position +\- errors ) -
723 const fscal z = hit.Z();
724
725 // check y-boundaries
726 const auto [y, C11] = fit.ExtrapolateLineYdY2(z);
727 const fscal dy_est = sqrt(Pick_m22[0] * C11[0]) + hit.RangeY();
728 const fscal dY = hit.Y() - y[0];
729
730 if (fabs(dY) > dy_est) {
731 if constexpr (fDebugCollectHits) {
732 LOG(info) << " hit Y does not match";
733 }
734 continue;
735 }
736
737 // check x-boundaries
738 const auto [x, C00] = fit.ExtrapolateLineXdX2(z);
739 const fscal dx_est = sqrt(Pick_m22[0] * C00[0]) + hit.RangeX();
740 const fscal dX = hit.X() - x[0];
741
742 if (fabs(dX) > dx_est) {
743 if constexpr (fDebugCollectHits) {
744 LOG(info) << " hit X does not match";
745 }
746 continue;
747 }
748
749 // check chi2
750 kf::MeasurementXy<fvec> mxy(hit.X(), hit.Y(), hit.dX2(), hit.dY2(), hit.dXY(), fvec::One(), fvec::One());
751
752 const fvec C10 = fit.ExtrapolateLineDxy(z);
753 const auto [chi2x, chi2u] = kf::TrackKalmanFilter<fvec>::GetChi2XChi2U(mxy, x, y, C00, C10, C11);
754
755 // TODO: adjust the cut, cut on chi2x & chi2u separately
756 if (!frWData.CurrentIteration()->GetTrackFromTripletsFlag()) {
757 if (chi2x[0] > chi2Cut) {
758 if constexpr (fDebugCollectHits) {
759 LOG(info) << " hit chi2X is too large";
760 }
761 continue;
762 }
763 if (chi2u[0] > chi2Cut) {
764 if constexpr (fDebugCollectHits) {
765 LOG(info) << " hit chi2U is too large";
766 }
767 continue;
768 }
769 }
770 if constexpr (fDebugCollectHits) {
771 LOG(info) << " hit passed all the checks";
772 }
773 collectedHits.push_back(ih);
774
775 } // loop over the hits in the area
776 }
777} // namespace cbm::algo::ca
TClonesArray * tracks
Macros for the CA tracking algorithm.
#define CBMCA_DEBUG_ASSERT(v)
Definition CaDefines.h:40
Triplet constructor for the CA tracker.
friend fvec sqrt(const fvec &a)
Track fit utilities for the CA tracking based on the Kalman filter.
Some class B.
Generates beam ions for transport simulation.
Class for accessing objects in the 2D area that are stored in ca::Grid.
Definition CaGridArea.h:17
bool GetNextObjectId(ca::HitIndex_t &objectId)
look up the next object id in the requested area
Definition CaGridArea.h:92
void DoLoopOverEntireGrid()
debug mode: loop over the entire GetEntries() vector ignoring the search area
Definition CaGridArea.h:103
ca::Hit class describes a generic hit for the CA tracker
Definition CaHit.h:32
fscal Z() const
Get the Z coordinate.
Definition CaHit.h:108
fscal RangeX() const
Get the +/- range of uncertainty of X coordinate.
Definition CaHit.h:126
fscal dT2() const
Get the uncertainty of time.
Definition CaHit.h:123
std::string ToString() const
Simple string representation of the hit class.
Definition CaHit.cxx:17
fscal dXY() const
Get the X/Y covariance.
Definition CaHit.h:120
fscal dX2() const
Get the uncertainty of X coordinate.
Definition CaHit.h:114
fscal Y() const
Get the Y coordinate.
Definition CaHit.h:105
fscal RangeY() const
Get the +/- range of uncertainty of Y coordinate.
Definition CaHit.h:129
fscal RangeT() const
Get the +/- range of uncertainty of time.
Definition CaHit.h:132
fscal T() const
Get the time.
Definition CaHit.h:111
fscal X() const
Get the X coordinate.
Definition CaHit.h:102
HitIndex_t Id() const
Get the hit id.
Definition CaHit.h:135
fscal dY2() const
Get the uncertainty of Y coordinate.
Definition CaHit.h:117
A container for all external parameters of the CA tracking algorithm.
const kf::ActiveLayer< fvec > * fStaL
left station
const cbm::algo::kf::Setup< fvec > & fSetup
Reference to the setup.
const Parameters< fvec > & fParameters
Object of Framework parameters class.
void SelectTriplets(Vector< ca::Triplet > &tripletsOut)
Select good triplets.
void CreateTripletsForHit(Vector< ca::Triplet > &tripletsOut, int istal, int istam, int istar, ca::HitIndex_t ihl)
---— FUNCTIONAL PART ---—
fscal fDefaultMass
mass of the propagated particle [GeV/c2]
const kf::ActiveLayer< fvec > * fStaR
right station
const ca::Framework & fFramework
Reference to the Framework object.
TripletConstructor(const ca::Framework &framework, const ca::Parameters< fvec > &pars, WindowData &wData, const fscal mass, const ca::TrackingMode &mode)
---— Constructors and destructor ---—
bool InitStations(int istal, int istam, int istar)
const cbm::algo::kf::Field< fvec > & fField
Reference to field.
void FindDoublets(kf::TrackKalmanFilter< fvec > &fit)
Find the doublets. Reformat data in the portion of doublets.
std::array< int, 2 > fFldStaTL
indices of two stations for field approximation between the t. and l. hit
void FindTriplets()
Find triplets on station.
void CollectHits(Vector< ca::HitIndex_t > &collectedHits, kf::TrackKalmanFilter< fvec > &fit, const int iSta, const double chi2Cut, const McMatch &mc, const int maxNhits)
std::array< int, 3 > fFldStaLR
indices of three stations for field approximation between the l. and r. hits
const kf::ActiveLayer< fvec > * fStaM
mid station
ca::HitIndex_t fIhitL
index of the left hit in fAlgo->fWindowHits
bool fIsTargetField
is the magnetic field present at the target
void shrink(std::size_t count)
Reduces the vector to a given size.
Definition CaVector.h:164
void push_back(Tinput value)
Pushes back a value to the vector.
Definition CaVector.h:190
void reserve(std::size_t count)
Reserves a new size for the vector.
Definition CaVector.h:176
void emplace_back(Tinput &&... value)
Creates a parameter in the end of the vector.
Definition CaVector.h:210
Container for internal data, processed on a single time window.
Properties of an active surface of the layer.
bool IsTimeMeasured() const
Checks, if time measurement available.
Magnetic field region, corresponding to a hit triplet.
void Set(const FieldValue< T > &b0, const FieldValue< T > &b1, const FieldValue< T > &b2)
Interpolates the field by three nodal points with the second order polynomial.
Magnetic flux density vector.
The class describes a 2D - measurement (x, y) in XY coordinate system.
void FilterTime(DataT t, DataT dt2, const DataTmask &m)
filter the track with the time measurement
DataT ExtrapolateLineDxy(DataT z_out) const
void EnergyLossCorrection(DataT radThick, FitDirection direction)
void ExtrapolateNoField(DataT z)
extrapolate the track to the given Z assuming no magnetic field
void FilterExtrapolatedXY(const kf::MeasurementXy< DataT > &m, const std::array< DataT, 5 > &Jx, const std::array< DataT, 5 > &Jy)
void SetLinearization(const Linearization_t &lin)
void Extrapolate(DataT z, const kf::FieldRegion< DataT > &F)
void MultipleScattering(DataT radThick, DataT tx0, DataT ty0, DataT qp0)
apply multiple scattering correction to the track with the given Qp0
void SetParticleMass(DataT mass)
set particle mass for the fit
kf::TrackParam< DataT > & Tr()
static std::tuple< DataT, DataT > GetChi2XChi2U(kf::MeasurementXy< DataT > m, DataT x, DataT y, DataT C00, DataT C10, DataT C11)
git two chi^2 components of the track fit to measurement
void FilterXY(const kf::MeasurementXy< DataT > &m, bool skipUnmeasuredCoordinates=false)
filter the track with the XY measurement
void SetTrack(const kf::TrackParam< T > &t)
std::pair< DataT, DataT > ExtrapolateLineXdX2(DataT z_out) const
std::pair< DataT, DataT > ExtrapolateLineYdY2(DataT z_out) const
void ExtrapolateLineInField(DataT z_out, const kf::FieldRegion< DataT > &F)
extrapolate the track to the given Z using linearization at the straight line
void GetMeasurementModelAtZline(DataT zm, const kf::FieldRegion< DataT > &Field, std::array< DataT, 5 > &Jx, std::array< DataT, 5 > &Jy) const
extrapolate track as a line, return the extrapolated X, Y and the Jacobians
T ChiSq() const
Gets Chi-square of track fit model.
T GetQp() const
Gets charge over momentum [ec/GeV].
static fvec One()
constexpr fscal ElectronMass
Electron mass [GeV/c2].
Definition CaDefs.h:93
constexpr fscal SpeedOfLightInv
Inverse speed of light [ns/cm].
Definition CaDefs.h:96
TODO: SZh 8.11.2022: add selection of parameterisation.
Definition CaBranch.h:14
class cbm::algo::ca::WindowData _fvecalignment
kf::fscal fscal
Definition CaSimd.h:14
kf::fmask fmask
Definition CaSimd.h:15
unsigned int HitIndex_t
Index of ca::Hit.
Definition CaHit.h:27
kf::fvec fvec
Definition CaSimd.h:13
constexpr auto SpeedOfLightInv
Inverse speed of light [ns/cm].
Definition KfDefs.h:210
fvec fabs(const fvec &v)
Definition KfUtils.h:30
TrackParam< fvec > TrackParamV
bool IsEmpty() const
Definition CaMcMatch.h:87
T qp
qp = q/pz at the linearization point