CbmRoot
Loading...
Searching...
No Matches
CbmKFV0FinderTask.cxx
Go to the documentation of this file.
1/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergei Zharko [committer] */
4
9
10#include "CbmKFV0FinderTask.h"
11
12#include "CbmEvent.h"
13#include "CbmEventTriggers.h"
14#include "CbmGlobalTrack.h"
15#include "CbmKfTarget.h"
16#include "CbmStsHit.h"
17#include "CbmStsTrack.h"
18#include "CbmTofAddress.h"
19#include "CbmTofHit.h"
20#include "CbmTofTrack.h"
21#include "CbmTrdHit.h"
22#include "CbmTrdTrack.h"
23#include "FairRunAna.h"
24#include "KFPTrackVector.h"
25#include "KFVertex.h"
26#include "KfpV0FinderConfig.h"
27#include "Logger.h"
28#include "TClonesArray.h"
29#include "TMatrixTSym.h"
30#include "yaml/Yaml.h"
31
32#include <boost/filesystem.hpp>
33
34#include <algorithm>
35#include <cmath>
36#include <iomanip>
37#include <iostream>
38#include <limits>
39#include <sstream>
40
41// Log macros:
42#define ERR_ LOG(error) << fName << ": "
43#define LOG_(SEVERITY, VERBOSITY) LOG_IF(SEVERITY, fVerbose >= VERBOSITY) << fName << ": "
44
46
47// ---------------------------------------------------------------------------------------------------------------------
48//
50{
51 namespace fs = boost::filesystem;
52 namespace yml = cbm::algo::yaml;
53 fs::path configPath = fsConfigName.Data();
54 if (!fs::exists(configPath)) {
55 std::stringstream msg;
56 msg << fName << ": configuration file " << configPath.string() << " does not exist";
57 throw std::runtime_error(msg.str());
58 }
59
60 LOG_(info, 1) << "applying configuration from " << configPath.string();
61 auto config = yml::ReadFromFile<cbm::algo::kfp::V0FinderConfig>(configPath);
62
63 LOG_(info, 1) << config.ToString();
64
65
66 // -- Read the config
67 if (config.reconstructPdg != 3122) { // At the moment only Lambda analysis is possible
68 std::stringstream msg;
69 msg << fName << ": at the moment only lambda finding is possible. Provided PDG: " << config.reconstructPdg;
70 throw std::runtime_error(msg.str());
71 }
72
73 // Check daughter particles:
74 auto& particles = config.cuts.particles;
75 int iPion = -1;
76 int iProton = -1;
77 for (int iPart = 0; iPart < int(particles.size()); ++iPart) {
78 const auto& particle = particles[iPart];
79 if (particle.pdg == -211) {
80 if (iPion == -1) {
81 iPion = iPart;
82 }
83 else {
84 std::stringstream msg;
85 msg << fName << ": pion entry is defined more then one time in the config.cuts.particles";
86 throw std::runtime_error(msg.str());
87 }
88 }
89 else if (particle.pdg == 2212) {
90 if (iProton == -1) {
91 iProton = iPart;
92 }
93 else {
94 std::stringstream msg;
95 msg << fName << ": proton entry is defined more then one time in the config.cuts.particles";
96 throw std::runtime_error(msg.str());
97 }
98 }
99 }
100 if (iProton == -1 || iPion == -1) {
101 std::stringstream msg;
102 msg << fName << ": config cuts/particles: either pion or proton settings are not found";
103 throw std::runtime_error(msg.str());
104 }
105
106 const auto& pion{particles[iPion]};
107 const auto& proton{particles[iProton]};
108
109 SetMinPionDca(pion.minDca);
110 SetPionVelocityRange(pion.minVelocity, pion.maxVelocity);
111 SetMinProtonDca(proton.minDca);
112 SetProtonVelocityRange(proton.minVelocity, proton.maxVelocity);
113
114 SetTzeroOffset(config.tZeroOffset);
115 SetQpAssignedUncertainty(config.qpAssignedUncertainty);
116 AddDecayToReconstructionList(config.reconstructPdg); // Lambda
117
118 fPrimaryAssignedPdg = config.primaryAssignedPdg;
119
120 // KFParticleFinder cuts:
121 auto& kfpCuts = config.cuts.kfp;
122 SetChiPrimaryCut2D(kfpCuts.maxChi2NdfPrim);
123 SetLdLCut2D(kfpCuts.minDecayLDL);
124 SetLCut(kfpCuts.minDecayLength); // 5cm cut
125 SetChi2Cut2D(kfpCuts.maxChi2NdfGeo);
126}
127
128// ---------------------------------------------------------------------------------------------------------------------
129//
131{
132 const int iTofTrk = pTrack->GetTofTrackIndex();
133 if (iTofTrk < 0) {
135 return false; // Skip tracks, which do not have hits in TOF
136 }
137
138 const auto* pTofTrack{static_cast<const CbmTofTrack*>(fpBrTofTracks->At(iTofTrk))};
139 assert(pTofTrack);
140
141 int nTofHits = pTofTrack->GetNofTofHits();
142 if (nTofHits < 1) {
143 // Must not be called
144 return false;
145 }
147
148 //int iFstTofHit = pTofTrack->GetTofHitIndex(0);
149 int iLstTofHit = pTofTrack->GetTofHitIndex(nTofHits - 1); // last hit in TOF
150
151 const auto* pLstTofHit{static_cast<CbmTofHit*>(fpBrTofHits->At(iLstTofHit))};
152 if (fbRunQa) {
153 fpQa->fph_tof_lst_hit_time->Fill(pLstTofHit->GetTime());
154 }
155 assert(pLstTofHit);
156
157 if (pLstTofHit->GetTime() < 0) { //< wrongly calibrated T0
159 return false;
160 }
161
162 auto qpAndBeta = EstimateQp(pLstTofHit, pdg);
163 if (fbRunQa) {
164 fpQa->fph_beta_all->Fill(qpAndBeta.fBeta);
165 }
166
167 auto& beta = qpAndBeta.fBeta;
168 if (qpAndBeta.fBeta > 1) {
170 return false; // unphysical track
171 }
172
173 // Extra cut on pion and proton velocity (TODO: maybe put this cut earlier)
174 if ((pdg == -211 && (beta > fMaxBetaPion || beta < fMinBetaPion))
175 || (pdg == 2212 && (beta > fMaxBetaProton || beta < fMinBetaProton))) {
176 return false;
177 }
178
179
180 // Update the track with the PID hypothesis and momentum
181 FairTrackParam parFst(*pTrack->GetParamFirst());
182 FairTrackParam parLst(*pTrack->GetParamLast());
183
184 parFst.SetQp(qpAndBeta.fQp);
185 parLst.SetQp(qpAndBeta.fQp);
186 parFst.SetCovariance(4, 4, qpAndBeta.fQpVar);
187 parFst.SetCovariance(4, 4, qpAndBeta.fQpVar);
188
189 pTrack->SetParamFirst(&parFst);
190 pTrack->SetParamLast(&parLst);
191 return true;
192}
193
194// ---------------------------------------------------------------------------------------------------------------------
195//
196template<bool UseEvent>
198{
199 int nTracks = UseEvent ? pEvent->GetNofData(ECbmDataType::kGlobalTrack) : fpBrGlobalTracks->GetEntriesFast();
201
202
203 // Local event counters
204 int nProtons{0};
205 int nPions{0};
206 int nTracksSelected{0};
207
208 // Local containers (per event)
209 std::vector<const CbmGlobalTrack*> vpSelectedTracks; // Selected tracks [n selected tracks]
210 vpSelectedTracks.reserve(nTracks);
211 std::vector<int> vSelectedTrackIds; // Indices of selected tracks [n selected tracks]
212 vSelectedTrackIds.reserve(nTracks);
213
214 // ----- Shift TOF hit times to t0
215 if constexpr (UseEvent) {
216 auto t0 = ShiftTofHitsToTzero(pEvent);
217 if (std::isnan(t0)) {
219 return false;
220 }
221 }
222
223 // ----- Select tracks
224 for (int iTrkEvt{0}; iTrkEvt < nTracks; ++iTrkEvt) {
225 const int iTrk = UseEvent ? pEvent->GetIndex(ECbmDataType::kGlobalTrack, iTrkEvt) : iTrkEvt;
226 auto* pGlobalTrack{static_cast<CbmGlobalTrack*>(fpBrGlobalTracks->At(iTrk))};
227 if (!SelectTrack(pGlobalTrack, iTrk)) {
228 continue;
229 }
230 ++nTracksSelected;
231 switch (pGlobalTrack->GetPidHypo()) {
232 case -211: // pions
233 ++nPions;
234 break;
235 case 2212: // protons
236 ++nProtons;
237 break;
238 }
239 vpSelectedTracks.push_back(pGlobalTrack);
240 vSelectedTrackIds.push_back(iTrk);
241 } // END LOOP: tracks in event
242
243 if (nProtons < 1 || nPions < 1) {
244 return false; // Nothing to search for in the event
245 }
246
247 fCounters[ECounter::TracksSelected] += nTracksSelected;
248 fCounters[ECounter::Pions] += nPions;
249 fCounters[ECounter::Protons] += nProtons;
250
252
253 // NOTE: The variable is used to assign a KfParticle to a corresponding primary vertex:
254 // a) pvChi2 < 3 => primary particle
255 // b) pvChi2 > 3 => secondary particle
256 // Here we assign all particles as secondary (TODO: test and try to separate primary and secondary particles)
257 std::vector<float> vChi2ToPv; // Chi-square to primary vertex (NOTE: not used)
258 vChi2ToPv.resize(nTracksSelected, 999.); // Assign all tracks as secondary
259
260 KFPTrackVector kfpTracksFst = MakeKfpTrackVector(vpSelectedTracks, vSelectedTrackIds, vChi2ToPv, true);
261 KFPTrackVector kfpTracksLst = MakeKfpTrackVector(vpSelectedTracks, vSelectedTrackIds, vChi2ToPv, false);
262
263 // ----- Reconstruct topology in the event
265 fpTopoReconstructorEvent->Init(kfpTracksFst, kfpTracksLst);
267 float x{float(fpOrigin->GetX())};
268 float y{float(fpOrigin->GetY())};
269 float z{float(fpOrigin->GetZ())};
270 // NOTE: the target size can be applied as a covariance matrix, now it has all nulls
271 fpTopoReconstructorEvent->AddPV(MakeKfpPrimaryVertex(x, y, z), std::vector<int>{});
272 }
273 fpTopoReconstructorEvent->SortTracks();
274 fpTopoReconstructorEvent->ReconstructParticles();
275
276 // ----- Count number of found lambda-candidates
277 int nLambda = 0;
278 //std::count_if(particles.begin(), particles.end(), [](const auto& p) { return p.GetPDG() == 3122; });
279 for (const auto& particle : fpTopoReconstructorEvent->GetParticles()) {
280 if (particle.GetPDG() == 3122) {
281 ++nLambda;
282 if (fbRunQa) {
283 fpQa->fph_lambda_cand_mass->Fill(particle.GetMass());
284 }
285 }
286 }
288 if (nLambda > 0) {
289 auto& triggers = (*fpBrEventTriggers)[pEvent ? pEvent->GetNumber() : 0];
292 }
293
294 // ----- Store particles to the run topology
296
297 return true;
298}
299
300// ---------------------------------------------------------------------------------------------------------------------
301//
302bool V0FinderTask::CheckTrackParam(const FairTrackParam* pParam)
303{
304 bool bOk{true};
305 bOk &= std::isfinite(pParam->GetX());
306 bOk &= std::isfinite(pParam->GetY());
307 bOk &= std::isfinite(pParam->GetZ());
308 bOk &= std::isfinite(pParam->GetTx());
309 bOk &= std::isfinite(pParam->GetTy());
310 bOk &= std::isfinite(pParam->GetQp());
311 std::array<double, 15> covMatrix = {0.};
312 if (bOk) {
313 for (int i = 0, iCov = 0; i < 5; ++i) {
314 for (int j = i; j < 5; j++, iCov++) {
315 // NOTE: In the FairTrackParam::GetCovariance(i, j) one can exchange the i and j indices, but for more
316 // efficient calculation it is recommended to keep i < j.
317 covMatrix[iCov] = pParam->GetCovariance(i, j);
318 bOk &= std::isfinite(covMatrix[iCov]);
319 }
320 }
321 }
322 return bOk;
323}
324
325// ---------------------------------------------------------------------------------------------------------------------
326//
328{
329 DcaVector res;
330 if (pStsTrack->GetNofStsHits() < 2) {
331 // Too few STS hits
332 return res;
333 }
334 const auto* pHitFst{static_cast<const CbmStsHit*>(fpBrStsHits->At(pStsTrack->GetStsHitIndex(0)))}; // first hit
335 const auto* pHitSnd{static_cast<const CbmStsHit*>(fpBrStsHits->At(pStsTrack->GetStsHitIndex(1)))}; // second hit
336 assert(pHitFst);
337 assert(pHitSnd);
338 double factor{(pHitFst->GetZ() - fpOrigin->GetZ()) / (pHitSnd->GetZ() - pHitFst->GetZ())};
339 res.fX = pHitFst->GetX() - fpOrigin->GetX() - factor * (pHitSnd->GetX() - pHitFst->GetX());
340 res.fY = pHitFst->GetY() - fpOrigin->GetY() - factor * (pHitSnd->GetY() - pHitFst->GetY());
341 res.fAbs = std::sqrt(res.fX * res.fX + res.fY * res.fY);
342 res.fX /= res.fAbs;
343 res.fY /= res.fAbs;
344 return res;
345}
346
347// ---------------------------------------------------------------------------------------------------------------------
348//
350{
351 // FIXME: For now we consider the origin as a precise measurement, which is not correct. The corresponding
352 // uncertainty of the origin must be accounted here.
353 // Also: redefine origin with reconstructed or MC PV (in other function).
354 // Also: the t0 uncertainty should be estimated and accounted in the momentum uncertainty
355 QpAndBeta res;
356 double x{pTofHit->GetX() - fpOrigin->GetX()};
357 double y{pTofHit->GetY() - fpOrigin->GetY()};
358 double z{pTofHit->GetZ() - fpOrigin->GetZ()};
359 double x2{x * x};
360 double y2{y * y};
361 double z2{z * z};
362 double t2{pTofHit->GetTime() * pTofHit->GetTime()};
363 double r2{x2 + y2 + z2};
364 double r4{r2 * r2};
365 // FIXME: In general case, the x, y, z coordinates of the origin can have non-zero covariances, which should be
366 // accounted in the calculation.
367 double xVar{pTofHit->GetDx() * pTofHit->GetDx() + fpOrigin->GetCovariance(0, 0)};
368 double yVar{pTofHit->GetDy() * pTofHit->GetDy() + fpOrigin->GetCovariance(1, 1)};
369 double zVar{pTofHit->GetDz() * pTofHit->GetDz() + fpOrigin->GetCovariance(2, 2)};
370 double tVar{pTofHit->GetTimeError() * pTofHit->GetTimeError()};
371 double factor{(x2 * xVar + y2 * yVar + z2 * zVar) / r4 + tVar / t2};
372 res.fBeta = std::sqrt(r2) / (pTofHit->GetTime() * kSpeedOfLight);
373 res.fBetaVar = res.fBeta * factor;
374 if (res.fBeta >= 1) {
375 return res; //< Non-physical beta
376 // FIXME: I would set beta to fixed large value, like 0.999999 for this case
377 }
378 double gamma{1. / std::sqrt(1. - res.fBeta * res.fBeta)};
379 double m{0};
380 double q{0};
381 switch (pdg) {
382 case -211:
383 m = kPionMass;
384 q = -1;
385 break;
386 case 2212:
387 m = kProtonMass;
388 q = 1;
389 break;
390 default:
391 res.fQp = -1. / 99999.; //< Give small momentum to primary tracks
393 return res;
394 // NOTE: it would be more straight forward to assign the primary tracks a mass of pion and keep it
395 }
396 res.fQp = q / (gamma * res.fBeta * m);
397 if (fQpAssignedUncertainty > 0) {
399 }
400 else {
401 res.fQpVar = q * q / (m * m * res.fBeta * res.fBeta) * factor;
402 }
403 return res;
404}
405
406// ---------------------------------------------------------------------------------------------------------------------
407//
408void V0FinderTask::Exec(Option_t*)
409{
410 fvTrackDca.clear();
411 fvTrackDca.resize(fpBrGlobalTracks->GetEntriesFast());
412
413 // ----- Reset data containers per timeslice
414 fpTopoReconstructorRun->Clear();
415
416 // ----- Process timeslice
419 fpBrEventTriggers->clear();
420 fpBrEventTriggers->resize(1);
421 ProcessEvent</*UseEvent = */ false>(nullptr);
422 }
423 else {
424 const int nEvents{fpBrRecoEvents->GetEntriesFast()};
425
427 fpBrEventTriggers->clear();
428 fpBrEventTriggers->resize(nEvents);
429 for (int iEvent = 0; iEvent < nEvents; ++iEvent) {
430 const auto* pEvent = static_cast<CbmEvent*>(fpBrRecoEvents->At(iEvent));
431 ProcessEvent</*UseEvent = */ true>(pEvent);
432 }
433 }
434}
435
436// ---------------------------------------------------------------------------------------------------------------------
437//
439{
440 // ----- Store QA histograms
441 if (fbRunQa) {
442 fpQa->WriteHistograms(fsQaOutputName);
443 }
444
445 // ----- Counters summary log
446 std::stringstream msg;
447 msg << "*** Counters summary ***\n";
448 msg << "\n tracks total: " << fCounters[ECounter::TracksTotal];
449 msg << "\n tracks selected: " << fCounters[ECounter::TracksSelected];
450 msg << "\n tracks w/ infinit parameters: " << fCounters[ECounter::TracksInfiniteParam];
451 msg << "\n tracks w/o TOF hits: " << fCounters[ECounter::TracksWoTofHits];
452 msg << "\n tracks w/ last TOF hit having t<0: " << fCounters[ECounter::TracksWNegativeTofHitTime];
453 msg << "\n tracks w/o STS hits: " << fCounters[ECounter::TracksWoStsHits];
454 msg << "\n tracks w/o PID: " << fCounters[ECounter::TracksWoPid];
455 msg << "\n tracks w/o momentum: " << fCounters[ECounter::TracksWoMomentum];
456 msg << "\n tracks w/ at least one TOF hit: " << fCounters[ECounter::TracksWAtLeastOneTofHit];
457 msg << "\n tracks w/ at least two TOF hits: " << fCounters[ECounter::TracksWAtLeastTwoTofHits];
458 msg << "\n tracks w/ beta > 1 " << fCounters[ECounter::TracksWithUnphysicalBeta];
459 msg << "\n pion candidates: " << fCounters[ECounter::Pions];
460 msg << "\n proton candidates: " << fCounters[ECounter::Protons];
461 msg << "\n events total: " << fCounters[ECounter::EventsTotal];
462 msg << "\n events w/o t-zero: " << fCounters[ECounter::EventsWoTzero];
463 msg << "\n events w/ potential Lambda-candidate: " << fCounters[ECounter::EventsLambdaCand];
464 msg << "\n events w/ Lambda-candidate from KFPF: " << fCounters[ECounter::KfpEventsLambdaCand];
465 msg << "\n Lambda-candidates: " << fCounters[ECounter::KfpLambdaCandidates];
466 LOG_(info, 1) << msg.str();
467}
468
469// ---------------------------------------------------------------------------------------------------------------------
470//
472{
473 if (std::isnan(dca)) {
474 return -2; //< Track PID cannot be infered
475 }
476 if (dca > fMinPionDca) {
477 return -211; // pi-
478 }
479 else if (dca > fMinProtonDca) {
480 return 2212; // proton
481 }
482 return kPrimaryPdg;
483}
484
485// ---------------------------------------------------------------------------------------------------------------------
486//
488{
489 LOG_(info, 1) << "initializing the task ... ";
490
491 LOG_(info, 1) << "using the following configuration:\n processing mode: " << ToString(fProcessingMode)
492 << "\n PID approach: " << ToString(fPidApproach) << "\n " << ToString(fPvUsageMode);
493
494 // Temporary not implemented:
498 ERR_ << "Desirable configuration of PID or PV handling was not implemented yet";
499 return kFATAL;
500 }
501
502 if (!fsConfigName.IsNull()) {
503 try {
505 }
506 catch (const std::exception& err) {
507 ERR_ << "configuration from a config was required, but failed. Reason: " << err.what();
508 return kFATAL;
509 }
510 }
511
512 // ----- Input data branches initialization
513 const auto* pTarget = kf::Target::Instance(); // CBM target info
514
515 auto* pFairManager = FairRootManager::Instance();
516 if (!pFairManager) {
517 ERR_ << "FairRootManager not found";
518 return kERROR;
519 }
520
521 auto InitBranch = [&](TClonesArray*& branch, const char* name) -> bool {
522 branch = dynamic_cast<TClonesArray*>(pFairManager->GetObject(name));
523 if (!branch) {
524 ERR_ << "branch \"" << name << "\" not found";
525 return false;
526 }
527 return true;
528 };
529
530 bool bBranchesInitialized{true};
532 bBranchesInitialized = InitBranch(fpBrRecoEvents, "CbmEvent") && bBranchesInitialized;
533 }
534 bBranchesInitialized = InitBranch(fpBrGlobalTracks, "GlobalTrack") && bBranchesInitialized;
535 bBranchesInitialized = InitBranch(fpBrStsTracks, "StsTrack") && bBranchesInitialized;
536 bBranchesInitialized = InitBranch(fpBrTrdTracks, "TrdTrack") && bBranchesInitialized;
537 bBranchesInitialized = InitBranch(fpBrTofTracks, "TofTrack") && bBranchesInitialized;
538 bBranchesInitialized = InitBranch(fpBrStsHits, "StsHit") && bBranchesInitialized;
539 bBranchesInitialized = InitBranch(fpBrTrdHits, "TrdHit") && bBranchesInitialized;
540 bBranchesInitialized = InitBranch(fpBrTofHits, "TofHit") && bBranchesInitialized;
541
543 fpBrPrimaryVertex = dynamic_cast<CbmVertex*>(pFairManager->GetObject("PrimaryVertex."));
544 if (!fpBrPrimaryVertex) {
545 ERR_ << "branch \"PrimaryVertex.\" not found";
546 bBranchesInitialized = false;
547 }
548 }
550 double x{pTarget->GetX()};
551 double y{pTarget->GetY()};
552 double z{pTarget->GetZ()};
553 LOG_(info, 1) << "using target center as origin: r = (" << x << ", " << y << ", " << z << ") [cm]";
554 TMatrixFSym covMatrix(3);
555 covMatrix(1, 0) = 0.;
556 covMatrix(2, 0) = 0.;
557 covMatrix(2, 1) = 0.;
558 //double transverseVariance{pTarget->GetRmax() * pTarget->GetRmax() / 12.};
559 //covMatrix(0, 0) = transverseVariance;
560 //covMatrix(1, 1) = transverseVariance;
561 //covMatrix(2, 2) = pTarget->GetDz() * pTarget->GetDz() / 3.;
562 covMatrix(0, 0) = 0.;
563 covMatrix(1, 1) = 0.;
564 covMatrix(2, 2) = 0.;
565 fpOrigin->SetVertex(x, y, z, 0., 1, 0, covMatrix);
566 }
567
568 if (!bBranchesInitialized) {
569 return kERROR;
570 }
571
572 // ----- Output branches initialization
573 fpBrEventTriggers = new std::vector<CbmEventTriggers>();
574 if (pFairManager->GetObject("CbmEventTriggers")) {
575 LOG(error) << "Branch \"CbmEventTriggers\" already exists!";
576 return kFATAL;
577 }
578 pFairManager->RegisterAny("CbmEventTriggers", fpBrEventTriggers, true);
579 LOG_(info, 1) << "registering branch \"CbmEventTriggers\"";
580
581 // ----- Topology reconstructor initialization
582 fpTopoReconstructorRun->SetTarget({float(pTarget->GetX()), float(pTarget->GetY()), float(pTarget->GetZ())});
583 fpTopoReconstructorEvent->SetTarget(fpTopoReconstructorRun->GetTargetPosition());
585 fpTopoReconstructorEvent->GetKFParticleFinder()->SetReconstructionList(
586 fpTopoReconstructorRun->GetKFParticleFinder()->GetReconstructionList());
587
588 // ----- Auxilary variables initialization
589 std::fill(fCounters.begin(), fCounters.end(), 0);
590
591 // ----- QA initialization
592 if (fbRunQa) {
593 fpQa = std::make_unique<V0FinderQa>(fbUseMc);
594 fpQa->InitHistograms();
595 }
596
597 LOG_(info, 1) << "initializing the task ... done";
598 return kSUCCESS;
599}
600
601// ---------------------------------------------------------------------------------------------------------------------
602//
603KFPTrackVector V0FinderTask::MakeKfpTrackVector(const std::vector<const CbmGlobalTrack*>& vpTracks,
604 const std::vector<int>& vTrackIds, const std::vector<float>& vChi2ToPv,
605 bool bAtFirstPoint) const
606{
607 // TODO: Cross-check with the CbmKFParticleFinder results
608 // NOTE: Actually tracks themselves are not needed here, so one could fill and pass a vector of FairTrackParam*,
609 // put in KFPTrackVector there is an option to set number of Pixel hits, so we will keep the signature of
610 // the function as it is.
611 KFPTrackVector trackVector;
612 int nTracks = vpTracks.size();
613 trackVector.Resize(nTracks);
614 for (int iTrk = 0; iTrk < nTracks; ++iTrk) {
615 const auto* pTrack{vpTracks[iTrk]};
616 const auto* pParam{bAtFirstPoint ? pTrack->GetParamFirst() : pTrack->GetParamLast()};
617
618 // ----- Parameters definition
619 int pdg{pTrack->GetPidHypo()};
620 const double& tx{pParam->GetTx()};
621 const double& ty{pParam->GetTy()};
622 const double& qp{pParam->GetQp()};
623 int q{qp > 0. ? 1 : -1};
624 if (std::fabs(pdg) == 10000020030 || std::fabs(pdg == 1000020040)) { // He3 and He4
625 // NOTE: at the moment not called, but never the less leave it here for the future pid procedures
626 q *= 2;
627 }
628 double p{q / qp};
629 double p2{p * p};
630 double t2inv{1. / (1. + tx * tx + ty * ty)};
631 double pz{std::sqrt(t2inv * p2)};
632 double px{tx * pz};
633 double py{ty * pz};
634
635 trackVector.SetParameter(pParam->GetX(), 0, iTrk);
636 trackVector.SetParameter(pParam->GetY(), 1, iTrk);
637 trackVector.SetParameter(pParam->GetZ(), 2, iTrk);
638 trackVector.SetParameter(px, 3, iTrk);
639 trackVector.SetParameter(py, 4, iTrk);
640 trackVector.SetParameter(pz, 5, iTrk);
641
642 // Jacobian matrix for (tx, ty, qp) -> (px, py, pz)
643 std::array<std::array<double, 3>, 3> Jp;
644 Jp[2][0] = -t2inv * px; // d(pz)/d(tx)
645 Jp[2][1] = -t2inv * py; // d(pz)/d(ty)
646 Jp[2][2] = -pz / qp; // d(pz)/d(qp)
647 Jp[0][0] = tx * Jp[2][0] + pz; // d(px)/d(tx)
648 Jp[0][1] = tx * Jp[2][1]; // d(px)/d(ty)
649 Jp[0][2] = tx * Jp[2][2]; // d(px)/d(qp)
650 Jp[1][0] = ty * Jp[2][0]; // d(py)/d(tx)
651 Jp[1][1] = ty * Jp[2][1] + pz; // d(py)/d(ty)
652 Jp[1][2] = ty * Jp[2][2]; // d(py)/d(qp)
653
654 // ----- Covariance matrix definition
655 // Position covariances
656 trackVector.SetCovariance(pParam->GetCovariance(0, 0), 0, iTrk); // var(x)
657 trackVector.SetCovariance(pParam->GetCovariance(0, 1), 1, iTrk); // cov(x, y)
658 trackVector.SetCovariance(pParam->GetCovariance(1, 1), 2, iTrk); // var(y)
659
660 // Momentum-position covariances
661 auto MomPosCovariance = [&](const int k, const int l) constexpr->double
662 {
663 double val{0.};
664 const auto& JpA = Jp[k];
665 for (int i = 0; i < 3; ++i) {
666 val += JpA[i] * pParam->GetCovariance(i + 2, l);
667 }
668 return val;
669 };
670 trackVector.SetCovariance(MomPosCovariance(0, 0), 6, iTrk); // cov(x, px)
671 trackVector.SetCovariance(MomPosCovariance(0, 1), 7, iTrk); // cov(y, px)
672 trackVector.SetCovariance(MomPosCovariance(1, 0), 10, iTrk); // cov(x, py)
673 trackVector.SetCovariance(MomPosCovariance(1, 1), 11, iTrk); // cov(y, py)
674 trackVector.SetCovariance(MomPosCovariance(2, 0), 15, iTrk); // cov(x, pz)
675 trackVector.SetCovariance(MomPosCovariance(2, 1), 16, iTrk); // cov(y, pz)
676
677 // Momentum covariances
678 auto MomentumCovariance = [&](const int k, const int l) constexpr->double
679 {
680 double val{0.};
681 const auto& JpA = Jp[k];
682 const auto& JpB = Jp[l];
683 for (int i = 0; i < 3; ++i) {
684 double factor{0.};
685 for (int j = 0; j < 3; ++j) {
686 factor += JpB[j] * pParam->GetCovariance(i + 2, j + 2);
687 }
688 val += JpA[i] * factor;
689 }
690 return val;
691 };
692 trackVector.SetCovariance(MomentumCovariance(0, 0), 9, iTrk); // var(px)
693 trackVector.SetCovariance(MomentumCovariance(1, 0), 13, iTrk); // cov(px, py)
694 trackVector.SetCovariance(MomentumCovariance(1, 1), 14, iTrk); // var(py)
695 trackVector.SetCovariance(MomentumCovariance(2, 0), 18, iTrk); // cov(px, pz)
696 trackVector.SetCovariance(MomentumCovariance(2, 1), 19, iTrk); // cov(py, pz)
697 trackVector.SetCovariance(MomentumCovariance(2, 2), 20, iTrk); // var(pz)
698
699 // Zero covariances
700 // NOTE: from the tracking point of view a z-coordinate in known precisely, so all the corresponding covariances
701 // should be set to null.
702 trackVector.SetCovariance(0.f, 3, iTrk); // cov(x,z)
703 trackVector.SetCovariance(0.f, 4, iTrk); // cov(y,z)
704 trackVector.SetCovariance(0.f, 5, iTrk); // var(z)
705 trackVector.SetCovariance(0.f, 8, iTrk); // cov(z,px)
706 trackVector.SetCovariance(0.f, 12, iTrk); // cov(z,py)
707 trackVector.SetCovariance(0.f, 17, iTrk); // var(z,pz)
708
709 // ----- Other parameters
710 // Magnetic field
711 // NOTE: In mCBM there is no magnetic field, so here we define the coefficients with zeros
712 for (int iF = 0; iF < 10; ++iF) {
713 trackVector.SetFieldCoefficient(0.f, iF, iTrk);
714 }
715
716 trackVector.SetId(vTrackIds[iTrk], iTrk);
717 trackVector.SetPDG(pdg, iTrk);
718 trackVector.SetQ(q, iTrk);
719 trackVector.SetNPixelHits(0, iTrk); // Number of MVD hits in track (used to define PV inside the KFPFinder)
720
721 if (EPvUsageMode::Reconstructed == fPvUsageMode || EPvUsageMode::Mc == fPvUsageMode) {
722 if (vChi2ToPv[iTrk] < kChi2PvPrimThrsh) {
723 trackVector.SetPVIndex(0, iTrk); // Primary track
724 }
725 else {
726 trackVector.SetPVIndex(-1, iTrk); // Secondary track
727 }
728 }
729 else {
730 trackVector.SetPVIndex(-1, iTrk); // Secondary track
731 }
732 }
733 return trackVector;
734}
735
736// ---------------------------------------------------------------------------------------------------------------------
737//
738KFVertex V0FinderTask::MakeKfpPrimaryVertex(float x, float y, float z) const
739{
740 KFVertex kfVertex;
741 kfVertex.X() = x;
742 kfVertex.Y() = y;
743 kfVertex.Z() = z;
744 for (int iC = 0; iC < 6; ++iC) {
745 kfVertex.Covariance(iC) = 0.f;
746 }
747 kfVertex.Chi2() = -100.f;
748 return kfVertex;
749}
750
751// ---------------------------------------------------------------------------------------------------------------------
752//
754{
755 const int iStsTrk = pTrack->GetStsTrackIndex();
756 if (iStsTrk < 0) {
758 return false; // Skip tracks, which do not have hits in TOF
759 }
760 const auto* pStsTrack{static_cast<const CbmStsTrack*>(fpBrStsTracks->At(iStsTrk))};
761
762 // Get PID hypothesis for the track
763 int pdgHypo{kUndefPdg};
765 auto& trkDca{fvTrackDca[iTrk]};
766 trkDca = EstimateDcaToOrigin(pStsTrack);
767 pdgHypo = InferTrackPidTopo(trkDca.fAbs);
768 if (fbRunQa) {
769 fpQa->fph_dca->Fill(trkDca.fAbs);
770 fpQa->fph_dca2D->Fill(trkDca.fAbs * trkDca.fX, trkDca.fAbs * trkDca.fY);
771 fpQa->fph_dca_projectionX->Fill(trkDca.fAbs * trkDca.fX);
772 fpQa->fph_dca_projectionY->Fill(trkDca.fAbs * trkDca.fY);
773 }
774 }
775
776 pTrack->SetPidHypo(pdgHypo);
777 if (pdgHypo == kUndefPdg) {
779 return false; // Tracks, which do not obey the PID criteria
780 }
781
782 // Assign a momentum to the track using the last hit in TOF, reject the track, if it has no TOF hits
783 if (!AssignMomentum(pTrack, pdgHypo)) {
785 return false;
786 }
787
788 // Check track parameters for validity
789 // FIXME: understand the reason, why the parameters are infinite
790 if (!CheckTrackParam(pTrack->GetParamFirst())) {
792 return false;
793 }
794
795 return true;
796}
797
798// ---------------------------------------------------------------------------------------------------------------------
799//
801{
802 // Define t0 from the Bmon hits
803 double t0{std::numeric_limits<double>::signaling_NaN()};
805 for (int iTofHitEvt{0}; iTofHitEvt < nTofHits; ++iTofHitEvt) {
806 int iTofHit = pEvent->GetIndex(ECbmDataType::kTofHit, iTofHitEvt);
807 const auto* pTofHit{static_cast<const CbmTofHit*>(fpBrTofHits->At(iTofHit))};
808 //if (5 == CbmTofAddress::GetSmType(pTofHit->GetAddress())) { // selection by the supermodule type
809 if (pTofHit->GetZ() == 0) { // Take some small z-coordinate to identify BMon (TODO: provide a flag by some task)
810 t0 = pTofHit->GetTime();
811 }
812 }
813 // NOTE: t0 must be defined for each event, since the Bmon digis are used to seed the digi event builder. Basically,
814 // the tZero must be defined as a field of CbmEvent, e.g. in a separate FairTask, or directly
815 // in CbmAlgoBuildRawEvent
816 if (std::isnan(t0)) {
817 return t0;
818 }
819
820 // Shift TOF times to found t0:
821 for (int iTofHitEvt{0}; iTofHitEvt < nTofHits; ++iTofHitEvt) {
822 int iTofHit = pEvent->GetIndex(ECbmDataType::kTofHit, iTofHitEvt);
823 auto* pTofHit{static_cast<CbmTofHit*>(fpBrTofHits->At(iTofHit))};
824 pTofHit->SetTime(pTofHit->GetTime() - t0 - fTzeroOffset);
825 }
826 return t0;
827}
828
829// ---------------------------------------------------------------------------------------------------------------------
830//
832{
833 int indexOffset = fpTopoReconstructorRun->GetParticles().size();
834 for (int iPv = 0; iPv < fpTopoReconstructorEvent->NPrimaryVertices(); ++iPv) {
835 std::vector<int> vPVTrackIndexArray = fpTopoReconstructorEvent->GetPVTrackIndexArray(iPv);
836 std::for_each(vPVTrackIndexArray.begin(), vPVTrackIndexArray.end(), [&](auto& item) { item += indexOffset; });
837 fpTopoReconstructorRun->AddPV(fpTopoReconstructorEvent->GetPrimKFVertex(iPv), vPVTrackIndexArray);
838 }
839
840 for (size_t iP = 0; iP < fpTopoReconstructorEvent->GetParticles().size(); ++iP) {
841 const KFParticle& particleEvt{fpTopoReconstructorEvent->GetParticles()[iP]};
842 KFParticle particle{particleEvt};
843 particle.CleanDaughtersId();
844 int nDaughters{particleEvt.NDaughters()};
845 if (nDaughters == 1) {
846 particle.AddDaughterId(particleEvt.DaughterIds()[0]);
847 }
848 else if (nDaughters > 1) {
849 for (int iD = 0; iD < particleEvt.NDaughters(); ++iD) {
850 particle.AddDaughterId(particleEvt.DaughterIds()[iD] + indexOffset);
851 }
852 }
853 particle.SetId(particleEvt.Id() + indexOffset);
854 fpTopoReconstructorRun->AddParticle(particle);
855 }
856}
857
858// ---------------------------------------------------------------------------------------------------------------------
859//
861{
862 switch (mode) {
863 case EProcessingMode::EventBased: return "event-based";
864 case EProcessingMode::TimeBased: return "time-based";
865 default: return "";
866 }
867}
868
869// ---------------------------------------------------------------------------------------------------------------------
870//
872{
873 switch (pid) {
874 case EPidApproach::Topo: return "track topology";
875 case EPidApproach::Mc: return "MC-truth";
876 default: return "";
877 }
878}
879
880// ---------------------------------------------------------------------------------------------------------------------
881//
883{
884 switch (pvMode) {
885 case EPvUsageMode::Reconstructed: return "reconstructed primary vertex is used";
886 case EPvUsageMode::ReconstructSingle: return "a single primary vertex will be reconstructed";
887 case EPvUsageMode::ReconstructMultiple: return "multiple primary vertices will be reconstructed";
888 case EPvUsageMode::Target: return "target center is used for primary vertex";
889 case EPvUsageMode::Mc: return "MC-true primary vertex is used";
890 default: return "";
891 }
892}
893
894// ---------------------------------------------------------------------------------------------------------------------
895//
896std::string V0FinderTask::ToString(const FairTrackParam* pParam)
897{
898 std::stringstream msg;
899 msg << "Track parameters: r=(" << pParam->GetX() << ", " << pParam->GetY() << ", " << pParam->GetZ()
900 << "), tx=" << pParam->GetTx() << ", ty=" << pParam->GetTy() << ", q/p=" << pParam->GetQp()
901 << ", Covariance matrix:";
902 for (int i = 0; i < 5; ++i) {
903 msg << '\n';
904 for (int j = 0; j <= i; ++j) {
905 msg << std::setw(15) << pParam->GetCovariance(i, j) << ' ';
906 }
907 }
908 return msg.str();
909}
A structure to store different triggers in parallel to the CbmEvent (implementation)
Int_t nTofHits
#define ERR_
#define LOG_(SEVERITY, VERBOSITY)
Target property initialization and access in CBM (source)
Data class for a reconstructed hit in the STS.
Data class for STS tracks.
Class for hits in TRD detector.
static constexpr size_t size()
Definition KfSimdPseudo.h:2
Configuration structure for V0 selector in mCBM.
@ Lambda
Lambda-trigger.
Class characterising one event by a collection of links (indices) to data objects,...
Definition CbmEvent.h:34
size_t GetNofData() const
Definition CbmEvent.cxx:58
int32_t GetNumber() const
Definition CbmEvent.h:121
uint32_t GetIndex(ECbmDataType type, uint32_t iData) const
Definition CbmEvent.cxx:42
const FairTrackParam * GetParamLast() const
void SetParamLast(const FairTrackParam *parLast)
int32_t GetStsTrackIndex() const
void SetPidHypo(int32_t iPid)
int32_t GetTofTrackIndex() const
void SetParamFirst(const FairTrackParam *parFirst)
const FairTrackParam * GetParamFirst() const
double GetTimeError() const
Definition CbmHit.h:77
double GetDz() const
Definition CbmHit.h:72
double GetTime() const
Definition CbmHit.h:76
double GetZ() const
Definition CbmHit.h:71
double GetDy() const
Definition CbmPixelHit.h:76
double GetDx() const
Definition CbmPixelHit.h:75
double GetY() const
Definition CbmPixelHit.h:74
double GetX() const
Definition CbmPixelHit.h:73
data class for a reconstructed 3-d hit in the STS
Definition CbmStsHit.h:35
int32_t GetStsHitIndex(int32_t iHit) const
int32_t GetNofStsHits() const
Definition CbmStsTrack.h:93
static Target * Instance()
Instance access.
A class to find V0 candidates in mCBM.
bool AssignMomentum(CbmGlobalTrack *pTrack, int pdg)
Assigns momentum to a global track.
double fMinBetaPion
Minimal proton velocity (beta) [c].
EPvUsageMode
Primary vertex finding/handling mode.
std::unique_ptr< V0FinderQa > fpQa
If QA is processed.
KFVertex MakeKfpPrimaryVertex(float x, float y, float z) const
Makes a KF vertex.
DcaVector EstimateDcaToOrigin(const CbmStsTrack *pTrack) const
Estimates distance to the origin.
void Finish() override
Action on the end of the run.
double fMinProtonDca
Minimum DCA to PV for protons.
static bool CheckTrackParam(const FairTrackParam *pParam)
Checks track parameter validity.
cbm::core::EnumArray< ECounter, size_t > fCounters
Counters per run.
std::vector< CbmEventTriggers > * fpBrEventTriggers
InitStatus Init() override
Initializes the task.
EProcessingMode fProcessingMode
Processing mode.
std::vector< DcaVector > fvTrackDca
Track DCA vector [n global tracks].
void StoreParticles()
Stores particles, reconstructed in event to the run topology reconstructor.
void SetTzeroOffset(double offset)
Sets an offset to t0.
QpAndBeta EstimateQp(const CbmTofHit *pTofHit, int pdg) const
Estimates q/p of the track, using one TOF hit (Norbert's method)
TString fsQaOutputName
Output QA name.
static constexpr double kProtonMass
Proton mass [GeV/c2].
static constexpr int kPrimaryPdg
PID hypothesis of primary tracks (kaons?)
double ShiftTofHitsToTzero(const CbmEvent *pEvent)
Shifts TOF hits to the t0 estimation.
KFPTrackVector MakeKfpTrackVector(const std::vector< const CbmGlobalTrack * > &vpTracks, const std::vector< int > &vTrackIds, const std::vector< float > &vChi2ToPv, bool bAtFirstPoint) const
Makes a KF-particle track vector.
static constexpr double kSpeedOfLight
Speed of light [cm/ns].
bool ProcessEvent(const CbmEvent *pEvent)
Processes one event.
void SetChiPrimaryCut2D(float cut)
Sets cut on of each track for 2-daughter decays.
void ApplyConfiguration()
Applies configuration from fsConfigName.
bool fbUseMc
Run using MC-information.
void AddDecayToReconstructionList(int pdg)
Adds particle to reconstruction list.
double fMaxBetaProton
Maximal proton velocity (beta) [c].
void SetQpAssignedUncertainty(double uncertainty)
Assignes an uncertainty to the momentum measurement.
void SetMinPionDca(double dca)
Sets minimal pion DCA to primary vertex.
void SetChi2Cut2D(float cut)
Sets cut on for 2-daughter decays.
bool SelectTrack(CbmGlobalTrack *pTrack, int iTrk)
Selects/rejects a track.
TString fsConfigName
Name of the config.
std::unique_ptr< KFParticleTopoReconstructor > fpTopoReconstructorEvent
void SetPionVelocityRange(double vMin, double vMax)
Sets pion velocity range.
void SetLCut(float cut)
Sets cut on the distance to the primary vertex from the decay vertex.
EProcessingMode
Data processing mode.
static constexpr double kPionMass
Pion mass [GeV/c2].
double fTzeroOffset
Offset for T0.
static constexpr int kUndefPdg
Undefined value, such tracks will be skipped.
double fMaxBetaPion
Maximal proton velocity (beta) [c].
int InferTrackPidTopo(double dca) const
Infers PID hypothesis for a track using track topology.
static std::string ToString(EProcessingMode mode)
String representation of processing mode.
TClonesArray * fpBrGlobalTracks
std::unique_ptr< CbmVertex > fpOrigin
Origin (e.g., can be either reconstructed PV or target)
EPidApproach
PID approach used.
void Exec(Option_t *) override
Executes the task.
std::shared_ptr< KFParticleTopoReconstructor > fpTopoReconstructorRun
Main topology reconstructor.
void SetMinProtonDca(double dca)
Sets minimal proton DCA to primary vertex.
void SetLdLCut2D(float cut)
Sets cut on for 2-daughter decays.
double fMinPionDca
Minimum DCA to PV for pions.
double fQpAssignedUncertainty
Assigned relative uncertainty for q/p estimation.
EPvUsageMode fPvUsageMode
Primary vertex mode.
EPidApproach fPidApproach
PID approach used.
int fPrimaryAssignedPdg
Assigned PDG hypothesis for primary particles.
void SetProtonVelocityRange(double vMin, double vMax)
Sets proton velocity range.
double fMinBetaProton
Minimal proton velocity (beta) [c].
A vector representation of DCA to target.
double fY
Y-component of the unit-vector.
double fX
X-component of the unit-vector.