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) {
355 fitter.setFitterID(fitCounter++);
357 fitter.setUseAbsDCA(mSVParams->
useAbsDCA);
358 fitter.setPropagateToPCA(
false);
359 fitter.setMaxR(mSVParams->
maxRIni);
362 fitter.setMaxDZIni(mSVParams->
maxDZIni);
363 fitter.setMaxDXYIni(mSVParams->
maxDXYIni);
364 fitter.setMaxChi2(mSVParams->
maxChi2);
368 fitter.setMaxStep(mSVParams->
maxStep);
369 fitter.setMaxSnp(mSVParams->
maxSnp);
370 fitter.setMinXSeed(mSVParams->
minXSeed);
372 mFitterCasc.resize(mNThreads);
374 for (
auto& fitter : mFitterCasc) {
375 fitter.setFitterID(fitCounter++);
377 fitter.setUseAbsDCA(mSVParams->
useAbsDCA);
378 fitter.setPropagateToPCA(
false);
382 fitter.setMaxDZIni(mSVParams->
maxDZIni);
383 fitter.setMaxDXYIni(mSVParams->
maxDXYIni);
384 fitter.setMaxChi2(mSVParams->
maxChi2);
388 fitter.setMaxStep(mSVParams->
maxStep);
389 fitter.setMaxSnp(mSVParams->
maxSnp);
390 fitter.setMinXSeed(mSVParams->
minXSeed);
393 mFitter3body.resize(mNThreads);
395 for (
auto& fitter : mFitter3body) {
396 fitter.setFitterID(fitCounter++);
398 fitter.setUseAbsDCA(mSVParams->
useAbsDCA);
399 fitter.setPropagateToPCA(
false);
403 fitter.setMaxDZIni(mSVParams->
maxDZIni);
404 fitter.setMaxDXYIni(mSVParams->
maxDXYIni);
405 fitter.setMaxChi2(mSVParams->
maxChi2);
409 fitter.setMaxStep(mSVParams->
maxStep);
410 fitter.setMaxSnp(mSVParams->
maxSnp);
411 fitter.setMinXSeed(mSVParams->
minXSeed);
425 std::array<float, 2> dca;
435 if (!trp.propagateParamToDCA(mMeanVertex.getXYZ(), prop->getNominalBz(), &dca)) {
439 if (std::abs(dca[0]) < mSVParams->
minDCAToPV) {
461 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());
464 std::unordered_map<GIndex, std::pair<int, int>> tmap;
465 std::unordered_map<GIndex, bool> rejmap;
468 int nv = vtxRefs.size() > 0 ? vtxRefs.size() - 1 : 0;
469 for (
int i = 0;
i < 2;
i++) {
470 mTracksPool[
i].clear();
471 mVtxFirstTrack[
i].clear();
472 mVtxFirstTrack[
i].resize(nv, -1);
474 for (
int iv = 0; iv < nv; iv++) {
475 const auto& vtref = vtxRefs[iv];
476 int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries();
477 for (; it < itLim; it++) {
478 auto tvid = trackIndex[it];
488 if (processTPCTrack(mTPCTracksArray[tvid], tvid, iv)) {
493 if (tvid.isAmbiguous()) {
494 auto tref = tmap.find(tvid);
495 if (tref != tmap.end()) {
496 mTracksPool[tref->second.second][tref->second.first].vBracket.setMax(iv);
500 if (rejmap.find(tvid) != rejmap.end()) {
507 bool heavyIonisingParticle =
false;
510 if (tpcGID.isIndexSet() && isTPCloaded) {
513 float dEdxTPC = tpcTrack.getdEdx().dEdxTotTPC;
516 heavyIonisingParticle =
true;
519 float dEdxExpected = mPIDresponse.getExpectedSignal(tpcTrack, protonId);
520 float fracDevProton = std::abs((dEdxTPC - dEdxExpected) / dEdxExpected);
521 if (fracDevProton < mSVParams->mFractiondEdxforCascBaryons) {
522 compatibleWithProton =
true;
528 bool shortOBITSOnlyTrack =
false;
533 nITSclu = itsTrack.getNumberOfClusters();
534 if (itsTrack.hasHitOnLayer(6) && itsTrack.hasHitOnLayer(5) && itsTrack.hasHitOnLayer(4) && itsTrack.hasHitOnLayer(3)) {
535 shortOBITSOnlyTrack =
true;
539 if (isITSTPCloaded) {
540 auto& itsABTracklet = recoData.
getITSABRef(itsGID);
541 nITSclu = itsABTracklet.getNClusters();
544 if (!acceptTrack(tvid, trc) && !heavyIonisingParticle) {
545 if (tvid.isAmbiguous()) {
550 if ((isTPCloaded && !hasTPC) && (isITSloaded && (nITSclu < mSVParams->mITSSAminNclu && (!shortOBITSOnlyTrack || mSVParams->
mRejectITSonlyOBtrack)))) {
554 int posneg = trc.getSign() < 0 ? 1 : 0;
555 float r = std::sqrt(trc.getX() * trc.getX() + trc.getY() * trc.getY());
556 mTracksPool[posneg].emplace_back(TrackCand{trc, tvid, {iv, iv},
r, hasTPC, nITSclu, compatibleWithProton});
558 correctTPCTrack(mTracksPool[posneg].back(), mTPCTracksArray[tvid], -1, -1);
560 if (tvid.isAmbiguous()) {
561 tmap[tvid] = {mTracksPool[posneg].size() - 1, posneg};
566 for (
int pn = 0; pn < 2; pn++) {
567 auto& vtxFirstT = mVtxFirstTrack[pn];
568 const auto& tracksPool = mTracksPool[pn];
569 for (
unsigned i = 0;
i < tracksPool.size();
i++) {
570 const auto& t = tracksPool[
i];
571 for (
int j{t.vBracket.getMin()};
j <= t.vBracket.getMax(); ++
j) {
572 if (vtxFirstT[
j] == -1) {
579 LOG(info) <<
"Collected " << mTracksPool[
POS].size() <<
" positive and " << mTracksPool[
NEG].size() <<
" negative seeds";
583bool SVertexer::checkV0(
const TrackCand& seedP,
const TrackCand& seedN,
int iP,
int iN,
int ithread)
585 auto& fitterV0 = mFitterV0[ithread];
590 if (std::abs(seedP.getTgl() - seedN.getTgl()) > mSVParams->
maxV0TglAbsDiff) {
597 seedP.getCircleParams(mBz, trkPosCircle, sna, csa);
599 seedN.getCircleParams(mBz, trkEleCircle, sna, csa);
601 float c2c = std::hypot(trkPosCircle.
xC - trkEleCircle.
xC,
602 trkPosCircle.
yC - trkEleCircle.
yC);
603 float r2r = trkPosCircle.
rC + trkEleCircle.
rC;
604 float dcr = c2c - r2r;
606 LOG(
debug) <<
"RejD2R " << c2c <<
" " << r2r <<
" " << dcr;
610 float r1_r = trkPosCircle.
rC / r2r;
611 float r2_r = trkEleCircle.
rC / r2r;
612 float dR = std::hypot(r2_r * trkPosCircle.
xC + r1_r * trkEleCircle.
xC, r2_r * trkPosCircle.
yC + r1_r * trkEleCircle.
yC);
622 fitterV0.setCollinear(
true);
626 int nCand = fitterV0.process(seedP, seedN);
629 fitterV0.setMaxDZIni(mSVParams->
maxDZIni);
630 fitterV0.setMaxDXYIni(mSVParams->
maxDXYIni);
631 fitterV0.setMaxChi2(mSVParams->
maxChi2);
632 fitterV0.setCollinear(
false);
639 const auto& v0XYZ = fitterV0.getPCACandidate();
642 float dxv0 = v0XYZ[0] - mMeanVertex.getX(), dyv0 = v0XYZ[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0;
643 if (r2v0 < mMinR2ToMeanVertex) {
644 LOG(
debug) <<
"RejMinR2ToMeanVertex";
647 float rv0 = std::sqrt(r2v0), drv0P = rv0 - seedP.minR, drv0N = rv0 - seedN.minR;
650 LOG(
debug) <<
"RejCausality " << drv0P <<
" " << drv0N;
654 if (!fitterV0.isPropagateTracksToVertexDone(cand) && !fitterV0.propagateTracksToVertex(cand)) {
658 const auto& trPProp = fitterV0.getTrack(0, cand);
659 const auto& trNProp = fitterV0.getTrack(1, cand);
660 std::array<float, 3> pP{}, pN{};
661 trPProp.getPxPyPzGlo(pP);
662 trNProp.getPxPyPzGlo(pN);
667 std::array<float, 3> pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]};
668 float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0;
669 if (pt2V0 < mMinPt2V0) {
673 if (pV0[2] * pV0[2] / pt2V0 > mMaxTgl2V0) {
674 LOG(
debug) <<
"RejTgL " << pV0[2] * pV0[2] / pt2V0;
677 float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0);
679 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];
682 std::array<bool, NHypV0> hypCheckStatus{};
685 if (mV0Hyps[ipid].
check(p2Pos, p2Neg, p2V0, ptV0)) {
686 goodHyp = hypCheckStatus[ipid] =
true;
690 bool goodLamForCascade =
false, goodALamForCascade =
false;
691 bool usesTPCOnly = (seedP.hasTPC && !seedP.hasITS()) || (seedN.hasTPC && !seedN.hasITS());
695 goodLamForCascade =
true;
698 goodALamForCascade =
true;
703 bool good3bodyV0Hyp =
false;
704 for (
int ipid = 2; ipid < 4; ipid++) {
705 float massForLambdaHyp = mV0Hyps[ipid].calcMass(p2Pos, p2Neg, p2V0);
706 if (massForLambdaHyp - mV0Hyps[ipid].getMassV0Hyp() < mV0Hyps[ipid].getMargin(ptV0)) {
707 good3bodyV0Hyp =
true;
713 bool checkFor3BodyDecays = mEnable3BodyDecays &&
717 bool rejectAfter3BodyCheck =
false;
718 bool checkForCascade = mEnableCascades &&
720 r2v0 < mMaxR2ToMeanVertexCascV0 &&
723 bool rejectIfNotCascade =
false;
727 if (!checkFor3BodyDecays && !checkForCascade) {
730 rejectAfter3BodyCheck =
true;
734 float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY;
735 float cosPAXY = prodXYv0 / std::sqrt(r2v0 * pt2V0);
737 if (checkForCascade) {
738 if (dca2 > mMaxDCAXY2ToMeanVertexV0Casc || cosPAXY < mSVParams->minCosPAXYMeanVertexCascV0) {
739 LOG(
debug) <<
"Rej for cascade DCAXY2: " << dca2 <<
" << cosPAXY: " << cosPAXY;
740 if (!checkFor3BodyDecays) {
743 rejectAfter3BodyCheck =
true;
747 if (checkFor3BodyDecays) {
748 if (dca2 > mMaxDCAXY2ToMeanVertex3bodyV0 || cosPAXY < mSVParams->minCosPAXYMeanVertex3bodyV0) {
749 LOG(
debug) <<
"Rej for 3 body decays DCAXY2: " << dca2 <<
" << cosPAXY: " << cosPAXY;
750 checkFor3BodyDecays =
false;
754 if (dca2 > mMaxDCAXY2ToMeanVertex || cosPAXY < mSVParams->minCosPAXYMeanVertex) {
755 if (checkForCascade) {
756 rejectIfNotCascade =
true;
757 }
else if (checkFor3BodyDecays) {
758 rejectAfter3BodyCheck =
true;
771 auto vlist = seedP.vBracket.getOverlap(seedN.vBracket);
772 bool candFound =
false;
774 bestCosPA = checkFor3BodyDecays ? std::min(mSVParams->
minCosPA3bodyV0, bestCosPA) : bestCosPA;
778 for (
int iv = vlist.getMin(); iv <= vlist.getMax(); iv++) {
779 const auto& pv = mPVertices[iv];
780 const auto v0XYZ = fitterV0.getPCACandidatePos(cand);
782 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];
783 float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0);
784 if (cosPA < bestCosPA) {
785 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
789 new (&v0new)
V0(v0XYZ, pV0, fitterV0.calcPCACovMatrixFlat(cand), trPProp, trNProp);
790 new (&v0Idxnew)
V0Index(-1, seedP.gid, seedN.gid);
791 v0new.setDCA(fitterV0.getChi2AtPCACandidate(cand));
794 v0new.setCosPA(cosPA);
801 if (bestCosPA < mSVParams->minCosPACascV0) {
802 rejectAfter3BodyCheck =
true;
804 if (bestCosPA < mSVParams->minCosPA && checkForCascade) {
805 rejectIfNotCascade =
true;
807 int nV0Ini = mV0sIdxTmp[ithread].size();
809 if (checkFor3BodyDecays) {
810 int n3bodyDecays = 0;
811 n3bodyDecays += check3bodyDecays(v0Idxnew, v0new, rv0, pV0, p2V0, iN,
NEG, vlist, ithread);
812 n3bodyDecays += check3bodyDecays(v0Idxnew, v0new, rv0, pV0, p2V0, iP,
POS, vlist, ithread);
814 if (rejectAfter3BodyCheck) {
819 int nCascIni = mCascadesIdxTmp[ithread].size(), nV0Used = 0;
820 if (checkForCascade) {
822 nV0Used += checkCascades(v0Idxnew, v0new, rv0, pV0, p2V0, iN,
NEG, vlist, ithread);
825 nV0Used += checkCascades(v0Idxnew, v0new, rv0, pV0, p2V0, iP,
POS, vlist, ithread);
830 for (
unsigned int ic = nCascIni; ic < mCascadesIdxTmp[ithread].size(); ic++) {
831 if (mCascadesIdxTmp[ithread][ic].getV0ID() == -1) {
832 mCascadesIdxTmp[ithread][ic].setV0ID(nV0Ini);
837 if (nV0Used || !rejectIfNotCascade) {
838 mV0sIdxTmp[ithread].push_back(v0Idxnew);
839 if (!rejectIfNotCascade) {
840 mV0sIdxTmp[ithread].back().setStandaloneV0();
843 mV0sIdxTmp[ithread].back().setPhotonOnly();
844 mV0sIdxTmp[ithread].back().setCollinear();
848 mV0sTmp[ithread].push_back(v0new);
853 for (
int iv = nV0Ini; iv < (
int)mV0sIdxTmp[ithread].
size(); iv++) {
854 mStrTracker->
processV0(iv, v0new, v0Idxnew, ithread);
858 return mV0sIdxTmp[ithread].size() - nV0Ini != 0;
862int 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)
865 auto& fitterCasc = mFitterCasc[ithread];
866 auto&
tracks = mTracksPool[posneg];
867 int nCascIni = mCascadesIdxTmp[ithread].size(), nv0use = 0;
870 std::unordered_map<int, int> pvMap;
873 int firstTr = mVtxFirstTrack[posneg][v0vlist.getMin()], nTr =
tracks.size();
877 for (
int it = firstTr; it < nTr; it++) {
878 if (it == avoidTrackID) {
889 if (bach.vBracket.getMin() > v0vlist.getMax()) {
893 auto cascVlist = v0vlist.getOverlap(bach.vBracket);
903 int nCandC = fitterCasc.process(
v0, bach);
908 const auto& cascXYZ = fitterCasc.getPCACandidatePos(candC);
911 float dxc = cascXYZ[0] - mMeanVertex.getX(), dyc = cascXYZ[1] - mMeanVertex.getY(), r2casc = dxc * dxc + dyc * dyc;
912 if (rv0 * rv0 - r2casc < mMinR2DiffV0Casc || r2casc < mMinR2ToMeanVertex) {
917 if (!fitterCasc.isPropagateTracksToVertexDone(candC) && !fitterCasc.propagateTracksToVertex(candC)) {
921 auto& trNeut = fitterCasc.getTrack(0, candC);
922 auto& trBach = fitterCasc.getTrack(1, candC);
925 std::array<float, 3> pNeut, pBach;
926 trNeut.getPxPyPzGlo(pNeut);
927 trBach.getPxPyPzGlo(pBach);
928 std::array<float, 3> pCasc = {pNeut[0] + pBach[0], pNeut[1] + pBach[1], pNeut[2] + pBach[2]};
930 float pt2Casc = pCasc[0] * pCasc[0] + pCasc[1] * pCasc[1], p2Casc = pt2Casc + pCasc[2] * pCasc[2];
931 if (pt2Casc < mMinPt2Casc) {
935 if (pCasc[2] * pCasc[2] / pt2Casc > mMaxTgl2Casc) {
936 LOG(
debug) <<
"Casc tgLambda too high";
944 for (
int iv = cascVlist.getMin(); iv <= cascVlist.getMax(); iv++) {
945 const auto& pv = mPVertices[iv];
947 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];
948 float cosPA = prodXYZcasc / std::sqrt((dx * dx + dy * dy + dz * dz) * p2Casc);
949 if (cosPA < bestCosPA) {
950 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
956 if (cascVtxID == -1) {
957 LOG(
debug) <<
"Casc not compatible with any vertex";
961 const auto& cascPv = mPVertices[cascVtxID];
962 float dxCasc = cascXYZ[0] - cascPv.getX(), dyCasc = cascXYZ[1] - cascPv.getY(), dzCasc = cascXYZ[2] - cascPv.getZ();
963 auto prodPPos = pV0[0] * dxCasc + pV0[1] * dyCasc + pV0[2] * dzCasc;
965 LOG(
debug) <<
"Casc not causally compatible";
969 float p2Bach = pBach[0] * pBach[0] + pBach[1] * pBach[1] + pBach[2] * pBach[2];
970 float ptCasc = std::sqrt(pt2Casc);
971 bool goodHyp =
false;
973 if (mCascHyps[ipid].
check(p2V0, p2Bach, p2Casc, ptCasc)) {
979 LOG(
debug) <<
"Casc not compatible with any hypothesis";
984 Cascade casc(cascXYZ, pCasc, fitterCasc.calcPCACovMatrixFlat(candC), trNeut, trBach);
987 if (!trc.propagateToDCA(cascPv, fitterCasc.getBz(), &dca, 5.) ||
989 LOG(
debug) <<
"Casc not compatible with PV";
990 LOG(
debug) <<
"DCA: " << dca.getY() <<
" " << dca.getZ();
995 LOGP(
debug,
"cascade successfully validated");
999 auto pvIdx = pvMap.find(cascVtxID);
1000 if (pvIdx != pvMap.end()) {
1001 cascIdx.setV0ID(pvIdx->second);
1003 const auto& pv = mPVertices[cascVtxID];
1004 cascIdx.setV0ID(mV0sIdxTmp[ithread].
size());
1005 pvMap[cascVtxID] = mV0sTmp[ithread].size();
1006 mV0sIdxTmp[ithread].emplace_back(cascVtxID, v0Idx.
getProngs());
1008 mV0sTmp[ithread].push_back(
v0);
1009 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];
1010 mV0sTmp[ithread].back().setCosPA(prodXYZ / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0));
1016 mCascadesIdxTmp[ithread].push_back(cascIdx);
1018 casc.setCosPA(bestCosPA);
1019 casc.setDCA(fitterCasc.getChi2AtPCACandidate(candC));
1020 mCascadesTmp[ithread].push_back(casc);
1031int 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)
1034 auto& fitter3body = mFitter3body[ithread];
1035 auto&
tracks = mTracksPool[posneg];
1036 int n3BodyIni = m3bodyIdxTmp[ithread].size();
1039 int firstTr = mVtxFirstTrack[posneg][v0vlist.getMin()], nTr =
tracks.size();
1048 for (
int it = firstTr; it < nTr; it++) {
1049 if (it == avoidTrackID) {
1056 if (bach.vBracket > v0vlist.getMax()) {
1060 auto decay3bodyVlist = v0vlist.getOverlap(bach.vBracket);
1070 if (bach.getPt() < 0.6) {
1074 int n3bodyVtx = fitter3body.process(
v0.getProng(0),
v0.getProng(1), bach);
1075 if (n3bodyVtx == 0) {
1079 const auto& vertexXYZ = fitter3body.getPCACandidatePos(cand3B);
1082 float dxc = vertexXYZ[0] - mMeanVertex.getX(), dyc = vertexXYZ[1] - mMeanVertex.getY(), dzc = vertexXYZ[2] - mMeanVertex.getZ(), r2vertex = dxc * dxc + dyc * dyc;
1083 if (std::abs(rv0 - std::sqrt(r2vertex)) > mSVParams->
maxRDiffV03body || r2vertex < mMinR2ToMeanVertex) {
1086 float drvtxBach = std::sqrt(r2vertex) - bach.minR;
1087 if (drvtxBach > mSVParams->
causalityRTolerance || drvtxBach < -mSVParams->maxV0ToProngsRDiff) {
1088 LOG(
debug) <<
"RejCausality " << drvtxBach;
1091 if (!fitter3body.isPropagateTracksToVertexDone() && !fitter3body.propagateTracksToVertex()) {
1095 auto& tr0 = fitter3body.getTrack(0, cand3B);
1096 auto& tr1 = fitter3body.getTrack(1, cand3B);
1097 auto& tr2 = fitter3body.getTrack(2, cand3B);
1098 std::array<float, 3>
p0,
p1,
p2;
1099 tr0.getPxPyPzGlo(p0);
1100 tr1.getPxPyPzGlo(
p1);
1101 tr2.getPxPyPzGlo(
p2);
1103 bool goodHyp =
false;
1105 auto decay3bodyVtxID = -1;
1108 std::array<float, 3> pbach = {0, 0, 0}, p3B = {0, 0, 0};
1109 for (
int ipid = 0; ipid <
NHyp3body; ipid++) {
1111 float bachChargeFactor = m3bodyHyps[ipid].getChargeBachProng() / tr2.getAbsCharge();
1112 pbach = {bachChargeFactor *
p2[0], bachChargeFactor *
p2[1], bachChargeFactor *
p2[2]};
1113 p3B = {
p0[0] +
p1[0] + pbach[0],
p0[1] +
p1[1] + pbach[1],
p0[2] +
p1[2] + pbach[2]};
1114 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];
1115 float pt2Candidate = p3B[0] * p3B[0] + p3B[1] * p3B[1], p2Candidate = pt2Candidate + p3B[2] * p3B[2];
1116 float ptCandidate = std::sqrt(pt2Candidate);
1117 if (m3bodyHyps[ipid].
check(sqP0, sqP1, sqPBach, p2Candidate, ptCandidate)) {
1118 if (pt2Candidate < mMinPt23Body) {
1121 if (p3B[2] * p3B[2] > pt2Candidate * mMaxTgl23Body) {
1127 for (
int iv = decay3bodyVlist.getMin(); iv <= decay3bodyVlist.getMax(); iv++) {
1128 const auto& pv = mPVertices[iv];
1130 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];
1131 float cosPA = prodXYZ3body / std::sqrt((dx * dx + dy * dy + dz * dz) * p2Candidate);
1132 if (cosPA < bestCosPA) {
1133 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
1136 decay3bodyVtxID = iv;
1139 if (decay3bodyVtxID == -1) {
1140 LOG(
debug) <<
"3-body decay not compatible with any vertex";
1145 pidHyp = m3bodyHyps[ipid].getPIDHyp();
1146 vtxCosPA = bestCosPA;
1154 const auto& decay3bodyPv = mPVertices[decay3bodyVtxID];
1155 Decay3Body candidate3B(vertexXYZ, p3B, fitter3body.calcPCACovMatrixFlat(cand3B), tr0, tr1, tr2, pidHyp);
1158 if (!trc.propagateToDCA(decay3bodyPv, fitter3body.getBz(), &dca, 5.) ||
1163 candidate3B.setCosPA(vtxCosPA);
1164 candidate3B.setDCA(fitter3body.getChi2AtPCACandidate());
1165 m3bodyTmp[ithread].push_back(candidate3B);
1167 m3bodyIdxTmp[ithread].emplace_back(decay3bodyVtxID, v0Idx.
getProngID(0), v0Idx.
getProngID(1), bach.gid);
1171 mStrTracker->
process3Body(m3bodyIdxTmp[ithread].
size() - 1, candidate3B, decay3bodyIdx, ithread);
1174 return m3bodyIdxTmp[ithread].size() - n3BodyIni;
1178template <
class TVI,
class TCI,
class T3I,
class TR>
1179void SVertexer::extractPVReferences(
const TVI& v0s, TR& vtx2V0Refs,
const TCI& cascades, TR& vtx2CascRefs,
const T3I& vtx3, TR& vtx2body3Refs)
1183 vtx2V0Refs.resize(mPVertices.size());
1184 vtx2CascRefs.clear();
1185 vtx2CascRefs.resize(mPVertices.size());
1186 vtx2body3Refs.clear();
1187 vtx2body3Refs.resize(mPVertices.size());
1188 int nv0 = v0s.size(), nCasc = cascades.size(), n3body = vtx3.size();
1191 int pvID = -1, nForPV = 0;
1192 for (
int iv = 0; iv < nv0; iv++) {
1193 if (pvID < v0s[iv].getVertexID()) {
1195 vtx2V0Refs[pvID].setEntries(nForPV);
1197 pvID = v0s[iv].getVertexID();
1198 vtx2V0Refs[pvID].setFirstEntry(iv);
1204 vtx2V0Refs[pvID].setEntries(nForPV);
1207 for (
int ip = vtx2V0Refs.size(); ip--;) {
1208 if (vtx2V0Refs[ip].getEntries()) {
1209 ent = vtx2V0Refs[ip].getFirstEntry();
1211 vtx2V0Refs[ip].setFirstEntry(ent);
1219 for (
int iv = 0; iv < nCasc; iv++) {
1220 if (pvID < cascades[iv].getVertexID()) {
1222 vtx2CascRefs[pvID].setEntries(nForPV);
1224 pvID = cascades[iv].getVertexID();
1225 vtx2CascRefs[pvID].setFirstEntry(iv);
1231 vtx2CascRefs[pvID].setEntries(nForPV);
1234 for (
int ip = vtx2CascRefs.size(); ip--;) {
1235 if (vtx2CascRefs[ip].getEntries()) {
1236 ent = vtx2CascRefs[ip].getFirstEntry();
1238 vtx2CascRefs[ip].setFirstEntry(ent);
1246 for (
int iv = 0; iv < n3body; iv++) {
1247 const auto& vertex3body = vtx3[iv];
1248 if (pvID < vertex3body.getVertexID()) {
1250 vtx2body3Refs[pvID].setEntries(nForPV);
1252 pvID = vertex3body.getVertexID();
1253 vtx2body3Refs[pvID].setFirstEntry(iv);
1259 vtx2body3Refs[pvID].setEntries(nForPV);
1262 for (
int ip = vtx2body3Refs.size(); ip--;) {
1263 if (vtx2body3Refs[ip].getEntries()) {
1264 ent = vtx2body3Refs[ip].getFirstEntry();
1266 vtx2body3Refs[ip].setFirstEntry(ent);
1276 mNThreads =
n > 0 ?
n : 1;
1289 if (trTPC.hasBothSidesClusters()) {
1292 const auto& vtx = mPVertices[vtxid];
1293 auto twe = vtx.getTimeStamp();
1294 int posneg = trTPC.getSign() < 0 ? 1 : 0;
1296 bool compatibleWithProton =
false;
1300 float dEdxTPC = trTPC.getdEdx().dEdxTotTPC;
1301 float dEdxExpected = mPIDresponse.getExpectedSignal(trTPC, protonId);
1302 float fracDevProton = std::abs((dEdxTPC - dEdxExpected) / dEdxExpected);
1303 if (fracDevProton < mSVParams->mFractiondEdxforCascBaryons) {
1304 compatibleWithProton =
true;
1308 auto& trLoc = mTracksPool[posneg].emplace_back(TrackCand{trTPC, gid, {vtxid, vtxid}, 0.,
true, -1, compatibleWithProton});
1309 auto err = correctTPCTrack(trLoc, trTPC, twe.getTimeStamp(), twe.getTimeStampError());
1311 mTracksPool[posneg].pop_back();
1319 bool dDPV = std::abs(trLoc.getX() * trLoc.getTgl() - trLoc.getZ() + vtx.getZ()) > mSVParams->
mTPCTrack2Beam;
1321 float sna{0}, csa{0};
1323 trLoc.getCircleParams(mBz, trkCircle, sna, csa);
1324 float cR = std::hypot(trkCircle.
xC, trkCircle.
yC);
1325 float drd2 = std::sqrt(cR * cR - trkCircle.
rC * trkCircle.
rC);
1328 if (dCls || dDPV || dRD2) {
1329 mTracksPool[posneg].pop_back();
1348 tTB = tTPC.getTime0();
1349 tTBErr = 0.5 * (tTPC.getDeltaTBwd() + tTPC.getDeltaTFwd());
1351 tTB = tmus * mMUS2TPCBin;
1352 tTBErr = tmusErr * mMUS2TPCBin;
1354 float dDrift = (tTB - tTPC.getTime0()) * mTPCBin2Z;
1355 float driftErr = tTBErr * mTPCBin2Z;
1356 if (driftErr < 0.) {
1360 trc.setZ(tTPC.getZ() + (tTPC.hasASideClustersOnly() ? dDrift : -dDrift));
1363 auto cl = &tTPC.getCluster(mTPCTrackClusIdx, tTPC.getNClusters() - 1, *mTPCClusterIdxStruct, sector,
row);
1364 float x = 0,
y = 0,
z = 0;
1365 mTPCCorrMaps->Transform(sector,
row, cl->getPad(), cl->getTime(),
x,
y,
z, tTB);
1369 trc.
minR = std::sqrt(
x *
x +
y *
y);
1370 LOGP(
debug,
"set MinR = {} for row {}, x:{}, y:{}, z:{}", trc.
minR,
row,
x,
y,
z);
1377 std::array<size_t, 3> calls{};
1378 for (
int i = 0;
i < mNThreads;
i++) {
1379 calls[0] += mFitterV0[
i].getCallID();
1380 calls[1] += mFitterCasc[
i].getCallID();
1381 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
static constexpr ID HyperHelium4
static constexpr ID Electron
static constexpr ID HyperTriton
static constexpr ID Lambda
static constexpr ID Helium3
static constexpr ID HyperHelium5
static constexpr ID Deuteron
static constexpr ID OmegaMinus
static constexpr ID Photon
static constexpr ID Proton
static constexpr ID Triton
static constexpr ID XiMinus
static constexpr ID Hyperhydrog4
static constexpr ID Alpha
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 createFullV0s
fill V0s prongs/kinematics
float maxTglV0
maximum tgLambda of V0
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"