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