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;
336 mTPCCorrMapsHelper = maph;
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, mTPCCorrMapsHelper,
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;
466 int nv = vtxRefs.size() - 1;
467 for (
int i = 0;
i < 2;
i++) {
468 mTracksPool[
i].clear();
469 mVtxFirstTrack[
i].clear();
470 mVtxFirstTrack[
i].resize(nv, -1);
472 for (
int iv = 0; iv < nv; iv++) {
473 const auto& vtref = vtxRefs[iv];
474 int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries();
475 for (; it < itLim; it++) {
476 auto tvid = trackIndex[it];
486 if (processTPCTrack(mTPCTracksArray[tvid], tvid, iv)) {
491 if (tvid.isAmbiguous()) {
492 auto tref = tmap.find(tvid);
493 if (tref != tmap.end()) {
494 mTracksPool[tref->second.second][tref->second.first].vBracket.setMax(iv);
498 if (rejmap.find(tvid) != rejmap.end()) {
505 bool heavyIonisingParticle =
false;
508 if (tpcGID.isIndexSet() && isTPCloaded) {
511 float dEdxTPC = tpcTrack.getdEdx().dEdxTotTPC;
514 heavyIonisingParticle =
true;
517 float dEdxExpected = mPIDresponse.getExpectedSignal(tpcTrack, protonId);
518 float fracDevProton = std::abs((dEdxTPC - dEdxExpected) / dEdxExpected);
519 if (fracDevProton < mSVParams->mFractiondEdxforCascBaryons) {
520 compatibleWithProton =
true;
526 bool shortOBITSOnlyTrack =
false;
531 nITSclu = itsTrack.getNumberOfClusters();
532 if (itsTrack.hasHitOnLayer(6) && itsTrack.hasHitOnLayer(5) && itsTrack.hasHitOnLayer(4) && itsTrack.hasHitOnLayer(3)) {
533 shortOBITSOnlyTrack =
true;
537 if (isITSTPCloaded) {
538 auto& itsABTracklet = recoData.
getITSABRef(itsGID);
539 nITSclu = itsABTracklet.getNClusters();
542 if (!acceptTrack(tvid, trc) && !heavyIonisingParticle) {
543 if (tvid.isAmbiguous()) {
548 if ((isTPCloaded && !hasTPC) && (isITSloaded && (nITSclu < mSVParams->mITSSAminNclu && (!shortOBITSOnlyTrack || mSVParams->
mRejectITSonlyOBtrack)))) {
552 int posneg = trc.getSign() < 0 ? 1 : 0;
553 float r = std::sqrt(trc.getX() * trc.getX() + trc.getY() * trc.getY());
554 mTracksPool[posneg].emplace_back(TrackCand{trc, tvid, {iv, iv},
r, hasTPC, nITSclu, compatibleWithProton});
556 correctTPCTrack(mTracksPool[posneg].back(), mTPCTracksArray[tvid], -1, -1);
558 if (tvid.isAmbiguous()) {
559 tmap[tvid] = {mTracksPool[posneg].size() - 1, posneg};
564 for (
int pn = 0; pn < 2; pn++) {
565 auto& vtxFirstT = mVtxFirstTrack[pn];
566 const auto& tracksPool = mTracksPool[pn];
567 for (
unsigned i = 0;
i < tracksPool.size();
i++) {
568 const auto& t = tracksPool[
i];
569 for (
int j{t.vBracket.getMin()};
j <= t.vBracket.getMax(); ++
j) {
570 if (vtxFirstT[
j] == -1) {
577 LOG(info) <<
"Collected " << mTracksPool[
POS].size() <<
" positive and " << mTracksPool[
NEG].size() <<
" negative seeds";
581bool SVertexer::checkV0(
const TrackCand& seedP,
const TrackCand& seedN,
int iP,
int iN,
int ithread)
583 auto& fitterV0 = mFitterV0[ithread];
588 if (std::abs(seedP.getTgl() - seedN.getTgl()) > mSVParams->
maxV0TglAbsDiff) {
595 seedP.getCircleParams(mBz, trkPosCircle, sna, csa);
597 seedN.getCircleParams(mBz, trkEleCircle, sna, csa);
599 float c2c = std::hypot(trkPosCircle.
xC - trkEleCircle.
xC,
600 trkPosCircle.
yC - trkEleCircle.
yC);
601 float r2r = trkPosCircle.
rC + trkEleCircle.
rC;
602 float dcr = c2c - r2r;
604 LOG(
debug) <<
"RejD2R " << c2c <<
" " << r2r <<
" " << dcr;
608 float r1_r = trkPosCircle.
rC / r2r;
609 float r2_r = trkEleCircle.
rC / r2r;
610 float dR = std::hypot(r2_r * trkPosCircle.
xC + r1_r * trkEleCircle.
xC, r2_r * trkPosCircle.
yC + r1_r * trkEleCircle.
yC);
620 fitterV0.setCollinear(
true);
624 int nCand = fitterV0.process(seedP, seedN);
627 fitterV0.setMaxDZIni(mSVParams->
maxDZIni);
628 fitterV0.setMaxDXYIni(mSVParams->
maxDXYIni);
629 fitterV0.setMaxChi2(mSVParams->
maxChi2);
630 fitterV0.setCollinear(
false);
637 const auto& v0XYZ = fitterV0.getPCACandidate();
640 float dxv0 = v0XYZ[0] - mMeanVertex.getX(), dyv0 = v0XYZ[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0;
641 if (r2v0 < mMinR2ToMeanVertex) {
642 LOG(
debug) <<
"RejMinR2ToMeanVertex";
645 float rv0 = std::sqrt(r2v0), drv0P = rv0 - seedP.minR, drv0N = rv0 - seedN.minR;
648 LOG(
debug) <<
"RejCausality " << drv0P <<
" " << drv0N;
652 if (!fitterV0.isPropagateTracksToVertexDone(cand) && !fitterV0.propagateTracksToVertex(cand)) {
656 const auto& trPProp = fitterV0.getTrack(0, cand);
657 const auto& trNProp = fitterV0.getTrack(1, cand);
658 std::array<float, 3> pP{}, pN{};
659 trPProp.getPxPyPzGlo(pP);
660 trNProp.getPxPyPzGlo(pN);
665 std::array<float, 3> pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]};
666 float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0;
667 if (pt2V0 < mMinPt2V0) {
671 if (pV0[2] * pV0[2] / pt2V0 > mMaxTgl2V0) {
672 LOG(
debug) <<
"RejTgL " << pV0[2] * pV0[2] / pt2V0;
675 float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0);
677 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];
680 std::array<bool, NHypV0> hypCheckStatus{};
683 if (mV0Hyps[ipid].
check(p2Pos, p2Neg, p2V0, ptV0)) {
684 goodHyp = hypCheckStatus[ipid] =
true;
688 bool goodLamForCascade =
false, goodALamForCascade =
false;
689 bool usesTPCOnly = (seedP.hasTPC && !seedP.hasITS()) || (seedN.hasTPC && !seedN.hasITS());
693 goodLamForCascade =
true;
696 goodALamForCascade =
true;
701 bool good3bodyV0Hyp =
false;
702 for (
int ipid = 2; ipid < 4; ipid++) {
703 float massForLambdaHyp = mV0Hyps[ipid].calcMass(p2Pos, p2Neg, p2V0);
704 if (massForLambdaHyp - mV0Hyps[ipid].getMassV0Hyp() < mV0Hyps[ipid].getMargin(ptV0)) {
705 good3bodyV0Hyp =
true;
711 bool checkFor3BodyDecays = mEnable3BodyDecays &&
715 bool rejectAfter3BodyCheck =
false;
716 bool checkForCascade = mEnableCascades &&
718 r2v0 < mMaxR2ToMeanVertexCascV0 &&
721 bool rejectIfNotCascade =
false;
725 if (!checkFor3BodyDecays && !checkForCascade) {
728 rejectAfter3BodyCheck =
true;
732 float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY;
733 float cosPAXY = prodXYv0 / std::sqrt(r2v0 * pt2V0);
735 if (checkForCascade) {
736 if (dca2 > mMaxDCAXY2ToMeanVertexV0Casc || cosPAXY < mSVParams->minCosPAXYMeanVertexCascV0) {
737 LOG(
debug) <<
"Rej for cascade DCAXY2: " << dca2 <<
" << cosPAXY: " << cosPAXY;
738 if (!checkFor3BodyDecays) {
741 rejectAfter3BodyCheck =
true;
745 if (checkFor3BodyDecays) {
746 if (dca2 > mMaxDCAXY2ToMeanVertex3bodyV0 || cosPAXY < mSVParams->minCosPAXYMeanVertex3bodyV0) {
747 LOG(
debug) <<
"Rej for 3 body decays DCAXY2: " << dca2 <<
" << cosPAXY: " << cosPAXY;
748 checkFor3BodyDecays =
false;
752 if (dca2 > mMaxDCAXY2ToMeanVertex || cosPAXY < mSVParams->minCosPAXYMeanVertex) {
753 if (checkForCascade) {
754 rejectIfNotCascade =
true;
755 }
else if (checkFor3BodyDecays) {
756 rejectAfter3BodyCheck =
true;
769 auto vlist = seedP.vBracket.getOverlap(seedN.vBracket);
770 bool candFound =
false;
772 bestCosPA = checkFor3BodyDecays ? std::min(mSVParams->
minCosPA3bodyV0, bestCosPA) : bestCosPA;
776 for (
int iv = vlist.getMin(); iv <= vlist.getMax(); iv++) {
777 const auto& pv = mPVertices[iv];
778 const auto v0XYZ = fitterV0.getPCACandidatePos(cand);
780 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];
781 float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0);
782 if (cosPA < bestCosPA) {
783 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
787 new (&v0new)
V0(v0XYZ, pV0, fitterV0.calcPCACovMatrixFlat(cand), trPProp, trNProp);
788 new (&v0Idxnew)
V0Index(-1, seedP.gid, seedN.gid);
789 v0new.setDCA(fitterV0.getChi2AtPCACandidate(cand));
792 v0new.setCosPA(cosPA);
799 if (bestCosPA < mSVParams->minCosPACascV0) {
800 rejectAfter3BodyCheck =
true;
802 if (bestCosPA < mSVParams->minCosPA && checkForCascade) {
803 rejectIfNotCascade =
true;
805 int nV0Ini = mV0sIdxTmp[ithread].size();
807 if (checkFor3BodyDecays) {
808 int n3bodyDecays = 0;
809 n3bodyDecays += check3bodyDecays(v0Idxnew, v0new, rv0, pV0, p2V0, iN,
NEG, vlist, ithread);
810 n3bodyDecays += check3bodyDecays(v0Idxnew, v0new, rv0, pV0, p2V0, iP,
POS, vlist, ithread);
812 if (rejectAfter3BodyCheck) {
817 int nCascIni = mCascadesIdxTmp[ithread].size(), nV0Used = 0;
818 if (checkForCascade) {
820 nV0Used += checkCascades(v0Idxnew, v0new, rv0, pV0, p2V0, iN,
NEG, vlist, ithread);
823 nV0Used += checkCascades(v0Idxnew, v0new, rv0, pV0, p2V0, iP,
POS, vlist, ithread);
828 for (
unsigned int ic = nCascIni; ic < mCascadesIdxTmp[ithread].size(); ic++) {
829 if (mCascadesIdxTmp[ithread][ic].getV0ID() == -1) {
830 mCascadesIdxTmp[ithread][ic].setV0ID(nV0Ini);
835 if (nV0Used || !rejectIfNotCascade) {
836 mV0sIdxTmp[ithread].push_back(v0Idxnew);
837 if (!rejectIfNotCascade) {
838 mV0sIdxTmp[ithread].back().setStandaloneV0();
841 mV0sIdxTmp[ithread].back().setPhotonOnly();
842 mV0sIdxTmp[ithread].back().setCollinear();
846 mV0sTmp[ithread].push_back(v0new);
851 for (
int iv = nV0Ini; iv < (
int)mV0sIdxTmp[ithread].
size(); iv++) {
852 mStrTracker->
processV0(iv, v0new, v0Idxnew, ithread);
856 return mV0sIdxTmp[ithread].size() - nV0Ini != 0;
860int 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)
863 auto& fitterCasc = mFitterCasc[ithread];
864 auto&
tracks = mTracksPool[posneg];
865 int nCascIni = mCascadesIdxTmp[ithread].size(), nv0use = 0;
868 std::unordered_map<int, int> pvMap;
871 int firstTr = mVtxFirstTrack[posneg][v0vlist.getMin()], nTr =
tracks.size();
875 for (
int it = firstTr; it < nTr; it++) {
876 if (it == avoidTrackID) {
887 if (bach.vBracket.getMin() > v0vlist.getMax()) {
891 auto cascVlist = v0vlist.getOverlap(bach.vBracket);
901 int nCandC = fitterCasc.process(
v0, bach);
906 const auto& cascXYZ = fitterCasc.getPCACandidatePos(candC);
909 float dxc = cascXYZ[0] - mMeanVertex.getX(), dyc = cascXYZ[1] - mMeanVertex.getY(), r2casc = dxc * dxc + dyc * dyc;
910 if (rv0 * rv0 - r2casc < mMinR2DiffV0Casc || r2casc < mMinR2ToMeanVertex) {
915 if (!fitterCasc.isPropagateTracksToVertexDone(candC) && !fitterCasc.propagateTracksToVertex(candC)) {
919 auto& trNeut = fitterCasc.getTrack(0, candC);
920 auto& trBach = fitterCasc.getTrack(1, candC);
923 std::array<float, 3> pNeut, pBach;
924 trNeut.getPxPyPzGlo(pNeut);
925 trBach.getPxPyPzGlo(pBach);
926 std::array<float, 3> pCasc = {pNeut[0] + pBach[0], pNeut[1] + pBach[1], pNeut[2] + pBach[2]};
928 float pt2Casc = pCasc[0] * pCasc[0] + pCasc[1] * pCasc[1], p2Casc = pt2Casc + pCasc[2] * pCasc[2];
929 if (pt2Casc < mMinPt2Casc) {
933 if (pCasc[2] * pCasc[2] / pt2Casc > mMaxTgl2Casc) {
934 LOG(
debug) <<
"Casc tgLambda too high";
942 for (
int iv = cascVlist.getMin(); iv <= cascVlist.getMax(); iv++) {
943 const auto& pv = mPVertices[iv];
945 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];
946 float cosPA = prodXYZcasc / std::sqrt((dx * dx + dy * dy + dz * dz) * p2Casc);
947 if (cosPA < bestCosPA) {
948 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
954 if (cascVtxID == -1) {
955 LOG(
debug) <<
"Casc not compatible with any vertex";
959 const auto& cascPv = mPVertices[cascVtxID];
960 float dxCasc = cascXYZ[0] - cascPv.getX(), dyCasc = cascXYZ[1] - cascPv.getY(), dzCasc = cascXYZ[2] - cascPv.getZ();
961 auto prodPPos = pV0[0] * dxCasc + pV0[1] * dyCasc + pV0[2] * dzCasc;
963 LOG(
debug) <<
"Casc not causally compatible";
967 float p2Bach = pBach[0] * pBach[0] + pBach[1] * pBach[1] + pBach[2] * pBach[2];
968 float ptCasc = std::sqrt(pt2Casc);
969 bool goodHyp =
false;
971 if (mCascHyps[ipid].
check(p2V0, p2Bach, p2Casc, ptCasc)) {
977 LOG(
debug) <<
"Casc not compatible with any hypothesis";
982 Cascade casc(cascXYZ, pCasc, fitterCasc.calcPCACovMatrixFlat(candC), trNeut, trBach);
985 if (!trc.propagateToDCA(cascPv, fitterCasc.getBz(), &dca, 5.) ||
987 LOG(
debug) <<
"Casc not compatible with PV";
988 LOG(
debug) <<
"DCA: " << dca.getY() <<
" " << dca.getZ();
993 LOGP(
debug,
"cascade successfully validated");
997 auto pvIdx = pvMap.find(cascVtxID);
998 if (pvIdx != pvMap.end()) {
999 cascIdx.setV0ID(pvIdx->second);
1001 const auto& pv = mPVertices[cascVtxID];
1002 cascIdx.setV0ID(mV0sIdxTmp[ithread].
size());
1003 pvMap[cascVtxID] = mV0sTmp[ithread].size();
1004 mV0sIdxTmp[ithread].emplace_back(cascVtxID, v0Idx.
getProngs());
1006 mV0sTmp[ithread].push_back(
v0);
1007 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];
1008 mV0sTmp[ithread].back().setCosPA(prodXYZ / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0));
1014 mCascadesIdxTmp[ithread].push_back(cascIdx);
1016 casc.setCosPA(bestCosPA);
1017 casc.setDCA(fitterCasc.getChi2AtPCACandidate(candC));
1018 mCascadesTmp[ithread].push_back(casc);
1029int 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)
1032 auto& fitter3body = mFitter3body[ithread];
1033 auto&
tracks = mTracksPool[posneg];
1034 int n3BodyIni = m3bodyIdxTmp[ithread].size();
1037 int firstTr = mVtxFirstTrack[posneg][v0vlist.getMin()], nTr =
tracks.size();
1046 for (
int it = firstTr; it < nTr; it++) {
1047 if (it == avoidTrackID) {
1054 if (bach.vBracket > v0vlist.getMax()) {
1058 auto decay3bodyVlist = v0vlist.getOverlap(bach.vBracket);
1068 if (bach.getPt() < 0.6) {
1072 int n3bodyVtx = fitter3body.process(
v0.getProng(0),
v0.getProng(1), bach);
1073 if (n3bodyVtx == 0) {
1077 const auto& vertexXYZ = fitter3body.getPCACandidatePos(cand3B);
1080 float dxc = vertexXYZ[0] - mMeanVertex.getX(), dyc = vertexXYZ[1] - mMeanVertex.getY(), dzc = vertexXYZ[2] - mMeanVertex.getZ(), r2vertex = dxc * dxc + dyc * dyc;
1081 if (std::abs(rv0 - std::sqrt(r2vertex)) > mSVParams->
maxRDiffV03body || r2vertex < mMinR2ToMeanVertex) {
1084 float drvtxBach = std::sqrt(r2vertex) - bach.minR;
1085 if (drvtxBach > mSVParams->
causalityRTolerance || drvtxBach < -mSVParams->maxV0ToProngsRDiff) {
1086 LOG(
debug) <<
"RejCausality " << drvtxBach;
1089 if (!fitter3body.isPropagateTracksToVertexDone() && !fitter3body.propagateTracksToVertex()) {
1093 auto& tr0 = fitter3body.getTrack(0, cand3B);
1094 auto& tr1 = fitter3body.getTrack(1, cand3B);
1095 auto& tr2 = fitter3body.getTrack(2, cand3B);
1096 std::array<float, 3>
p0,
p1,
p2;
1097 tr0.getPxPyPzGlo(p0);
1098 tr1.getPxPyPzGlo(
p1);
1099 tr2.getPxPyPzGlo(
p2);
1101 bool goodHyp =
false;
1103 auto decay3bodyVtxID = -1;
1106 std::array<float, 3> pbach = {0, 0, 0}, p3B = {0, 0, 0};
1107 for (
int ipid = 0; ipid <
NHyp3body; ipid++) {
1109 float bachChargeFactor = m3bodyHyps[ipid].getChargeBachProng() / tr2.getAbsCharge();
1110 pbach = {bachChargeFactor *
p2[0], bachChargeFactor *
p2[1], bachChargeFactor *
p2[2]};
1111 p3B = {
p0[0] +
p1[0] + pbach[0],
p0[1] +
p1[1] + pbach[1],
p0[2] +
p1[2] + pbach[2]};
1112 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];
1113 float pt2Candidate = p3B[0] * p3B[0] + p3B[1] * p3B[1], p2Candidate = pt2Candidate + p3B[2] * p3B[2];
1114 float ptCandidate = std::sqrt(pt2Candidate);
1115 if (m3bodyHyps[ipid].
check(sqP0, sqP1, sqPBach, p2Candidate, ptCandidate)) {
1116 if (pt2Candidate < mMinPt23Body) {
1119 if (p3B[2] * p3B[2] > pt2Candidate * mMaxTgl23Body) {
1125 for (
int iv = decay3bodyVlist.getMin(); iv <= decay3bodyVlist.getMax(); iv++) {
1126 const auto& pv = mPVertices[iv];
1128 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];
1129 float cosPA = prodXYZ3body / std::sqrt((dx * dx + dy * dy + dz * dz) * p2Candidate);
1130 if (cosPA < bestCosPA) {
1131 LOG(
debug) <<
"Rej. cosPA: " << cosPA;
1134 decay3bodyVtxID = iv;
1137 if (decay3bodyVtxID == -1) {
1138 LOG(
debug) <<
"3-body decay not compatible with any vertex";
1143 pidHyp = m3bodyHyps[ipid].getPIDHyp();
1144 vtxCosPA = bestCosPA;
1152 const auto& decay3bodyPv = mPVertices[decay3bodyVtxID];
1153 Decay3Body candidate3B(vertexXYZ, p3B, fitter3body.calcPCACovMatrixFlat(cand3B), tr0, tr1, tr2, pidHyp);
1156 if (!trc.propagateToDCA(decay3bodyPv, fitter3body.getBz(), &dca, 5.) ||
1161 candidate3B.setCosPA(vtxCosPA);
1162 candidate3B.setDCA(fitter3body.getChi2AtPCACandidate());
1163 m3bodyTmp[ithread].push_back(candidate3B);
1165 m3bodyIdxTmp[ithread].emplace_back(decay3bodyVtxID, v0Idx.
getProngID(0), v0Idx.
getProngID(1), bach.gid);
1169 mStrTracker->
process3Body(m3bodyIdxTmp[ithread].
size() - 1, candidate3B, decay3bodyIdx, ithread);
1172 return m3bodyIdxTmp[ithread].size() - n3BodyIni;
1176template <
class TVI,
class TCI,
class T3I,
class TR>
1177void SVertexer::extractPVReferences(
const TVI& v0s, TR& vtx2V0Refs,
const TCI& cascades, TR& vtx2CascRefs,
const T3I& vtx3, TR& vtx2body3Refs)
1181 vtx2V0Refs.resize(mPVertices.size());
1182 vtx2CascRefs.clear();
1183 vtx2CascRefs.resize(mPVertices.size());
1184 vtx2body3Refs.clear();
1185 vtx2body3Refs.resize(mPVertices.size());
1186 int nv0 = v0s.size(), nCasc = cascades.size(), n3body = vtx3.size();
1189 int pvID = -1, nForPV = 0;
1190 for (
int iv = 0; iv < nv0; iv++) {
1191 if (pvID < v0s[iv].getVertexID()) {
1193 vtx2V0Refs[pvID].setEntries(nForPV);
1195 pvID = v0s[iv].getVertexID();
1196 vtx2V0Refs[pvID].setFirstEntry(iv);
1202 vtx2V0Refs[pvID].setEntries(nForPV);
1205 for (
int ip = vtx2V0Refs.size(); ip--;) {
1206 if (vtx2V0Refs[ip].getEntries()) {
1207 ent = vtx2V0Refs[ip].getFirstEntry();
1209 vtx2V0Refs[ip].setFirstEntry(ent);
1217 for (
int iv = 0; iv < nCasc; iv++) {
1218 if (pvID < cascades[iv].getVertexID()) {
1220 vtx2CascRefs[pvID].setEntries(nForPV);
1222 pvID = cascades[iv].getVertexID();
1223 vtx2CascRefs[pvID].setFirstEntry(iv);
1229 vtx2CascRefs[pvID].setEntries(nForPV);
1232 for (
int ip = vtx2CascRefs.size(); ip--;) {
1233 if (vtx2CascRefs[ip].getEntries()) {
1234 ent = vtx2CascRefs[ip].getFirstEntry();
1236 vtx2CascRefs[ip].setFirstEntry(ent);
1244 for (
int iv = 0; iv < n3body; iv++) {
1245 const auto& vertex3body = vtx3[iv];
1246 if (pvID < vertex3body.getVertexID()) {
1248 vtx2body3Refs[pvID].setEntries(nForPV);
1250 pvID = vertex3body.getVertexID();
1251 vtx2body3Refs[pvID].setFirstEntry(iv);
1257 vtx2body3Refs[pvID].setEntries(nForPV);
1260 for (
int ip = vtx2body3Refs.size(); ip--;) {
1261 if (vtx2body3Refs[ip].getEntries()) {
1262 ent = vtx2body3Refs[ip].getFirstEntry();
1264 vtx2body3Refs[ip].setFirstEntry(ent);
1274 mNThreads =
n > 0 ?
n : 1;
1287 if (trTPC.hasBothSidesClusters()) {
1290 const auto& vtx = mPVertices[vtxid];
1291 auto twe = vtx.getTimeStamp();
1292 int posneg = trTPC.getSign() < 0 ? 1 : 0;
1294 bool compatibleWithProton =
false;
1298 float dEdxTPC = trTPC.getdEdx().dEdxTotTPC;
1299 float dEdxExpected = mPIDresponse.getExpectedSignal(trTPC, protonId);
1300 float fracDevProton = std::abs((dEdxTPC - dEdxExpected) / dEdxExpected);
1301 if (fracDevProton < mSVParams->mFractiondEdxforCascBaryons) {
1302 compatibleWithProton =
true;
1306 auto& trLoc = mTracksPool[posneg].emplace_back(TrackCand{trTPC, gid, {vtxid, vtxid}, 0.,
true, -1, compatibleWithProton});
1307 auto err = correctTPCTrack(trLoc, trTPC, twe.getTimeStamp(), twe.getTimeStampError());
1309 mTracksPool[posneg].pop_back();
1317 bool dDPV = std::abs(trLoc.getX() * trLoc.getTgl() - trLoc.getZ() + vtx.getZ()) > mSVParams->
mTPCTrack2Beam;
1319 float sna{0}, csa{0};
1321 trLoc.getCircleParams(mBz, trkCircle, sna, csa);
1322 float cR = std::hypot(trkCircle.
xC, trkCircle.
yC);
1323 float drd2 = std::sqrt(cR * cR - trkCircle.
rC * trkCircle.
rC);
1326 if (dCls || dDPV || dRD2) {
1327 mTracksPool[posneg].pop_back();
1346 tTB = tTPC.getTime0();
1347 tTBErr = 0.5 * (tTPC.getDeltaTBwd() + tTPC.getDeltaTFwd());
1349 tTB = tmus * mMUS2TPCBin;
1350 tTBErr = tmusErr * mMUS2TPCBin;
1352 float dDrift = (tTB - tTPC.getTime0()) * mTPCBin2Z;
1353 float driftErr = tTBErr * mTPCBin2Z;
1354 if (driftErr < 0.) {
1358 trc.setZ(tTPC.getZ() + (tTPC.hasASideClustersOnly() ? dDrift : -dDrift));
1361 auto cl = &tTPC.getCluster(mTPCTrackClusIdx, tTPC.getNClusters() - 1, *mTPCClusterIdxStruct, sector,
row);
1362 float x = 0,
y = 0,
z = 0;
1363 mTPCCorrMapsHelper->Transform(sector,
row, cl->getPad(), cl->getTime(),
x,
y,
z, tTB);
1367 trc.
minR = std::sqrt(
x *
x +
y *
y);
1368 LOGP(
debug,
"set MinR = {} for row {}, x:{}, y:{}, z:{}", trc.
minR,
row,
x,
y,
z);
1375 std::array<size_t, 3> calls{};
1376 for (
int i = 0;
i < mNThreads;
i++) {
1377 calls[0] += mFitterV0[
i].getCallID();
1378 calls[1] += mFitterCasc[
i].getCallID();
1379 calls[2] += mFitter3body[
i].getCallID();
Helper class to access correction maps.
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
void setTPCCorrMaps(o2::gpu::CorrectionMapsHelper *maph)
std::array< size_t, 3 > getNFitterCalls() const
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 PrimaryVertex 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::@453 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"