18#include "Math/SMatrix.h"
19#include "Math/SVector.h"
21#include <unordered_map>
27constexpr float PVertexer::kAlmost0F;
28constexpr double PVertexer::kAlmost0D;
29constexpr float PVertexer::kHugeF;
34 mMeanVertex.
setSigma({0.5f, 0.5f, 6.0f});
38int PVertexer::runVertexing(
const gsl::span<o2d::GlobalTrackID> gids,
const gsl::span<InteractionCandidate> intCand,
39 std::vector<PVertex>& vertices, std::vector<o2d::VtxTrackIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs,
40 gsl::span<const o2::MCCompLabel> lblTracks, std::vector<o2::MCEventLabel>& lblVtx)
43 doDBGPoolDump(lblTracks);
49 mMaxTrialPerCluster = 0;
50 mLongestClusterTimeMS = 0;
51 mLongestClusterMult = 0;
58 mPoolDumpProduced =
false;
60 std::vector<PVertex> verticesLoc;
61 std::vector<uint32_t> trackIDs;
62 std::vector<V2TRef> v2tRefsLoc;
63 std::vector<float> validationTimes;
64 std::vector<o2::MCEventLabel> lblVtxLoc;
65 mTimeVertexing.Start();
67 for (
auto tc : mTimeZClusters) {
68 size_t nnold = verticesLoc.size();
70 inp.
idRange = gsl::span<int>(tc.trackIDs);
74 doDBScanDump(inp, lblTracks);
76 findVertices(inp, verticesLoc, trackIDs, v2tRefsLoc);
78 mTimeVertexing.Stop();
80 std::vector<int> vtTimeSortID(verticesLoc.size());
81 std::iota(vtTimeSortID.begin(), vtTimeSortID.end(), 0);
82 std::sort(vtTimeSortID.begin(), vtTimeSortID.end(), [&verticesLoc](
int i,
int j) {
83 return verticesLoc[i].getTimeStamp().getTimeStamp() < verticesLoc[j].getTimeStamp().getTimeStamp();
87 if (lblTracks.size()) {
88 createMCLabels(lblTracks, trackIDs, v2tRefsLoc, lblVtxLoc);
91 mNIniFound = verticesLoc.size();
98 applITSOnlyFractionCut(verticesLoc, vtTimeSortID, v2tRefsLoc, trackIDs);
103 reduceDebris(verticesLoc, vtTimeSortID, lblVtxLoc);
108 mTimeReAttach.Start();
109 reAttach(verticesLoc, vtTimeSortID, trackIDs, v2tRefsLoc);
110 mTimeReAttach.Stop();
113 if (lblTracks.size()) {
114 createMCLabels(lblTracks, trackIDs, v2tRefsLoc, lblVtxLoc);
117#ifdef _PV_DEBUG_TREE_
118 doVtxDump(verticesLoc, trackIDs, v2tRefsLoc, lblTracks);
123 vertexTrackIDs.clear();
124 vertices.reserve(verticesLoc.size());
125 v2tRefs.reserve(v2tRefsLoc.size());
126 vertexTrackIDs.reserve(trackIDs.size());
128 int trCopied = 0,
count = 0, vtimeID = 0;
129 for (
auto&
i : vtTimeSortID) {
133 auto& vtx = verticesLoc[
i];
140 if (mValidateWithIR) {
146 applyMADSelection(verticesLoc, vtTimeSortID, v2tRefsLoc, trackIDs);
150 for (
auto i : vtTimeSortID) {
154 auto& vtx = verticesLoc[
i];
155 vertices.push_back(vtx);
156 if (lblVtxLoc.size()) {
157 lblVtx.push_back(lblVtxLoc[
i]);
159 int it = v2tRefsLoc[
i].getFirstEntry(), itEnd = it + v2tRefsLoc[
i].getEntries(), dest0 = vertexTrackIDs.size();
160 for (; it < itEnd; it++) {
161 const auto& trc = mTracksPool[trackIDs[it]];
162 auto& gid = vertexTrackIDs.emplace_back(trc.gid);
163 gid.setPVContributor();
165 v2tRefs.emplace_back(dest0, v2tRefsLoc[
i].getEntries());
166 LOG(
debug) <<
"#" <<
count++ <<
" " << vertices.back() <<
" | " << v2tRefs.back().getEntries() <<
" indices from " << v2tRefs.back().getFirstEntry();
169 return vertices.size();
173int PVertexer::findVertices(
const VertexingInput& input, std::vector<PVertex>& vertices, std::vector<uint32_t>& trackIDs, std::vector<V2TRef>& v2tRefs)
179 int nfound = 0, ntr = 0;
180 auto seedHistoTZ = buildHistoTZ(input);
182#ifdef _PV_DEBUG_TREE_
183 static int dbsCount = -1;
187 hh->SetDirectory(
nullptr);
188 mDebugDumpFile->cd();
191 long tStart = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count(), tCurr = tStart;
192 long mult = input.
idRange.size();
194 while (nfound < mPVParams->maxVerticesPerCluster && nTrials < mPVParams->maxTrialsPerCluster) {
195 int peakBin = seedHistoTZ.findPeakBin();
196 if (!seedHistoTZ.isValidBin(peakBin)) {
199 int peakBinT = seedHistoTZ.getXBin(peakBin), peakBinZ = seedHistoTZ.getYBin(peakBin);
200 float tv = seedHistoTZ.getBinXCenter(peakBinT);
201 float zv = seedHistoTZ.getBinYCenter(peakBinZ);
202 LOG(
debug) <<
"Seeding with T=" << tv <<
" Z=" << zv <<
" bin " << peakBin <<
" on trial " << nTrials <<
" for vertex " << nfound <<
" mult=" << mult;
206 vtx.setTimeStamp({tv, 0.f});
208 finalizeVertex(input, vtx, vertices, v2tRefs, trackIDs, &seedHistoTZ);
212 seedHistoTZ.setBinContent(peakBin, -1);
216#ifdef _PV_DEBUG_TREE_
218 hh1->SetDirectory(
nullptr);
219 mDebugDumpFile->cd();
222 tCurr = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
223 auto clTime = tCurr - tStart;
225 LOGP(warn,
"Time per TZ-cluster ({}ms) of {} tracks exceeded limit after {} trials, abandon", clTime, mult, nTrials);
226 if (!mPoolDumpProduced) {
232 mTotTrials += nTrials;
233 if (
size_t(nTrials) > mMaxTrialPerCluster) {
234 mMaxTrialPerCluster = nTrials;
236 if (tCurr - tStart > mLongestClusterTimeMS) {
237 mLongestClusterTimeMS = tCurr - tStart;
238 mLongestClusterMult = mult;
250 int ntr = input.
idRange.size();
256 LOG(
debug) <<
"Start time guess: " << vtxSeed.getTimeStamp();
265 <<
" ntr=" << ntr <<
" Zv=" << vtxSeed.getZ() <<
" Tv=" << vtxSeed.getTimeStamp().getTimeStamp();
266 result = fitIteration(input, vtxSeed);
269 result = evalIterations(vtxSeed, vtx);
298 for (
int i : input.idRange) {
299 if (mTracksPool[
i].canUse()) {
300 accountTrack(mTracksPool[
i], vtxSeed);
312 applyConstraint(vtxSeed);
314 if (!solveVertex(vtxSeed)) {
324 bool useTime = vtxSeed.getTimeStamp().getTimeStampError() >= 0.f;
327 if (wghT < kAlmost0F) {
334 auto timeErrorFromTB = [&trc]() {
341 vtxSeed.
wghChi2 += wghT * chi2T;
350 tmpSC = trc.
sinAlp + tmpCP, tmpCS = -trc.
cosAlp + tmpSP,
352 tmpYXP = trc.
y - trc.
tgP * trc.
x, tmpZXL = trc.
z - trc.
tgL * trc.
x,
353 tmpCLzz = tmpCL * szzI, tmpSLzz = tmpSL * szzI, tmpSCyz = tmpSC * syzI,
354 tmpCSyz = tmpCS * syzI, tmpCSyy = tmpCS * syyI, tmpSCyy = tmpSC * syyI,
355 tmpSLyz = tmpSL * syzI, tmpCLyz = tmpCL * syzI;
358 vtxSeed.
cxx += tmpCL * (tmpCLzz + tmpSCyz + tmpSCyz) + tmpSC * tmpSCyy;
359 vtxSeed.
cxy += tmpCL * (tmpSLzz + tmpCSyz) + tmpSL * tmpSCyz + tmpSC * tmpCSyy;
360 vtxSeed.
cxz += -trc.
sinAlp * syzI - tmpCLzz - tmpCP * syzI;
361 vtxSeed.
cx0 += -(tmpCLyz + tmpSCyy) * tmpYXP - (tmpCLzz + tmpSCyz) * tmpZXL;
363 vtxSeed.
cyy += tmpSL * (tmpSLzz + tmpCSyz + tmpCSyz) + tmpCS * tmpCSyy;
364 vtxSeed.
cyz += -(tmpCSyz + tmpSLzz);
365 vtxSeed.
cy0 += -tmpYXP * (tmpCSyy + tmpSLyz) - tmpZXL * (tmpCSyz + tmpSLzz);
368 vtxSeed.
cz0 += tmpZXL * szzI + tmpYXP * syzI;
371 float trErr2I = wghT / (trc.
timeEst.getTimeStampError() * trc.
timeEst.getTimeStampError());
372 if (timeErrorFromTB()) {
382 vtxSeed.addContributor();
386bool PVertexer::solveVertex(
VertexSeed& vtxSeed)
const
389 mat(0, 0) = vtxSeed.
cxx;
390 mat(0, 1) = vtxSeed.
cxy;
391 mat(0, 2) = vtxSeed.
cxz;
392 mat(1, 1) = vtxSeed.
cyy;
393 mat(1, 2) = vtxSeed.
cyz;
394 mat(2, 2) = vtxSeed.
czz;
395 if (!mat.InvertFast()) {
396 LOG(error) <<
"Failed to invert matrix" << mat;
400 auto sol = mat *
rhs;
401 vtxSeed.setXYZ(sol(0), sol(1), sol(2));
402 vtxSeed.setCov(mat(0, 0), mat(1, 0), mat(1, 1), mat(2, 0), mat(2, 1), mat(2, 2));
411 auto err2 = 1. / e2i;
412 vtxSeed.setTimeStamp({
float(t * err2),
float(std::sqrt(err2))});
419 <<
" n-contributors=" << vtxSeed.getNContributors();
420 vtxSeed.
setScale(newScale < mPVParams->minScale2 ? mPVParams->
minScale2 : newScale, mTukey2I);
438 if (fair::Logger::Logging(fair::Severity::debug)) {
439 auto dchi = (vtx.getChi2() - vtxSeed.getChi2()) / vtxSeed.getChi2();
440 auto dx = vtxSeed.getX() - vtx.getX(), dy = vtxSeed.getY() - vtx.getY(), dz = vtxSeed.getZ() - vtx.getZ();
441 auto dst = std::sqrt(dx * dx + dy * dy + dz * dz);
443 LOG(
debug) <<
"dChi:" << vtx.getChi2() <<
"->" << vtxSeed.getChi2() <<
" :-> " << dchi;
444 LOG(
debug) <<
"dx: " << dx <<
" dy: " << dy <<
" dz: " << dz <<
" -> " <<
dst;
447 vtx =
reinterpret_cast<const PVertex&
>(vtxSeed);
450 auto chi2Mean = vtxSeed.getChi2() / vtxSeed.getNContributors();
483void PVertexer::reAttach(std::vector<PVertex>& vertices, std::vector<int>& timeSort, std::vector<uint32_t>& trackIDs, std::vector<V2TRef>& v2tRefs)
485 float tRange = 0.5 * std::max(mITSROFrameLengthMUS, mDBScanDeltaT) + mPVParams->
timeMarginReattach;
486 std::vector<std::pair<int, TimeEst>> vtvec;
487 int nvtOrig = vertices.size();
488 vtvec.reserve(nvtOrig);
489 mTimeZClusters.resize(nvtOrig);
490 for (
int ivt = 0; ivt < nvtOrig; ivt++) {
491 mTimeZClusters[ivt].trackIDs.clear();
492 mTimeZClusters[ivt].trackIDs.reserve(
int(vertices[ivt].getNContributors() * 1.2));
494 for (
auto ivt : timeSort) {
499 int ntr = mTracksPool.size(), nvt = vtvec.size();
501 for (
int itr = 0; itr < ntr; itr++) {
502 auto& trc = mTracksPool[itr];
505 for (
int ivt = vtStart; ivt < nvt; ivt++) {
506 auto dt = vtvec[ivt].second.getTimeStamp() - trc.
timeEst.getTimeStamp();
518 trc.
vtxID = vtvec[ivt].first;
522 mTimeZClusters[trc.
vtxID].trackIDs.push_back(itr);
530 std::vector<PVertex> verticesUpd;
531 for (
int ivt = 0; ivt < nvtOrig; ivt++) {
532 auto& clusZT = mTimeZClusters[ivt];
533 auto& vtx = vertices[ivt];
538 inp.
idRange = gsl::span<int>(clusZT.trackIDs);
540 inp.
timeEst = vtx.getTimeStamp();
542 vtx.setNContributors(0);
545 finalizeVertex(inp, vtx, verticesUpd, v2tRefs, trackIDs);
548 vertices.swap(verticesUpd);
549 timeSort.resize(vertices.size());
550 std::iota(timeSort.begin(), timeSort.end(), 0);
551 std::sort(timeSort.begin(), timeSort.end(), [&vertices](
int i,
int j) {
552 return vertices[i].getTimeStamp().getTimeStamp() < vertices[j].getTimeStamp().getTimeStamp();
557void PVertexer::applyMADSelection(std::vector<PVertex>& vertices, std::vector<int>& timeSort,
const std::vector<V2TRef>& v2tRefs,
const std::vector<uint32_t>& trackIDs)
559 int nv = timeSort.size(), nkill = 0;
560 std::vector<float> dvec;
561 for (
int ivt = 0; ivt < nv; ivt++) {
562 int iv = timeSort[ivt];
566 auto& pv = vertices[iv];
567 const auto trefs = v2tRefs[iv];
568 int idMin = trefs.getFirstEntry(), idMax = idMin + trefs.getEntries();
570 dvec.reserve(pv.getNContributors());
573 float tVtx = pv.getTimeStamp().getTimeStamp();
574 for (
int i = idMin;
i < idMax;
i++) {
575 const auto& trc = mTracksPool[trackIDs[
i]];
580 dvec.push_back(trc.
timeEst.getTimeStamp() - tVtx);
585 if (tmad > mPVParams->
maxTMAD || tmad < mPVParams->minTMAD) {
588 LOGP(
debug,
"Killing vertex {} with TMAD {}, {} of {} killed", iv, tmad, ++nkill, nv);
594 float zVtx = pv.getZ();
595 for (
int i = idMin;
i < idMax;
i++) {
596 const auto& trc = mTracksPool[trackIDs[
i]];
597 dvec.push_back(trc.
z - zVtx);
600 if (zmad > mPVParams->
maxZMAD || zmad < mPVParams->minZMAD) {
603 LOGP(
debug,
"Killing vertex {} with ZMAD {}, {} of {} killed", iv, zmad, ++nkill, nv);
612void PVertexer::applITSOnlyFractionCut(std::vector<PVertex>& vertices, std::vector<int>& timeSort,
const std::vector<V2TRef>& v2tRefs,
const std::vector<uint32_t>& trackIDs)
614 int nv = timeSort.size();
615 for (
int ivt = 0; ivt < nv; ivt++) {
616 int iv = timeSort[ivt];
620 const auto& pv = vertices[iv];
621 float tVtx = pv.getTimeStamp().getTimeStamp();
622 const auto trefs = v2tRefs[iv];
623 int idMin = trefs.getFirstEntry(), idMax = idMin + trefs.getEntries();
625 for (
int i = idMin;
i < idMax;
i++) {
626 const auto& trc = mTracksPool[trackIDs[
i]];
631 float frac = nITS /
float(trefs.getEntries());
640void PVertexer::applInteractionValidation(std::vector<PVertex>& vertices, std::vector<int>& timeSort,
const gsl::span<InteractionCandidate> intCand,
int minContrib)
643 int nv = timeSort.size(), nkill = 0;
646 int intCandMin = 0, nInt = intCand.size();
647 for (
int ivt = 0; ivt < nv; ivt++) {
648 int iv = timeSort[ivt];
652 auto& pv = vertices[iv];
653 while (intCandMin < nInt && intCand[intCandMin].
time < (pv.getTimeStamp().getTimeStamp() + mPVParams->
timeBiasMS - maxErr)) {
656 int i = intCandMin, nCompatible = 0, best = -1;
659 float tv = pv.getTimeStamp().getTimeStamp() + mPVParams->
timeBiasMS;
661 if (intCand[
i].
time > (tv + tvE)) {
664 if (intCand[
i].
time < (tv - tvE)) {
669 auto dfa = std::abs(tv - intCand[intCandMin].
time);
678 if (nCompatible == 1) {
679 pv.setIR(intCand[best]);
681 }
else if (pv.getNContributors() >= minContrib) {
689void PVertexer::reduceDebris(std::vector<PVertex>& vertices, std::vector<int>& timeSort,
const std::vector<o2::MCEventLabel>& lblVtx)
693 int nv = vertices.size();
694 std::vector<int> multSort(nv);
695 std::iota(multSort.begin(), multSort.end(), 0);
696 std::sort(multSort.begin(), multSort.end(), [&timeSort, vertices](
int i,
int j) {
697 return timeSort[i] < 0 ? false : (timeSort[j] < 0 ? true : vertices[timeSort[i]].getNContributors() > vertices[timeSort[j]].getNContributors());
702 auto checkPair = [&vertices, &timeSort, &lblVtx,
this](
int i,
int j) {
703 auto &vtI = vertices[timeSort[
i]], &vtJ = vertices[timeSort[
j]];
704 auto tDiff = std::abs(vtI.getTimeStamp().getTimeStamp() - vtJ.getTimeStamp().getTimeStamp());
706 if (tDiff > this->mMaxTDiffDebrisFiducial) {
709 if (vtI.getNContributors() < vtJ.getNContributors()) {
713 float zDiff = std::abs(vtI.getZ() - vtJ.getZ());
714 float chi2z = 0.f, chi2t = 0.f, chi2zE = 0.f, chi2tE = 0.f;
715 if (zDiff < this->mMaxZDiffDebrisFiducial &&
float(vtJ.getNContributors() <
float(vtI.getNContributors()) *
this->mMaxMultRatDebrisFiducial)) {
716 if (this->mMaxTDiffDebrisExtra <= 0 ||
717 (zDiff < this->mPVParams->
maxZDiffDebris && tDiff < this->mMaxTDiffDebris &&
float(vtJ.getNContributors()) <
float(vtI.getNContributors()) *
this->mPVParams->maxMultRatDebris)) {
718 chi2z = zDiff * zDiff / (vtI.getSigmaZ2() + vtJ.getSigmaZ2() + this->mPVParams->
addZSigma2Debris);
719 chi2t = tDiff * tDiff / (vtI.getTimeStamp().getTimeStampError2() + vtJ.getTimeStamp().getTimeStampError2() + this->mPVParams->
addTimeSigma2Debris);
722 if (!rej && this->mMaxTDiffDebrisExtra > 0 &&
723 (zDiff < this->mPVParams->
maxZDiffDebrisExtra && tDiff < this->mMaxTDiffDebrisExtra &&
float(vtJ.getNContributors()) <
float(vtI.getNContributors()) *
this->mPVParams->maxMultRatDebrisExtra)) {
724 chi2zE = zDiff * zDiff / (vtI.getSigmaZ2() + vtJ.getSigmaZ2() + this->mPVParams->
addZSigma2DebrisExtra);
725 chi2tE = tDiff * tDiff / (vtI.getTimeStamp().getTimeStampError2() + vtJ.getTimeStamp().getTimeStampError2() + this->mPVParams->
addTimeSigma2DebrisExtra);
728#ifdef _PV_DEBUG_TREE_
730 this->mDebugDumpPVComp.emplace_back(vtI, vtJ, chi2z, chi2t, chi2zE, chi2tE, rej);
731 if (!lblVtx.empty()) {
732 this->mDebugDumpPVCompLbl0.push_back(lblVtx[timeSort[
i]]);
733 this->mDebugDumpPVCompLbl1.push_back(lblVtx[timeSort[
j]]);
740 vtJ.setNContributors(0);
745 for (
int im = 0; im < nv; im++) {
746 int it = multSort[im];
747 if (timeSort[it] < 0) {
753 if (timeSort[--itL] >= 0) {
754 if (checkPair(it, itL)) {
761 if (timeSort[itH] >= 0) {
762 if (checkPair(it, itH)) {
768#ifdef _PV_DEBUG_TREE_
769 mDebugVtxCompTree->Fill();
770 mDebugDumpPVComp.clear();
771 mDebugDumpPVCompLbl0.clear();
772 mDebugDumpPVCompLbl1.clear();
777void PVertexer::initMeanVertexConstraint()
781 float ex2 = mMeanVertex.getSigmaX2() + extraErr2, ey2 = mMeanVertex.getSigmaY2() + extraErr2, exy = mMeanVertex.getSigmaXY();
782 double det =
ex2 * ey2 - exy * exy;
783 if (det <= kAlmost0D ||
ex2 < kAlmost0D || ey2 < kAlmost0D) {
784 throw std::runtime_error(fmt::format(
"Singular matrix for vertex constraint: sxx={:+.4e} syy={:+.4e} sxy={:+.4e}",
787 mXYConstraintInvErr[0] = ey2 / det;
788 mXYConstraintInvErr[1] = -exy / det;
789 mXYConstraintInvErr[2] =
ex2 / det;
796 return sqrtf(1. / mTukey2I);
803 for (
int i : input.idRange) {
804 if (mTracksPool[
i].canUse()) {
805 const auto& timeT = mTracksPool[
i].timeEst;
806 auto trErr2I = 1. / (timeT.getTimeStampError() * timeT.getTimeStampError());
807 test.add(timeT.getTimeStamp(), trErr2I);
811 const auto [t, te2] =
test.getMeanRMS2<
float>();
819 initMeanVertexConstraint();
822 setBz(prop->getNominalBz());
828 mMaxTDiffDebrisFiducial = mMaxTDiffDebrisExtra > 0 ? std::max(mMaxTDiffDebrisExtra, mMaxTDiffDebris) : mMaxTDiffDebris;
832#ifdef _PV_DEBUG_TREE_
833 mDebugDumpFile = std::make_unique<TFile>(
"pvtxDebug.root",
"recreate");
835 mDebugPoolTree = std::make_unique<TTree>(
"pvtxTrackPool",
"PVertexer tracks pool debug output");
836 mDebugPoolTree->Branch(
"trc", &mDebugDumpDBSTrc);
837 mDebugPoolTree->Branch(
"gid", &mDebugDumpDBSGID);
838 mDebugPoolTree->Branch(
"mc", &mDebugDumpDBSTrcMC);
840 mDebugDBScanTree = std::make_unique<TTree>(
"pvtxDBScan",
"PVertexer DBScan debug output");
841 mDebugDBScanTree->Branch(
"trc", &mDebugDumpDBSTrc);
842 mDebugDBScanTree->Branch(
"gid", &mDebugDumpDBSGID);
843 mDebugDBScanTree->Branch(
"mc", &mDebugDumpDBSTrcMC);
845 mDebugVtxTree = std::make_unique<TTree>(
"pvtx",
"final PVertexer debug output");
846 mDebugVtxTree->Branch(
"vtx", &mDebugDumpVtx);
847 mDebugVtxTree->Branch(
"trc", &mDebugDumpVtxTrc);
848 mDebugVtxTree->Branch(
"gid", &mDebugDumpVtxGID);
849 mDebugVtxTree->Branch(
"mc", &mDebugDumpVtxTrcMC);
851 mDebugVtxCompTree = std::make_unique<TTree>(
"pvtxComp",
"PVertexer neighbouring vertices debud output");
852 mDebugVtxCompTree->Branch(
"vtxComp", &mDebugDumpPVComp);
853 mDebugVtxCompTree->Branch(
"vtxCompLbl0", &mDebugDumpPVCompLbl0);
854 mDebugVtxCompTree->Branch(
"vtxCompLbl1", &mDebugDumpPVCompLbl1);
861#ifdef _PV_DEBUG_TREE_
862 if (mDebugDumpFile) {
863 mDebugDumpFile->cd();
864 mDebugPoolTree->Write();
865 mDebugDBScanTree->Write();
866 mDebugVtxCompTree->Write();
867 mDebugVtxTree->Write();
869 mDebugPoolTree.reset();
870 mDebugDBScanTree.reset();
871 mDebugVtxCompTree.reset();
872 mDebugVtxTree.reset();
874 mDebugDumpFile->Close();
875 mDebugDumpFile.reset();
882 std::vector<PVertex>& vertices, std::vector<V2TRef>& v2tRefs, std::vector<uint32_t>& trackIDs,
885 int lastID = vertices.size();
886 vertices.emplace_back(vtx);
887 auto&
ref = v2tRefs.emplace_back(trackIDs.size(), 0);
888 for (
int i : input.idRange) {
889 auto& trc = mTracksPool[
i];
891 trackIDs.push_back(
i);
898 ref.setEntries(trackIDs.size() -
ref.getFirstEntry());
902void PVertexer::createMCLabels(gsl::span<const o2::MCCompLabel> lblTracks,
903 const std::vector<uint32_t>& trackIDs,
const std::vector<V2TRef>& v2tRefs,
904 std::vector<o2::MCEventLabel>& lblVtx)
907 if (!lblTracks.size()) {
908 LOG(error) <<
"Track labels are not provided";
911 std::unordered_map<o2::MCEventLabel, int> labelOccurence;
913 auto bestLbl = [](std::unordered_map<o2::MCEventLabel, int> mp,
int norm) ->
o2::MCEventLabel {
916 for (
auto [lbl, cnt] : mp) {
917 if (cnt > bestCount && lbl.isSet()) {
922 if (bestCount && norm) {
928 for (
const auto& v2t : v2tRefs) {
929 int tref = v2t.getFirstEntry(),
last = tref + v2t.getEntries();
930 labelOccurence.clear();
932 for (; tref <
last; tref++) {
933 const auto& lbl = lblTracks[mTracksPool[trackIDs[tref]].entry];
938 labelOccurence[{lbl.getEventID(), lbl.getSourceID(), 0.}]++;
941 if (labelOccurence.size()) {
942 winner = bestLbl(labelOccurence, v2t.getEntries());
944 lblVtx.push_back(winner);
956 LOG(error) <<
"Empty bunch filling is provided, all vertices will be rejected";
957 mClosestBunchAbove[0] = mClosestBunchBelow[0] = -1;
965 mClosestBunchAbove[
i] = bcAbove;
972 mClosestBunchBelow[
i] = bcBelow;
983 const auto& vtxT = vtx.getTimeStamp();
986 float t = vtxT.getTimeStamp() + mPVParams->
timeBiasMS;
997 int bc = mClosestBunchAbove[irMin.bc];
998 LOG(
debug) <<
"irMin.bc = " << irMin.bc <<
" bcAbove = " <<
bc;
1003 bc = mClosestBunchBelow[irMax.
bc];
1004 LOG(
debug) <<
"irMax.bc = " << irMax.
bc <<
" bcBelow = " <<
bc;
1005 if (
bc > irMax.
bc) {
1006 if (irMax.
orbit == 0) {
1015 if (irMin > irMax) {
1018 return irMax >= irMin;
1022int PVertexer::dbscan_RangeQuery(
int id, std::vector<int>& cand, std::vector<int>& status)
1027 const auto& tI = mTracksPool[
id];
1028 if (tI.sig2ZI < mDBSMaxZ2InvCorePoint) {
1031 int ntr = mTracksPool.size();
1033 auto procPnt = [
this, &tI, &status, &cand, &nFound,
id](
int idN) {
1034 const auto& tL = this->mTracksPool[idN];
1035 if (std::abs(tI.timeEst.getTimeStamp() - tL.timeEst.getTimeStamp()) > this->mDBScanDeltaT) {
1038 auto statN = status[idN], stat = status[
id];
1039 if (statN >= 0 && (stat < 0 || (stat >= 0 && statN != stat))) {
1042 auto dist2 = tL.getDist2(tI);
1045 if (statN < 0 && statN > DBS_INCHECK) {
1046 cand.push_back(idN);
1047 status[idN] += DBS_INCHECK;
1053 while (--idL >= 0) {
1054 if (procPnt(idL) < 0) {
1059 while (++idU < ntr) {
1060 if (procPnt(idU) < 0) {
1068void PVertexer::dbscan_clusterize()
1070 mTimeZClusters.clear();
1071 int ntr = mTracksPool.size();
1072 std::vector<int> status(ntr, DBS_UNDEF);
1075 std::vector<int> nbVec;
1076 for (
int it = 0; it < ntr; it++) {
1077 if (status[it] != DBS_UNDEF) {
1081 auto nnb0 = dbscan_RangeQuery(it, nbVec, status);
1083 if (nnb0 < minNeighbours) {
1084 status[it] = DBS_NOISE;
1087 if (nnb0 > minNeighbours) {
1088 minNeighbours = std::max(minNeighbours,
int(nnb0 * mPVParams->
dbscanAdaptCoef));
1090 status[it] = ++clID;
1091 auto& clusVec = mTimeZClusters.emplace_back().trackIDs;
1092 clusVec.push_back(it);
1094 for (
int j = 0;
j < nnb0;
j++) {
1096 auto statjt = status[jt];
1098 LOG(error) <<
"assigned track " << jt <<
" with status " << statjt <<
" head is " << it <<
" clID= " << clID;
1102 clusVec.push_back(jt);
1103 if (statjt == DBS_NOISE + DBS_INCHECK) {
1106 int ncurr = nbVec.size();
1107 if (clusVec.size() > minNeighbours) {
1108 minNeighbours = std::max(minNeighbours,
int(clusVec.size() * mPVParams->
dbscanAdaptCoef));
1110 auto nnb1 = dbscan_RangeQuery(jt, nbVec, status);
1111 if (nnb1 < minNeighbours) {
1112 for (
unsigned k = ncurr; k < nbVec.size(); k++) {
1113 if (status[nbVec[k]] < DBS_INCHECK) {
1114 status[nbVec[k]] -= DBS_INCHECK;
1117 nbVec.resize(ncurr);
1119 nnb0 = nbVec.size();
1124 for (
auto& clus : mTimeZClusters) {
1126 clus.trackIDs.clear();
1130 for (
const auto tid : clus.trackIDs) {
1131 tMean += mTracksPool[tid].timeEst.getTimeStamp();
1133 clus.timeEst.setTimeStamp(tMean / clus.trackIDs.size());
1135 mNTZClustersIni = mTimeZClusters.size();
1139std::pair<int, int> PVertexer::getBestIR(
const PVertex& vtx,
const gsl::span<InteractionCandidate> intCand,
int& currEntry)
const
1142 int best = -1,
n = intCand.size();
1143 while (currEntry <
n && intCand[currEntry] < vtx.
getIRMin()) {
1146 int i = currEntry, nCompatible = 0;
1147 float bestDf = 1e12;
1148 auto tVtxNS = (vtx.getTimeStamp().getTimeStamp() + mPVParams->
timeBiasMS) * 1e3;
1154 auto dfa = std::abs(intCand[
i].differenceInBCNS(mStartIR) - tVtxNS);
1155 if (dfa <= bestDf) {
1161 return {best, nCompatible};
1170 float hZMin = 1e9, hZMax = -1e8, hTMin = 1e9, hTMax = -1e9;
1171 for (
int i : input.idRange) {
1172 const auto& trc = mTracksPool[
i];
1174 if (trc.
z > hZMax) {
1177 if (trc.
z < hZMin) {
1180 if (trc.
timeEst.getTimeStamp() > hTMax) {
1181 hTMax = trc.
timeEst.getTimeStamp();
1183 if (trc.
timeEst.getTimeStamp() < hTMin) {
1184 hTMin = trc.
timeEst.getTimeStamp();
1189 float dz = hZMax - hZMin, dt = hTMax - hTMin;
1191 if (nbz * nbt > 0x7fff) {
1192 float factor =
float(nbz * nbt / 0x7fff);
1194 nbt = (0x7fff - 1) / nbz;
1196 nbz = (0x7fff - 1) / nbt;
1200 SeedHistoTZ seedHistoTZ(nbt, hTMin - dth, hTMax + dth, nbz, hZMin - dzh, hZMax + dzh);
1202 for (
int i : input.idRange) {
1203 auto& trc = mTracksPool[
i];
1209 return std::move(seedHistoTZ);
1216 auto z = trc.getZAt(0., mBz);
1218 z = mMeanVertex.getZ();
1224 return dca.getY() * dca.getY() / (dca.getSigmaY2() + vtxErr2) < mPVParams->
pullIniCut;
1234void PVertexer::doDBScanDump(
const VertexingInput& input, gsl::span<const o2::MCCompLabel> lblTracks)
1237#ifdef _PV_DEBUG_TREE_
1238 for (
int i : input.idRange) {
1239 const auto& trc = mTracksPool[
i];
1241 mDebugDumpDBSTrc.emplace_back(trc.z, trc.sig2ZI, trc.timeEst.getTimeStamp(), trc.timeEst.getTimeStampError(), trc.wghHisto);
1242 mDebugDumpDBSGID.push_back(trc.gid);
1243 if (lblTracks.size()) {
1244 mDebugDumpDBSTrcMC.push_back(lblTracks[trc.entry]);
1248 mDebugDBScanTree->Fill();
1249 mDebugDumpDBSTrc.clear();
1250 mDebugDumpDBSGID.clear();
1251 mDebugDumpDBSTrcMC.clear();
1256void PVertexer::doDBGPoolDump(gsl::span<const o2::MCCompLabel> lblTracks)
1259#ifdef _PV_DEBUG_TREE_
1260 for (
const auto& trc : mTracksPool) {
1261 mDebugDumpDBSTrc.emplace_back(trc.z, trc.sig2ZI, trc.timeEst.getTimeStamp(), trc.timeEst.getTimeStampError(), trc.wghHisto);
1262 mDebugDumpDBSGID.push_back(trc.gid);
1263 if (lblTracks.size()) {
1264 mDebugDumpDBSTrcMC.push_back(lblTracks[trc.entry]);
1267 mDebugPoolTree->Fill();
1268 mDebugDumpDBSTrc.clear();
1269 mDebugDumpDBSGID.clear();
1270 mDebugDumpDBSTrcMC.clear();
1275void PVertexer::doVtxDump(std::vector<PVertex>& vertices, std::vector<uint32_t> trackIDsLoc, std::vector<V2TRef>& v2tRefsLoc,
1276 gsl::span<const o2::MCCompLabel> lblTracks)
1279#ifdef _PV_DEBUG_TREE_
1280 int nv = vertices.size();
1281 for (
int iv = 0; iv < nv; iv++) {
1282 mDebugDumpVtx = vertices[iv];
1283 if (mDebugDumpVtx.getNContributors() == 0) {
1286 int start = v2tRefsLoc[iv].getFirstEntry(), stop =
start + v2tRefsLoc[iv].getEntries();
1287 for (
int it =
start; it < stop; it++) {
1288 const auto& trc = mTracksPool[trackIDsLoc[it]];
1289 mDebugDumpVtxTrc.emplace_back(trc.z, trc.sig2ZI, trc.timeEst.getTimeStamp(), trc.timeEst.getTimeStampError(), trc.wgh);
1290 mDebugDumpVtxGID.push_back(trc.gid);
1291 if (lblTracks.size()) {
1292 mDebugDumpVtxTrcMC.push_back(lblTracks[trc.entry]);
1295 mDebugVtxTree->Fill();
1296 mDebugDumpVtxTrc.clear();
1297 mDebugDumpVtxGID.clear();
1298 mDebugDumpVtxTrcMC.clear();
1312 if (vtxSeed != mVtxRefitOrig) {
1313 throw std::runtime_error(
"refitVertex must be preceded by successful prepareVertexRefit");
1317 inp.
idRange = gsl::span<int>(mRefitTrackIDs);
1318 if (useTrack.size()) {
1319 for (uint32_t
i = 0;
i < mTracksPool.size();
i++) {
1324 vtxs.VertexBase::operator=(vtxSeed);
1327 vtxs.setTimeStamp({0.f, -1.});
1331 vtxRes.setChi2(-1.);
1341 if (mTracksPool[
i].canUse()) {
1342 LOGP(info,
"#{}: {} z:{:.3f}/{:.3f} t:{:.3f}/{:.3f} w:{:.3f} gid:{}", cnt,
i, mTracksPool[
i].
z, std::sqrt(1. / mTracksPool[
i].sig2ZI),
1343 mTracksPool[
i].
timeEst.getTimeStamp(), mTracksPool[
i].timeEst.getTimeStampError(), mTracksPool[
i].wgh, mTracksPool[
i].gid.asString());
1350void PVertexer::dumpPool()
1352 static int dumpID = 0;
1353 if (mPoolDumpDirectory !=
"/dev/null") {
1354 TFile dumpFile(fmt::format(
"{}{}pvtracksPool{}_{}_{}.root", mPoolDumpDirectory, (mPoolDumpDirectory.empty() || mPoolDumpDirectory.back() ==
'/') ?
"" :
"/",
1355 dumpID,
std::chrono::time_point_cast<
std::chrono::milliseconds>(
std::chrono::
system_clock::now()).time_since_epoch().
count(),
1356 o2::
utils::Str::getRandomString(5))
1359 dumpFile.WriteObjectAny(&mTracksPool,
"std::vector<o2::vertexing::TrackVF>",
"pool");
1360 LOGP(warn,
"Produced tracks pool dump {}", dumpFile.GetName());
1362 mPoolDumpProduced =
true;
1368 std::vector<InteractionCandidate> intCand;
1369 std::vector<o2::MCCompLabel> lblTracks;
1370 std::vector<o2::MCEventLabel> lblVtx;
1372 std::vector<GTrackID> gids;
1373 for (
auto tr : pool) {
1376 mTracksPool.push_back(tr);
1377 gids.push_back(tr.gid);
1379 return runVertexing(gids, intCand, vertices, vertexTrackIDs, v2tRefs, lblTracks, lblVtx);
1390 if (mTrackSrc[is]) {
1391 mSrcVec.push_back(is);
1392 if ((GTrackID::getSourceDetectorsMask(is) & ITSTPC) == ITSTPC) {
1397 mITSOnly = nGloSrc == 0;
int getLastFilledBC(int dir=-1) const
bool testBC(int bcID, int dir=-1) const
int getFirstFilledBC(int dir=-1) const
void setCorrWeight(float corrW)
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
static const PVertexerParams & Instance()
Static class with identifiers, bitmasks and names for ALICE detectors.
static mask_t getMask(const std::string_view detList)
detector masks from any non-alpha-num delimiter-separated list (empty if NONE is supplied)
void setTrackSources(GTrackID::mask_t s)
void printInpuTracksStatus(const VertexingInput &input) const
bool findVertex(const VertexingInput &input, PVertex &vtx)
PVertex refitVertex(const std::vector< bool > useTrack, const o2d::VertexBase &vtxSeed)
int processFromExternalPool(const std::vector< TrackVF > &pool, std::vector< PVertex > &vertices, std::vector< o2d::VtxTrackIndex > &vertexTrackIDs, std::vector< V2TRef > &v2tRefs)
void setBunchFilling(const o2::BunchFilling &bf)
bool setCompatibleIR(PVertex &vtx)
GLdouble GLdouble GLdouble z
constexpr int LHCMaxBunches
D const SVectorGPU< T, D > & rhs
T MAD2Sigma(int np, T *y)
uint64_t getTimeStamp(o2::framework::ProcessingContext &pc)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
std::string to_string(gsl::span< T, Size > span)
FIXME: do not use data model tables.
Common utility functions.
uint16_t bc
bunch crossing ID of interaction
static std::string concat_string(Ts const &... ts)
float iniScale2
initial scale to assign
bool applyDebrisReduction
apply algorithm reducing split vertices
float dbscanMaxSigZCorPoint
max sigZ of the track which can be core points in the DBScan
float dbscanMaxDist2
distance^2 cut (eps^2).
float addTimeSigma2DebrisExtra
increment time error^2 by this amount when calculating vertex-to-vertex chi2
int maxNScaleIncreased
max number of scaling-non-decreasing iterations
float pullIniCut
cut on pull (n^2 sigma) on dca to mean vertex
float histoBinZSize
size of the seedTZ histo bin Z
float maxTDiffDebris
when reducing debris, don't consider vertices separated by time > this value in \mus if >0,...
int minNContributorsForIRcutIni
min multiplicity to reject before cleanup if no matching interaction found (if >= 0)
float dbscanDeltaT
abs. time difference cut, should be ~ 0.5 ITS ROF duration if ITS SA tracks used, if < 0 then the val...
float maxChi2TZDebris
don't consider vertices with mutual chi2 exceeding this (for pp should be ~10)
int minTracksPerVtx
min N tracks per vertex
float addZSigma2Debris
increment z error^2 by this amount when calculating vertex-to-vertex chi2
float maxChi2Mean
max mean chi2 of vertex to accept
float maxTError
use min of vertex time error or this for nsigma evaluation
float minScale2
min scaling factor^2
bool doBCValidation
apply validation by interacting BC compatible with the vertex time span
bool applyReattachment
refit vertices reattaching tracks to closest found vertex
float nSigmaTimeCut
eliminate vertex if there is no FT0 or BC signal within this cut
float maxTMAD
max accepted tMAD, not tMAD cleanup if negative
long maxTimeMSPerCluster
max allowed time per TZCluster processing, ms
bool useTimeInChi2
use track-vertex time difference in chi2 calculation
float dcaTolerance
consider tracks within this abs DCA to mean vertex
float maxTDiffDebrisExtra
when reducing debris, don't consider vertices separated by time > this value in \mus if >0,...
float timeMarginVertexTime
additive marginal error to \mus vertex time bracket
float histoBinTSize
size of the seedTZ histo bin T
float dbscanAdaptCoef
adapt dbscan minPts for each cluster as minPts=max(minPts, currentSize*dbscanAdaptCoef).
int minNContributorsForIRcut
do not apply IR cut to vertices below IR tagging efficiency threshold
bool useMeanVertexConstraint
use MeanVertex as extra measured point
float maxMultRatDebris
don't consider vertices with multiplicity ratio above this
float maxITSOnlyFraction
max ITS-only tracks fraction to accept, recommended value for PbPb = 0.85
float meanVertexExtraErrConstraint
extra error to meanvertex sigma used when applying constrant
float tukey
Tukey parameter.
float maxZDiffDebris
don't consider vertices separated by Z > this value in cm
float maxChi2TZDebrisExtra
don't consider vertices with mutual chi2 exceeding this (for pp should be ~10)
float minTError
don't use error smaller than that (~BC/2/minNContributorsForFT0cut)
float timeBiasMS
relative bias in ms to add to TPCITS-based time stamp
float slowConvergenceFactor
consider convergence as slow if ratio new/old scale2 exceeds it
float maxMultRatDebrisExtra
don't consider vertices with multiplicity ratio above this
float maxZMAD
max accepted zMAD, not zMAD cleanup if negative
float timeMarginReattach
safety marging for track time vs vertex time difference during reattachment
float minITSOnlyFraction
min ITS-only tracks fraction to accept
float addTimeSigma2Debris
increment time error^2 by this amount when calculating vertex-to-vertex chi2
int maxIterations
max iterations per vertex fit
int maxNScaleSlowConvergence
max number of weak scaling decrease iterations
float acceptableScale2
if below this factor, try to refit with minScale2
float addZSigma2DebrisExtra
increment z error^2 by this amount when calculating vertex-to-vertex chi2
float maxZDiffDebrisExtra
don't consider vertices separated by Z > this value in cm
bool isITSTPCAdjusted() const
float tgP
tangent(phi) in tracking frame
float sigYZI
YZ component of inverse cov.matrix.
float evalChi2ToVertex(const PVertex &vtx, bool useTime)
float wgh
track weight wrt current vertex seed
float sig2YI
YY component of inverse cov.matrix.
float cosAlp
cos of alpha frame
float sig2ZI
ZZ component of inverse cov.matrix.
float sinAlp
sin of alpha frame
float maxScaleSigma2Tested
void resetForNewIteration()
void setScale(float scale2, float tukey2I)
int nScaleSlowConvergence
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"