44 mRecoCont = &recoData;
45 mNV0s = mNCascades = mN3Bodies = 0;
46 updateTimeDependentParams();
49 int ntrP = mTracksPool[
POS].size(), ntrN = mTracksPool[
NEG].size();
55 int dynGrp = std::min(4, std::max(1, mNThreads / 2));
56#pragma omp parallel for schedule(dynamic, dynGrp) num_threads(mNThreads)
58 for (
int itp = 0; itp < ntrP; itp++) {
59 auto& seedP = mTracksPool[
POS][itp];
60 const int firstN = mVtxFirstTrack[
NEG][seedP.vBracket.getMin()];
62 LOG(
debug) <<
"No partner is found for pos.track " << itp <<
" out of " << ntrP;
65 for (
int itn = firstN; itn < ntrN; itn++) {
66 auto& seedN = mTracksPool[
NEG][itn];
67 if (seedN.vBracket > seedP.vBracket) {
68 LOG(
debug) <<
"Brackets do not match";
75 int iThread = omp_get_thread_num();
79 checkV0(seedP, seedN, itp, itn, iThread);
95 for (
int ith = 0; ith < mNThreads; ith++) {
96 mNV0s += mV0sIdxTmp[ith].size();
97 mNCascades += mCascadesIdxTmp[ith].size();
98 mN3Bodies += m3bodyIdxTmp[ith].size();
100 std::vector<vid> v0SortID, cascSortID, nbodySortID;
101 v0SortID.reserve(mNV0s);
102 cascSortID.reserve(mNCascades);
103 nbodySortID.reserve(mN3Bodies);
104 for (
int ith = 0; ith < mNThreads; ith++) {
105 for (
int j = 0;
j < (
int)mV0sIdxTmp[ith].
size();
j++) {
106 v0SortID.emplace_back(vid{ith,
j, mV0sIdxTmp[ith][
j].getVertexID()});
108 for (
int j = 0;
j < (
int)mCascadesIdxTmp[ith].
size();
j++) {
109 cascSortID.emplace_back(vid{ith,
j, mCascadesIdxTmp[ith][
j].getVertexID()});
111 for (
int j = 0;
j < (
int)m3bodyIdxTmp[ith].
size();
j++) {
112 nbodySortID.emplace_back(vid{ith,
j, m3bodyIdxTmp[ith][
j].getVertexID()});
115 std::sort(v0SortID.begin(), v0SortID.end(), [](
const vid&
a,
const vid&
b) { return a.vtxID < b.vtxID; });
116 std::sort(cascSortID.begin(), cascSortID.end(), [](
const vid&
a,
const vid&
b) { return a.vtxID < b.vtxID; });
117 std::sort(nbodySortID.begin(), nbodySortID.end(), [](
const vid&
a,
const vid&
b) { return a.vtxID < b.vtxID; });
122 auto& body3Idx = pc.
outputs().
make<std::vector<Decay3BodyIndex>>(
o2f::Output{
"GLO",
"DECAYS3BODY_IDX", 0});
131 v0sIdx.reserve(mNV0s);
133 fullv0s.reserve(mNV0s);
136 cascsIdx.reserve(mNCascades);
138 fullcascs.reserve(mNCascades);
141 body3Idx.reserve(mN3Bodies);
143 full3body.reserve(mN3Bodies);
146 for (
const auto&
id : v0SortID) {
147 auto& v0idx = mV0sIdxTmp[
id.thrID][
id.entry];
148 int pos = v0sIdx.size();
149 v0sIdx.push_back(v0idx);
150 v0idx.setVertexID(
pos);
152 fullv0s.push_back(mV0sTmp[
id.thrID][
id.
entry]);
156 for (
int ith = 0; ith < mNThreads; ith++) {
157 for (
size_t ic = 0; ic < mCascadesIdxTmp[ith].size(); ic++) {
158 auto& cidx = mCascadesIdxTmp[ith][ic];
159 cidx.setV0ID(mV0sIdxTmp[ith][cidx.getV0ID()].getVertexID());
163 for (
const auto&
id : cascSortID) {
164 cascsIdx.push_back(mCascadesIdxTmp[
id.thrID][
id.
entry]);
165 mCascadesIdxTmp[
id.thrID][
id.entry].setVertexID(cascCnt++);
167 fullcascs.push_back(mCascadesTmp[
id.thrID][
id.
entry]);
171 for (
const auto&
id : nbodySortID) {
172 body3Idx.push_back(m3bodyIdxTmp[
id.thrID][
id.
entry]);
173 m3bodyIdxTmp[
id.thrID][
id.entry].setVertexID(b3cnt++);
175 full3body.push_back(m3bodyTmp[
id.thrID][
id.
entry]);
180 for (
int ith = 0; ith < mNThreads; ith++) {
181 mNStrangeTracks += mStrTracker->
getNTracks(ith);
184 std::vector<o2::dataformats::StrangeTrack> strTracksTmp;
185 std::vector<o2::strangeness_tracking::ClusAttachments> strClusTmp;
186 std::vector<o2::MCCompLabel> mcLabTmp;
187 strTracksTmp.reserve(mNStrangeTracks);
188 strClusTmp.reserve(mNStrangeTracks);
190 mcLabTmp.reserve(mNStrangeTracks);
193 for (
int ith = 0; ith < mNThreads; ith++) {
197 for (
int i = 0;
i < (
int)strTracks.size();
i++) {
198 auto& t = strTracks[
i];
200 t.mDecayRef = mV0sIdxTmp[ith][t.mDecayRef].getVertexID();
202 t.mDecayRef = mCascadesIdxTmp[ith][t.mDecayRef].getVertexID();
204 t.mDecayRef = m3bodyIdxTmp[ith][t.mDecayRef].getVertexID();
206 LOGP(fatal,
"Unknown strange track decay reference type {} for index {}",
int(t.mPartType), t.mDecayRef);
209 strTracksTmp.push_back(t);
210 strClusTmp.push_back(strClust[
i]);
212 mcLabTmp.push_back(stcTrMCLab[
i]);
217 auto& strTracksOut = pc.
outputs().
make<std::vector<o2::dataformats::StrangeTrack>>(
o2f::Output{
"GLO",
"STRANGETRACKS", 0});
218 auto& strClustOut = pc.
outputs().
make<std::vector<o2::strangeness_tracking::ClusAttachments>>(
o2f::Output{
"GLO",
"CLUSUPDATES", 0});
220 strTracksOut.resize(mNStrangeTracks);
221 strClustOut.resize(mNStrangeTracks);
223 mcLabsOut.resize(mNStrangeTracks);
226 std::vector<int> sortIdx(strTracksTmp.size());
227 std::iota(sortIdx.begin(), sortIdx.end(), 0);
229 if (mNThreads > 1 && mNStrangeTracks > 1) {
230 std::sort(sortIdx.begin(), sortIdx.end(), [&strTracksTmp](
int i1,
int i2) { return strTracksTmp[i1].mDecayRef < strTracksTmp[i2].mDecayRef; });
233 for (
int i = 0;
i < (
int)sortIdx.size();
i++) {
234 strTracksOut[
i] = strTracksTmp[sortIdx[
i]];
235 strClustOut[
i] = strClusTmp[sortIdx[
i]];
237 mcLabsOut[
i] = mcLabTmp[sortIdx[
i]];
242 auto& strTrMCLableOut = pc.
outputs().
make<std::vector<o2::MCCompLabel>>(
o2f::Output{
"GLO",
"STRANGETRACKS_MC", 0});
243 strTrMCLableOut.swap(mcLabsOut);
247 for (
int ith = 0; ith < mNThreads; ith++) {
248 mV0sTmp[ith].clear();
249 mCascadesTmp[ith].clear();
250 m3bodyTmp[ith].clear();
251 mV0sIdxTmp[ith].clear();
252 mCascadesIdxTmp[ith].clear();
253 m3bodyIdxTmp[ith].clear();
256 extractPVReferences(v0sIdx, v0Refs, cascsIdx, cascRefs, body3Idx, vtx3bodyRefs);
265void SVertexer::updateTimeDependentParams()
268 static bool updatedOnce =
false;
273 LOGP(fatal,
"TPC tracks requested but not provided");
311 for (
auto& ft : mFitterV0) {
314 for (
auto& ft : mFitterCasc) {
317 for (
auto& ft : mFitter3body) {
321 mPIDresponse.setBetheBlochParams(mSVParams->
mBBpars);
327 mTPCVDrift =
v.refVDrift *
v.corrFact;
328 mTPCVDriftCorrFact =
v.corrFact;
329 mTPCVDriftRef =
v.refVDrift;
330 mTPCDriftTimeOffset =
v.getTimeOffset();
331 mTPCBin2Z = mTPCVDrift / mMUS2TPCBin;
340void SVertexer::setupThreads()
342 if (!mV0sTmp.empty()) {
345 mV0sTmp.resize(mNThreads);
346 mCascadesTmp.resize(mNThreads);
347 m3bodyTmp.resize(mNThreads);
348 mV0sIdxTmp.resize(mNThreads);
349 mCascadesIdxTmp.resize(mNThreads);
350 m3bodyIdxTmp.resize(mNThreads);
351 mFitterV0.resize(mNThreads);
354 for (
auto& fitter : mFitterV0) {
356 fitter.setFitterID(fitCounter++);
358 fitter.setUseAbsDCA(mSVParams->
useAbsDCA);
359 fitter.setPropagateToPCA(
false);
360 fitter.setMaxR(mSVParams->
maxRIni);
363 fitter.setMaxDZIni(mSVParams->
maxDZIni);
364 fitter.setMaxDXYIni(mSVParams->
maxDXYIni);
365 fitter.setMaxChi2(mSVParams->
maxChi2);
369 fitter.setMaxStep(mSVParams->
maxStep);
370 fitter.setMaxSnp(mSVParams->
maxSnp);
371 fitter.setMinXSeed(mSVParams->
minXSeed);
373 mFitterCasc.resize(mNThreads);
375 for (
auto& fitter : mFitterCasc) {
377 fitter.setFitterID(fitCounter++);
379 fitter.setUseAbsDCA(mSVParams->
useAbsDCA);
380 fitter.setPropagateToPCA(
false);
384 fitter.setMaxDZIni(mSVParams->
maxDZIni);
385 fitter.setMaxDXYIni(mSVParams->
maxDXYIni);
386 fitter.setMaxChi2(mSVParams->
maxChi2);
390 fitter.setMaxStep(mSVParams->
maxStep);
391 fitter.setMaxSnp(mSVParams->
maxSnp);
392 fitter.setMinXSeed(mSVParams->
minXSeed);
395 mFitter3body.resize(mNThreads);
397 for (
auto& fitter : mFitter3body) {
399 fitter.setFitterID(fitCounter++);
401 fitter.setUseAbsDCA(mSVParams->
useAbsDCA);
402 fitter.setPropagateToPCA(
false);
406 fitter.setMaxDZIni(mSVParams->
maxDZIni);
407 fitter.setMaxDXYIni(mSVParams->
maxDXYIni);
408 fitter.setMaxChi2(mSVParams->
maxChi2);
412 fitter.setMaxStep(mSVParams->
maxStep);
413 fitter.setMaxSnp(mSVParams->
maxSnp);
414 fitter.setMinXSeed(mSVParams->
minXSeed);
428 std::array<float, 2> dca;
438 if (!trp.propagateParamToDCA(mMeanVertex.getXYZ(), prop->getNominalBz(), &dca)) {
442 if (std::abs(dca[0]) < mSVParams->
minDCAToPV) {
464 mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCCorrMaps,
o2::base::Propagator::Instance()->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(),
nullptr,
o2::base::Propagator::Instance());
467 std::unordered_map<GIndex, std::pair<int, int>> tmap;
468 std::unordered_map<GIndex, bool> rejmap;
471 int nv = vtxRefs.size() > 0 ? vtxRefs.size() - 1 : 0;
472 for (
int i = 0;
i < 2;
i++) {
473 mTracksPool[
i].clear();
474 mVtxFirstTrack[
i].clear();
475 mVtxFirstTrack[
i].resize(nv, -1);
477 for (
int iv = 0; iv < nv; iv++) {
478 const auto& vtref = vtxRefs[iv];
479 int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries();
480 for (; it < itLim; it++) {
481 auto tvid = trackIndex[it];
491 if (processTPCTrack(mTPCTracksArray[tvid], tvid, iv)) {
496 if (tvid.isAmbiguous()) {
497 auto tref = tmap.find(tvid);
498 if (tref != tmap.end()) {
499 mTracksPool[tref->second.second][tref->second.first].vBracket.setMax(iv);
503 if (rejmap.find(tvid) != rejmap.end()) {
510 bool heavyIonisingParticle =
false;
513 if (tpcGID.isIndexSet() && isTPCloaded) {
516 float dEdxTPC = tpcTrack.getdEdx().dEdxTotTPC;
519 heavyIonisingParticle =
true;
521 auto protonId = o2::track::PID::Proton;
522 float dEdxExpected = mPIDresponse.getExpectedSignal(tpcTrack, protonId);
523 float fracDevProton = std::abs((dEdxTPC - dEdxExpected) / dEdxExpected);
524 if (fracDevProton < mSVParams->mFractiondEdxforCascBaryons) {
525 compatibleWithProton =
true;
531 bool shortOBITSOnlyTrack =
false;
536 nITSclu = itsTrack.getNumberOfClusters();
537 if (itsTrack.hasHitOnLayer(6) && itsTrack.hasHitOnLayer(5) && itsTrack.hasHitOnLayer(4) && itsTrack.hasHitOnLayer(3)) {
538 shortOBITSOnlyTrack =
true;
542 if (isITSTPCloaded) {
543 auto& itsABTracklet = recoData.
getITSABRef(itsGID);
544 nITSclu = itsABTracklet.getNClusters();
547 if (!acceptTrack(tvid, trc) && !heavyIonisingParticle) {
548 if (tvid.isAmbiguous()) {
553 if ((isTPCloaded && !hasTPC) && (isITSloaded && (nITSclu < mSVParams->mITSSAminNclu && (!shortOBITSOnlyTrack || mSVParams->
mRejectITSonlyOBtrack)))) {
557 int posneg = trc.getSign() < 0 ? 1 : 0;
558 float r = std::sqrt(trc.getX() * trc.getX() + trc.getY() * trc.getY());
559 mTracksPool[posneg].emplace_back(TrackCand{trc, tvid, {iv, iv},
r, hasTPC, nITSclu, compatibleWithProton});
561 correctTPCTrack(mTracksPool[posneg].back(), mTPCTracksArray[tvid], -1, -1);
563 if (tvid.isAmbiguous()) {
564 tmap[tvid] = {mTracksPool[posneg].size() - 1, posneg};
569 for (
int pn = 0; pn < 2; pn++) {
570 auto& vtxFirstT = mVtxFirstTrack[pn];
571 const auto& tracksPool = mTracksPool[pn];
572 for (
unsigned i = 0;
i < tracksPool.size();
i++) {
573 const auto& t = tracksPool[
i];
574 for (
int j{t.vBracket.getMin()};
j <= t.vBracket.getMax(); ++
j) {
575 if (vtxFirstT[
j] == -1) {
582 LOG(info) <<
"Collected " << mTracksPool[
POS].size() <<
" positive and " << mTracksPool[
NEG].size() <<
" negative seeds";
586bool SVertexer::checkV0(
const TrackCand& seedP,
const TrackCand& seedN,
int iP,
int iN,
int ithread)
588 auto& fitterV0 = mFitterV0[ithread];
593 if (std::abs(seedP.getTgl() - seedN.getTgl()) > mSVParams->
maxV0TglAbsDiff) {
600 seedP.getCircleParams(mBz, trkPosCircle, sna, csa);
602 seedN.getCircleParams(mBz, trkEleCircle, sna, csa);
604 float c2c = std::hypot(trkPosCircle.
xC - trkEleCircle.
xC,
605 trkPosCircle.
yC - trkEleCircle.
yC);
606 float r2r = trkPosCircle.
rC + trkEleCircle.
rC;
607 float dcr = c2c - r2r;
609 LOG(
debug) <<
"RejD2R " << c2c <<
" " << r2r <<
" " << dcr;
613 float r1_r = trkPosCircle.
rC / r2r;
614 float r2_r = trkEleCircle.
rC / r2r;
615 float dR = std::hypot(r2_r * trkPosCircle.
xC + r1_r * trkEleCircle.
xC, r2_r * trkPosCircle.
yC + r1_r * trkEleCircle.
yC);
625 fitterV0.setCollinear(
true);
629 int nCand = fitterV0.process(seedP, seedN);
632 fitterV0.setMaxDZIni(mSVParams->
maxDZIni);
633 fitterV0.setMaxDXYIni(mSVParams->
maxDXYIni);
634 fitterV0.setMaxChi2(mSVParams->
maxChi2);
635 fitterV0.setCollinear(
false);
642 const auto& v0XYZ = fitterV0.getPCACandidate();
645 float dxv0 = v0XYZ[0] - mMeanVertex.getX(), dyv0 = v0XYZ[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0;
646 if (r2v0 < mMinR2ToMeanVertex) {
647 LOG(
debug) <<
"RejMinR2ToMeanVertex";
650 float rv0 = std::sqrt(r2v0), drv0P = rv0 - seedP.minR, drv0N = rv0 - seedN.minR;
653 LOG(
debug) <<
"RejCausality " << drv0P <<
" " << drv0N;
657 if (!fitterV0.isPropagateTracksToVertexDone(cand) && !fitterV0.propagateTracksToVertex(cand)) {
661 const auto& trPProp = fitterV0.getTrack(0, cand);
662 const auto& trNProp = fitterV0.getTrack(1, cand);
663 std::array<float, 3> pP{}, pN{};
664 trPProp.getPxPyPzGlo(pP);
665 trNProp.getPxPyPzGlo(pN);
670 std::array<float, 3> pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]};
671 float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0;
672 if (pt2V0 < mMinPt2V0) {
676 if (pV0[2] * pV0[2] / pt2V0 > mMaxTgl2V0) {
677 LOG(
debug) <<
"RejTgL " << pV0[2] * pV0[2] / pt2V0;
680 float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0);
682 float p2Pos = pP[0] * pP[0] + pP[1] * pP[1] + pP[2] * pP[2], p2Neg = pN[0] * pN[0] + pN[1] * pN[1] + pN[2] * pN[2];
685 std::array<bool, NHypV0> hypCheckStatus{};
688 if (mV0Hyps[ipid].
check(p2Pos, p2Neg, p2V0, ptV0)) {
689 goodHyp = hypCheckStatus[ipid] =
true;
693 bool goodLamForCascade =
false, goodALamForCascade =
false;
694 bool usesTPCOnly = (seedP.hasTPC && !seedP.hasITS()) || (seedN.hasTPC && !seedN.hasITS());
698 goodLamForCascade =
true;
701 goodALamForCascade =
true;
706 bool good3bodyV0Hyp =
false;
707 for (
int ipid = 2; ipid < 4; ipid++) {
708 float massForLambdaHyp = mV0Hyps[ipid].calcMass(p2Pos, p2Neg, p2V0);
709 if (massForLambdaHyp - mV0Hyps[ipid].getMassV0Hyp() < mV0Hyps[ipid].getMargin(ptV0)) {
710 good3bodyV0Hyp =
true;
716 bool checkFor3BodyDecays = mEnable3BodyDecays &&
720 bool rejectAfter3BodyCheck =
false;
721 bool checkForCascade = mEnableCascades &&
723 r2v0 < mMaxR2ToMeanVertexCascV0 &&
726 bool rejectIfNotCascade =
false;
730 if (!checkFor3BodyDecays && !checkForCascade) {
733 rejectAfter3BodyCheck =
true;
737 float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY;
738 float cosPAXY = prodXYv0 / std::sqrt(r2v0 * pt2V0);
740 if (checkForCascade) {
741 if (dca2 > mMaxDCAXY2ToMeanVertexV0Casc || cosPAXY < mSVParams->minCosPAXYMeanVertexCascV0) {
742 LOG(
debug) <<
"Rej for cascade DCAXY2: " << dca2 <<
" << cosPAXY: " << cosPAXY;
743 if (!checkFor3BodyDecays) {
746 rejectAfter3BodyCheck =
true;
750 if (checkFor3BodyDecays) {
751 if (dca2 > mMaxDCAXY2ToMeanVertex3bodyV0 || cosPAXY < mSVParams->minCosPAXYMeanVertex3bodyV0) {
752 LOG(
debug) <<
"Rej for 3 body decays DCAXY2: " << dca2 <<
" << cosPAXY: " << cosPAXY;
753 checkFor3BodyDecays =
false;
757 if (dca2 > mMaxDCAXY2ToMeanVertex || cosPAXY < mSVParams->minCosPAXYMeanVertex) {
758 if (checkForCascade) {
759 rejectIfNotCascade =
true;
760 }
else if (checkFor3BodyDecays) {
761 rejectAfter3BodyCheck =
true;
774 auto vlist = seedP.vBracket.getOverlap(seedN.vBracket);
775 bool candFound =
false;
777 bestCosPA = checkFor3BodyDecays ? std::min(mSVParams->
minCosPA3bodyV0, bestCosPA) : bestCosPA;
781 for (
int iv = vlist.getMin(); iv <= vlist.getMax(); iv++) {
782 const auto& pv = mPVertices[iv];
783 const auto v0XYZ = fitterV0.getPCACandidatePos(cand);
785 float dx = v0XYZ[0] - pv.getX(), dy = v0XYZ[1] - pv.getY(), dz = v0XYZ[2] - pv.getZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2];
786 float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0);
787 if (cosPA < bestCosPA) {
788 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
792 new (&v0new)
V0(v0XYZ, pV0, fitterV0.calcPCACovMatrixFlat(cand), trPProp, trNProp);
793 new (&v0Idxnew)
V0Index(-1, seedP.gid, seedN.gid);
794 v0new.setDCA(fitterV0.getChi2AtPCACandidate(cand));
797 v0new.setCosPA(cosPA);
804 if (bestCosPA < mSVParams->minCosPACascV0) {
805 rejectAfter3BodyCheck =
true;
807 if (bestCosPA < mSVParams->minCosPA && checkForCascade) {
808 rejectIfNotCascade =
true;
810 int nV0Ini = mV0sIdxTmp[ithread].size();
812 if (checkFor3BodyDecays) {
813 int n3bodyDecays = 0;
814 n3bodyDecays += check3bodyDecays(v0Idxnew, v0new, rv0, pV0, p2V0, iN,
NEG, vlist, ithread);
815 n3bodyDecays += check3bodyDecays(v0Idxnew, v0new, rv0, pV0, p2V0, iP,
POS, vlist, ithread);
817 if (rejectAfter3BodyCheck) {
822 int nCascIni = mCascadesIdxTmp[ithread].size(), nV0Used = 0;
823 if (checkForCascade) {
825 nV0Used += checkCascades(v0Idxnew, v0new, rv0, pV0, p2V0, iN,
NEG, vlist, ithread);
828 nV0Used += checkCascades(v0Idxnew, v0new, rv0, pV0, p2V0, iP,
POS, vlist, ithread);
833 for (
unsigned int ic = nCascIni; ic < mCascadesIdxTmp[ithread].size(); ic++) {
834 if (mCascadesIdxTmp[ithread][ic].getV0ID() == -1) {
835 mCascadesIdxTmp[ithread][ic].setV0ID(nV0Ini);
840 if (nV0Used || !rejectIfNotCascade) {
841 mV0sIdxTmp[ithread].push_back(v0Idxnew);
842 if (!rejectIfNotCascade) {
843 mV0sIdxTmp[ithread].back().setStandaloneV0();
846 mV0sIdxTmp[ithread].back().setPhotonOnly();
847 mV0sIdxTmp[ithread].back().setCollinear();
851 mV0sTmp[ithread].push_back(v0new);
856 for (
int iv = nV0Ini; iv < (
int)mV0sIdxTmp[ithread].
size(); iv++) {
857 mStrTracker->
processV0(iv, v0new, v0Idxnew, ithread);
861 return mV0sIdxTmp[ithread].size() - nV0Ini != 0;
865int SVertexer::checkCascades(
const V0Index& v0Idx,
const V0&
v0,
float rv0, std::array<float, 3> pV0,
float p2V0,
int avoidTrackID,
int posneg, VBracket v0vlist,
int ithread)
868 auto& fitterCasc = mFitterCasc[ithread];
869 auto&
tracks = mTracksPool[posneg];
870 int nCascIni = mCascadesIdxTmp[ithread].size(), nv0use = 0;
873 std::unordered_map<int, int> pvMap;
876 int firstTr = mVtxFirstTrack[posneg][v0vlist.getMin()], nTr =
tracks.size();
880 for (
int it = firstTr; it < nTr; it++) {
881 if (it == avoidTrackID) {
892 if (bach.vBracket.getMin() > v0vlist.getMax()) {
896 auto cascVlist = v0vlist.getOverlap(bach.vBracket);
906 int nCandC = fitterCasc.process(
v0, bach);
911 const auto& cascXYZ = fitterCasc.getPCACandidatePos(candC);
914 float dxc = cascXYZ[0] - mMeanVertex.getX(), dyc = cascXYZ[1] - mMeanVertex.getY(), r2casc = dxc * dxc + dyc * dyc;
915 if (rv0 * rv0 - r2casc < mMinR2DiffV0Casc || r2casc < mMinR2ToMeanVertex) {
920 if (!fitterCasc.isPropagateTracksToVertexDone(candC) && !fitterCasc.propagateTracksToVertex(candC)) {
924 auto& trNeut = fitterCasc.getTrack(0, candC);
925 auto& trBach = fitterCasc.getTrack(1, candC);
926 trNeut.setPID(o2::track::PID::Lambda);
927 trBach.setPID(o2::track::PID::Pion);
928 std::array<float, 3> pNeut, pBach;
929 trNeut.getPxPyPzGlo(pNeut);
930 trBach.getPxPyPzGlo(pBach);
931 std::array<float, 3> pCasc = {pNeut[0] + pBach[0], pNeut[1] + pBach[1], pNeut[2] + pBach[2]};
933 float pt2Casc = pCasc[0] * pCasc[0] + pCasc[1] * pCasc[1], p2Casc = pt2Casc + pCasc[2] * pCasc[2];
934 if (pt2Casc < mMinPt2Casc) {
938 if (pCasc[2] * pCasc[2] / pt2Casc > mMaxTgl2Casc) {
939 LOG(
debug) <<
"Casc tgLambda too high";
947 for (
int iv = cascVlist.getMin(); iv <= cascVlist.getMax(); iv++) {
948 const auto& pv = mPVertices[iv];
950 float dx = cascXYZ[0] - pv.getX(), dy = cascXYZ[1] - pv.getY(), dz = cascXYZ[2] - pv.getZ(), prodXYZcasc = dx * pCasc[0] + dy * pCasc[1] + dz * pCasc[2];
951 float cosPA = prodXYZcasc / std::sqrt((dx * dx + dy * dy + dz * dz) * p2Casc);
952 if (cosPA < bestCosPA) {
953 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
959 if (cascVtxID == -1) {
960 LOG(
debug) <<
"Casc not compatible with any vertex";
964 const auto& cascPv = mPVertices[cascVtxID];
965 float dxCasc = cascXYZ[0] - cascPv.getX(), dyCasc = cascXYZ[1] - cascPv.getY(), dzCasc = cascXYZ[2] - cascPv.getZ();
966 auto prodPPos = pV0[0] * dxCasc + pV0[1] * dyCasc + pV0[2] * dzCasc;
968 LOG(
debug) <<
"Casc not causally compatible";
972 float p2Bach = pBach[0] * pBach[0] + pBach[1] * pBach[1] + pBach[2] * pBach[2];
973 float ptCasc = std::sqrt(pt2Casc);
974 bool goodHyp =
false;
976 if (mCascHyps[ipid].
check(p2V0, p2Bach, p2Casc, ptCasc)) {
982 LOG(
debug) <<
"Casc not compatible with any hypothesis";
987 Cascade casc(cascXYZ, pCasc, fitterCasc.calcPCACovMatrixFlat(candC), trNeut, trBach);
990 if (!trc.propagateToDCA(cascPv, fitterCasc.getBz(), &dca, 5.) ||
992 LOG(
debug) <<
"Casc not compatible with PV";
993 LOG(
debug) <<
"DCA: " << dca.getY() <<
" " << dca.getZ();
998 LOGP(
debug,
"cascade successfully validated");
1002 auto pvIdx = pvMap.find(cascVtxID);
1003 if (pvIdx != pvMap.end()) {
1004 cascIdx.setV0ID(pvIdx->second);
1006 const auto& pv = mPVertices[cascVtxID];
1007 cascIdx.setV0ID(mV0sIdxTmp[ithread].
size());
1008 pvMap[cascVtxID] = mV0sTmp[ithread].size();
1009 mV0sIdxTmp[ithread].emplace_back(cascVtxID, v0Idx.
getProngs());
1011 mV0sTmp[ithread].push_back(
v0);
1012 float dx =
v0.getX() - pv.getX(), dy =
v0.getY() - pv.getY(), dz =
v0.getZ() - pv.getZ(), prodXYZ = dx * pV0[0] + dy * pV0[1] + dz * pV0[2];
1013 mV0sTmp[ithread].back().setCosPA(prodXYZ / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0));
1019 mCascadesIdxTmp[ithread].push_back(cascIdx);
1021 casc.setCosPA(bestCosPA);
1022 casc.setDCA(fitterCasc.getChi2AtPCACandidate(candC));
1023 mCascadesTmp[ithread].push_back(casc);
1034int SVertexer::check3bodyDecays(
const V0Index& v0Idx,
const V0&
v0,
float rv0, std::array<float, 3> pV0,
float p2V0,
int avoidTrackID,
int posneg, VBracket v0vlist,
int ithread)
1037 auto& fitter3body = mFitter3body[ithread];
1038 auto&
tracks = mTracksPool[posneg];
1039 int n3BodyIni = m3bodyIdxTmp[ithread].size();
1042 int firstTr = mVtxFirstTrack[posneg][v0vlist.getMin()], nTr =
tracks.size();
1051 for (
int it = firstTr; it < nTr; it++) {
1052 if (it == avoidTrackID) {
1059 if (bach.vBracket > v0vlist.getMax()) {
1063 auto decay3bodyVlist = v0vlist.getOverlap(bach.vBracket);
1073 if (bach.getPt() < 0.6) {
1077 int n3bodyVtx = fitter3body.process(
v0.getProng(0),
v0.getProng(1), bach);
1078 if (n3bodyVtx == 0) {
1082 const auto& vertexXYZ = fitter3body.getPCACandidatePos(cand3B);
1085 float dxc = vertexXYZ[0] - mMeanVertex.getX(), dyc = vertexXYZ[1] - mMeanVertex.getY(), dzc = vertexXYZ[2] - mMeanVertex.getZ(), r2vertex = dxc * dxc + dyc * dyc;
1086 if (std::abs(rv0 - std::sqrt(r2vertex)) > mSVParams->
maxRDiffV03body || r2vertex < mMinR2ToMeanVertex) {
1089 float drvtxBach = std::sqrt(r2vertex) - bach.minR;
1090 if (drvtxBach > mSVParams->
causalityRTolerance || drvtxBach < -mSVParams->maxV0ToProngsRDiff) {
1091 LOG(
debug) <<
"RejCausality " << drvtxBach;
1094 if (!fitter3body.isPropagateTracksToVertexDone() && !fitter3body.propagateTracksToVertex()) {
1098 auto& tr0 = fitter3body.getTrack(0, cand3B);
1099 auto& tr1 = fitter3body.getTrack(1, cand3B);
1100 auto& tr2 = fitter3body.getTrack(2, cand3B);
1101 std::array<float, 3>
p0,
p1,
p2;
1102 tr0.getPxPyPzGlo(p0);
1103 tr1.getPxPyPzGlo(
p1);
1104 tr2.getPxPyPzGlo(
p2);
1106 bool goodHyp =
false;
1108 auto decay3bodyVtxID = -1;
1111 std::array<float, 3> pbach = {0, 0, 0}, p3B = {0, 0, 0};
1112 for (
int ipid = 0; ipid <
NHyp3body; ipid++) {
1114 float bachChargeFactor = m3bodyHyps[ipid].getChargeBachProng() / tr2.getAbsCharge();
1115 pbach = {bachChargeFactor *
p2[0], bachChargeFactor *
p2[1], bachChargeFactor *
p2[2]};
1116 p3B = {
p0[0] +
p1[0] + pbach[0],
p0[1] +
p1[1] + pbach[1],
p0[2] +
p1[2] + pbach[2]};
1117 float sqP0 =
p0[0] *
p0[0] +
p0[1] *
p0[1] +
p0[2] *
p0[2], sqP1 =
p1[0] *
p1[0] +
p1[1] *
p1[1] +
p1[2] *
p1[2], sqPBach = pbach[0] * pbach[0] + pbach[1] * pbach[1] + pbach[2] * pbach[2];
1118 float pt2Candidate = p3B[0] * p3B[0] + p3B[1] * p3B[1], p2Candidate = pt2Candidate + p3B[2] * p3B[2];
1119 float ptCandidate = std::sqrt(pt2Candidate);
1120 if (m3bodyHyps[ipid].
check(sqP0, sqP1, sqPBach, p2Candidate, ptCandidate)) {
1121 if (pt2Candidate < mMinPt23Body) {
1124 if (p3B[2] * p3B[2] > pt2Candidate * mMaxTgl23Body) {
1130 for (
int iv = decay3bodyVlist.getMin(); iv <= decay3bodyVlist.getMax(); iv++) {
1131 const auto& pv = mPVertices[iv];
1133 float dx = vertexXYZ[0] - pv.getX(), dy = vertexXYZ[1] - pv.getY(), dz = vertexXYZ[2] - pv.getZ(), prodXYZ3body = dx * p3B[0] + dy * p3B[1] + dz * p3B[2];
1134 float cosPA = prodXYZ3body / std::sqrt((dx * dx + dy * dy + dz * dz) * p2Candidate);
1135 if (cosPA < bestCosPA) {
1136 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
1139 decay3bodyVtxID = iv;
1142 if (decay3bodyVtxID == -1) {
1143 LOG(
debug) <<
"3-body decay not compatible with any vertex";
1148 pidHyp = m3bodyHyps[ipid].getPIDHyp();
1149 vtxCosPA = bestCosPA;
1157 const auto& decay3bodyPv = mPVertices[decay3bodyVtxID];
1158 Decay3Body candidate3B(vertexXYZ, p3B, fitter3body.calcPCACovMatrixFlat(cand3B), tr0, tr1, tr2, pidHyp);
1161 if (!trc.propagateToDCA(decay3bodyPv, fitter3body.getBz(), &dca, 5.) ||
1166 candidate3B.setCosPA(vtxCosPA);
1167 candidate3B.setDCA(fitter3body.getChi2AtPCACandidate());
1168 m3bodyTmp[ithread].push_back(candidate3B);
1170 m3bodyIdxTmp[ithread].emplace_back(decay3bodyVtxID, v0Idx.
getProngID(0), v0Idx.
getProngID(1), bach.gid);
1174 mStrTracker->
process3Body(m3bodyIdxTmp[ithread].
size() - 1, candidate3B, decay3bodyIdx, ithread);
1177 return m3bodyIdxTmp[ithread].size() - n3BodyIni;
1181template <
class TVI,
class TCI,
class T3I,
class TR>
1182void SVertexer::extractPVReferences(
const TVI& v0s, TR& vtx2V0Refs,
const TCI& cascades, TR& vtx2CascRefs,
const T3I& vtx3, TR& vtx2body3Refs)
1186 vtx2V0Refs.resize(mPVertices.size());
1187 vtx2CascRefs.clear();
1188 vtx2CascRefs.resize(mPVertices.size());
1189 vtx2body3Refs.clear();
1190 vtx2body3Refs.resize(mPVertices.size());
1191 int nv0 = v0s.size(), nCasc = cascades.size(), n3body = vtx3.size();
1194 int pvID = -1, nForPV = 0;
1195 for (
int iv = 0; iv < nv0; iv++) {
1196 if (pvID < v0s[iv].getVertexID()) {
1198 vtx2V0Refs[pvID].setEntries(nForPV);
1200 pvID = v0s[iv].getVertexID();
1201 vtx2V0Refs[pvID].setFirstEntry(iv);
1207 vtx2V0Refs[pvID].setEntries(nForPV);
1210 for (
int ip = vtx2V0Refs.size(); ip--;) {
1211 if (vtx2V0Refs[ip].getEntries()) {
1212 ent = vtx2V0Refs[ip].getFirstEntry();
1214 vtx2V0Refs[ip].setFirstEntry(ent);
1222 for (
int iv = 0; iv < nCasc; iv++) {
1223 if (pvID < cascades[iv].getVertexID()) {
1225 vtx2CascRefs[pvID].setEntries(nForPV);
1227 pvID = cascades[iv].getVertexID();
1228 vtx2CascRefs[pvID].setFirstEntry(iv);
1234 vtx2CascRefs[pvID].setEntries(nForPV);
1237 for (
int ip = vtx2CascRefs.size(); ip--;) {
1238 if (vtx2CascRefs[ip].getEntries()) {
1239 ent = vtx2CascRefs[ip].getFirstEntry();
1241 vtx2CascRefs[ip].setFirstEntry(ent);
1249 for (
int iv = 0; iv < n3body; iv++) {
1250 const auto& vertex3body = vtx3[iv];
1251 if (pvID < vertex3body.getVertexID()) {
1253 vtx2body3Refs[pvID].setEntries(nForPV);
1255 pvID = vertex3body.getVertexID();
1256 vtx2body3Refs[pvID].setFirstEntry(iv);
1262 vtx2body3Refs[pvID].setEntries(nForPV);
1265 for (
int ip = vtx2body3Refs.size(); ip--;) {
1266 if (vtx2body3Refs[ip].getEntries()) {
1267 ent = vtx2body3Refs[ip].getFirstEntry();
1269 vtx2body3Refs[ip].setFirstEntry(ent);
1279 mNThreads =
n > 0 ?
n : 1;
1292 if (trTPC.hasBothSidesClusters()) {
1295 const auto& vtx = mPVertices[vtxid];
1296 auto twe = vtx.getTimeStamp();
1297 int posneg = trTPC.getSign() < 0 ? 1 : 0;
1299 bool compatibleWithProton =
false;
1302 const auto protonId = o2::track::PID::Proton;
1303 float dEdxTPC = trTPC.getdEdx().dEdxTotTPC;
1304 float dEdxExpected = mPIDresponse.getExpectedSignal(trTPC, protonId);
1305 float fracDevProton = std::abs((dEdxTPC - dEdxExpected) / dEdxExpected);
1306 if (fracDevProton < mSVParams->mFractiondEdxforCascBaryons) {
1307 compatibleWithProton =
true;
1311 auto& trLoc = mTracksPool[posneg].emplace_back(TrackCand{trTPC, gid, {vtxid, vtxid}, 0.,
true, -1, compatibleWithProton});
1312 auto err = correctTPCTrack(trLoc, trTPC, twe.getTimeStamp(), twe.getTimeStampError());
1314 mTracksPool[posneg].pop_back();
1322 bool dDPV = std::abs(trLoc.getX() * trLoc.getTgl() - trLoc.getZ() + vtx.getZ()) > mSVParams->
mTPCTrack2Beam;
1324 float sna{0}, csa{0};
1326 trLoc.getCircleParams(mBz, trkCircle, sna, csa);
1327 float cR = std::hypot(trkCircle.
xC, trkCircle.
yC);
1328 float drd2 = std::sqrt(cR * cR - trkCircle.
rC * trkCircle.
rC);
1331 if (dCls || dDPV || dRD2) {
1332 mTracksPool[posneg].pop_back();
1351 tTB = tTPC.getTime0();
1352 tTBErr = 0.5 * (tTPC.getDeltaTBwd() + tTPC.getDeltaTFwd());
1354 tTB = tmus * mMUS2TPCBin;
1355 tTBErr = tmusErr * mMUS2TPCBin;
1357 float dDrift = (tTB - tTPC.getTime0()) * mTPCBin2Z;
1358 float driftErr = tTBErr * mTPCBin2Z;
1359 if (driftErr < 0.) {
1363 trc.setZ(tTPC.getZ() + (tTPC.hasASideClustersOnly() ? dDrift : -dDrift));
1366 auto cl = &tTPC.getCluster(mTPCTrackClusIdx, tTPC.getNClusters() - 1, *mTPCClusterIdxStruct, sector,
row);
1367 float x = 0,
y = 0,
z = 0;
1368 mTPCCorrMaps->Transform(sector,
row, cl->getPad(), cl->getTime(),
x,
y,
z, tTB);
1372 trc.
minR = std::sqrt(
x *
x +
y *
y);
1373 LOGP(
debug,
"set MinR = {} for row {}, x:{}, y:{}, z:{}", trc.
minR,
row,
x,
y,
z);
1380 std::array<size_t, 3> calls{};
1381 for (
int i = 0;
i < mNThreads;
i++) {
1382 calls[0] += mFitterV0[
i].getCallID();
1383 calls[1] += mFitterCasc[
i].getCallID();
1384 calls[2] += mFitter3body[
i].getCallID();
Some ALICE geometry constants of common interest.
Global index for barrel track: provides provenance (detectors combination), index in respective array...
constexpr int p1()
constexpr to accelerate the coordinates changing
Reference on ITS/MFT clusters set.
calibration data from laser track calibration
Helper class to obtain TPC clusters / digits / labels from DPL.
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
static const SVertexerParams & Instance()
TO BE DONE: extend to generic N body vertex.
GIndex getProngID(int i) const
const std::array< GIndex, N > & getProngs() const
decltype(auto) make(const Output &spec, Args... args)
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
void processV0(int iv0, const V0 &v0, const V0Index &v0Idx, int iThread=0)
std::vector< StrangeTrack > & getStrangeTrackVec(int iThread=0)
void processCascade(int icasc, const Cascade &casc, const CascadeIndex &cascIdx, const V0 &cascV0, int iThread=0)
std::vector< ClusAttachments > & getClusAttachments(int iThread=0)
void process3Body(int i3body, const Decay3Body &dec3body, const Decay3BodyIndex &dec3bodyIdx, int iThread=0)
size_t getNTracks(int ithread=0) const
bool loadData(const o2::globaltracking::RecoContainer &recoData)
std::vector< o2::MCCompLabel > & getStrangeTrackLabels(int iThread=0)
bool getMCTruthOn() const
std::array< size_t, 3 > getNFitterCalls() const
void setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD *maph)
void process(const o2::globaltracking::RecoContainer &recoTracks, o2::framework::ProcessingContext &pc)
void setTPCVDrift(const o2::tpc::VDriftCorrFact &v)
o2::dataformats::V0Index V0Index
void produceOutput(o2::framework::ProcessingContext &pc)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
GLdouble GLdouble GLdouble z
uint8_t itsSharedClusterMap uint8_t
constexpr float XTPCInnerRef
reference radius at which TPC provides the tracks
Defining ITS Vertex explicitly as messageable.
void check(const std::vector< std::string > &arguments, const std::vector< ConfigParamSpec > &workflowOptions, const std::vector< DeviceSpec > &deviceSpecs, CheckMatrix &matrix)
std::vector< T, fair::mq::pmr::polymorphic_allocator< T > > vector
struct o2::upgrades_utils::@469 tracks
structure to keep trigger-related info
GTrackID getITSContributorGID(GTrackID source) const
bool isTrackSourceLoaded(int src) const
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
auto getPrimaryVertices() const
auto getPrimaryVertexMatchedTracks() const
auto getTPCTracksClusterRefs() const
auto getPrimaryVertexMatchedTrackRefs() const
const o2::itsmft::TrkClusRef & getITSABRef(GTrackID gid) const
GTrackID getTPCContributorGID(GTrackID source) const
const o2::track::TrackParCov & getTrackParam(GTrackID gidx) const
gsl::span< const unsigned char > clusterShMapTPC
externally set TPC clusters sharing map
const o2::its::TrackITS & getITSTrack(GTrackID gid) const
std::unique_ptr< o2::tpc::internal::getWorkflowTPCInput_ret > inputsTPCclusters
auto getTPCTracks() const
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
int maxPVContributors
max number PV contributors to allow in V0
float pidCutsHhydrog4[SVertexHypothesis::NPIDParams]
float minCosPA
min cos of PA to PV for prompt V0 candidates
bool mRejectITSonlyOBtrack
float pidCutsHe5L3body[SVertex3Hypothesis::NPIDParams]
float maxDCAXYToMeanVertex
max DCA of V0 from beam line (mean vertex) for prompt V0 candidates
float pidCutsPhoton[SVertexHypothesis::NPIDParams]
bool useAbsDCA
use abs dca minimization
bool usePropagator
use external propagator
float maxDCAXYToMeanVertex3bodyV0
max DCA of V0 from beam line (mean vertex) for 3body V0 candidates
float maxRIni
don't consider as a seed (circles intersection) if its R exceeds this
uint8_t mITSSAminNcluCascades
bool checkCascadeHypothesis
bool createFullCascades
fill cascades prongs/kinematics
float maxDCAXYToMeanVertexV0Casc
max DCA of V0 from beam line (mean vertex) for cascade V0 candidates
float minParamChange
stop when tracks X-params being minimized change by less that this value
float causalityRTolerance
V0 radius cannot exceed its contributors minR by more than this value.
float maxSnp
max snp when external propagator is used
float minXSeed
minimal X of seed in prong frame (within the radial resolution track should not go to negative X)
float maximalCascadeWidth
int matCorr
material correction to use
int mTPCTrackMinNClusters
float maxV0TglAbsDiff
max absolute difference in Tgl for V0 for photons only
float maxDZIni
don't consider as a seed (circles intersection) if Z distance exceeds this
float maxStep
max step size when external propagator is used
float pidCutsK0[SVertexHypothesis::NPIDParams]
float pidCutsHe4L3body[SVertex3Hypothesis::NPIDParams]
float minPtV0
v0 minimum pT
float minPtV0FromCascade
v0 minimum pT for v0 to be used in cascading (lowest pT Run 2 lambda: 0.4)
float mTPCTrackMaxDCAXY2ToMeanVertex
max DCA^2 of V0 from beam line (mean vertex) for prompt V0 candidates, for photon TPC-only track only
bool mRequireTPCforCascBaryons
float pidCutsLambda[SVertexHypothesis::NPIDParams]
bool createFull3Bodies
fill 3-body decays prongs/kinematics
float minRelChi2Change
stop when chi2 changes by less than this value
float maxChi2
max dca from prongs to vertex
bool selectBestV0
match only the best v0 for each cascade candidate
float mFractiondEdxforCascBaryons
float minRFor3DField
above this radius use 3D field
bool refitWithMatCorr
refit V0 applying material corrections
float pidCutsH3L3body[SVertex3Hypothesis::NPIDParams]
float minRDiffV0Casc
cascade should be at least this radial distance below V0
float pidCutsOmegaMinus[SVertexHypothesis::NPIDParams]
float minRToMeanVertex
min radial distance of V0 from beam line (mean vertex)
float pidCutsXiMinus[SVertexHypothesis::NPIDParams]
float maxRDiffV03body
Maximum difference between V0 and 3body radii.
float mTPCTrackMaxDXYIni
don't consider as a seed (circles intersection) if XY distance exceeds this, for photon TPC-only trac...
float minDCAToPV
min DCA to PV of single track to accept
float mTPCTrackMaxDZIni
don't consider as a seed (circles intersection) if Z distance exceeds this, for photon TPC-only track...
float pidCutsHTriton[SVertexHypothesis::NPIDParams]
float maxDXYIni
don't consider as a seed (circles intersection) if XY distance exceeds this
float maxRToMeanVertexCascV0
float mTPCTrackMaxChi2
max DCA from prongs to vertex for photon TPC-only track only
float pidCutsH4L3body[SVertex3Hypothesis::NPIDParams]
bool oldDCAFitterMode
pre(old) or post(new) PR15610+15784 behaviour of DCAFitter
bool createFullV0s
fill V0s prongs/kinematics
float maxTglV0
maximum tgLambda of V0
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"