255 static int TFCount = 0;
256 int nv = vtxRefs.size();
259 std::vector<o2::dataformats::PrimaryVertexExt> pveVec(nv);
260 std::vector<float> tpcOccAftV, tpcOccBefV;
261 pveVec.back() = vtxDummy;
265 std::vector<o2::dataformats::TrackInfoExt> trcExtVec;
266 std::vector<o2::trackstudy::TrackPairInfo> trcPairsVec;
269 int groupOcc = std::ceil(maxDriftTB / mNOccBinsDrift / mNTPCOccBinLength);
279 uint8_t clSect = 0, clRow = 0, lowestR = -1;
281 for (
int ic = 0; ic < trc.getNClusterReferences(); ic++) {
282 trc.getClusterReference(clRefs, ic, clSect, clRow, clIdx);
283 if (clRow < lowestR) {
287 unsigned int absoluteIndex = tpcClusAcc.clusterOffset[clSect][clRow] + clIdx;
289 trExt.nClTPCShared++;
292 trExt.rowMinTPC = lowestR;
293 const auto& clus = tpcClusAcc.clusters[clSect][clRow][clIdx];
294 trExt.padFromEdge = uint8_t(clus.getPad());
295 int npads = o2::gpu::GPUTPCGeometry::NPads(lowestR);
296 if (trExt.padFromEdge > npads / 2) {
297 trExt.padFromEdge = npads - 1 - trExt.padFromEdge;
299 this->mTPCCorrMapsLoader.Transform(clSect, clRow, clus.getPad(), clus.getTime(), trExt.innerTPCPos0[0], trExt.innerTPCPos0[1], trExt.innerTPCPos0[2], trc.getTime0());
300 if (timestampTB > -1e8) {
301 this->mTPCCorrMapsLoader.Transform(clSect, clRow, clus.getPad(), clus.getTime(), trExt.innerTPCPos[0], trExt.innerTPCPos[1], trExt.innerTPCPos[2], timestampTB);
303 trExt.innerTPCPos = trExt.innerTPCPos0;
305 trc.getClusterReference(clRefs, 0, clSect, clRow, clIdx);
306 trExt.rowMaxTPC = clRow;
312 uint8_t nsh = 0, nshRows = 0, lastSharedRow = -1;
314 uint8_t clSect0 = 0, clRow0 = 0, clSect1 = 0, clRow1 = 0;
315 uint32_t clIdx0 = 0, clIdx1 = 0;
317 for (
int ic0 = 0; ic0 < trc0.getNClusterReferences(); ic0++) {
318 trc0.getClusterReference(clRefs, ic0, clSect0, clRow0, clIdx0);
319 for (
int ic1 = ic1Start; ic1 < trc1.getNClusterReferences(); ic1++) {
320 trc1.getClusterReference(clRefs, ic1, clSect1, clRow1, clIdx1);
321 if (clRow1 > clRow0) {
325 if (clRow1 == clRow0) {
326 if (clSect0 == clSect1 && clIdx0 == clIdx1) {
328 if (lastSharedRow != clRow0) {
329 lastSharedRow = clRow0;
339 return std::make_pair(nsh, nshRows);
345 dst.ts.setTimeStamp(
src.ttime);
346 dst.ts.setTimeStampError(
src.ttimeE);
349 dst.pattITS =
src.pattITS;
350 if (
src.q2ptITS == 0. &&
dst.nClITS > 0) {
351 dst.pattITS |= 0x1 << 7;
353 dst.lowestPadRow =
src.rowMinTPC;
359 auto msk =
src.gid.getSourceDetectorsMask();
363 if (lblITS.isFake()) {
384 tpcOccAftV.resize(mNOccBinsDrift);
385 tpcOccBefV.resize(mNOccBinsDrift);
387 for (
int iv = 0; iv < nv; iv++) {
388 LOGP(
debug,
"processing PV {} of {}", iv, nv);
389 const auto& vtref = vtxRefs[iv];
391 auto& pve = pveVec[iv];
394 float bestTimeDiff = 1000, bestTime = -999;
398 const auto& ft0 = FITInfo[trackIndex[ift0]];
400 auto fitTime = ft0.getInteractionRecord().differenceInBCMUS(recoData.
startIR);
401 if (std::abs(fitTime - pve.getTimeStamp().getTimeStamp()) < bestTimeDiff) {
402 bestTimeDiff = fitTime - pve.getTimeStamp().getTimeStamp();
403 bestFTID = trackIndex[ift0];
408 LOGP(warn,
"FT0 is not requested, cannot set complete vertex info");
411 pve.FT0A = FITInfo[bestFTID].getTrigger().getAmplA();
412 pve.FT0C = FITInfo[bestFTID].getTrigger().getAmplC();
413 pve.FT0Time = double(FITInfo[bestFTID].getInteractionRecord().differenceInBCMUS(recoData.
startIR)) + FITInfo[bestFTID].getCollisionTimeMean() * 1e-6;
419 float q2ptITS, q2ptTPC, q2ptITSTPC, q2ptITSTPCTRD;
423 int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is);
424 for (
int i = idMin;
i < idMax;
i++) {
425 auto vid = trackIndex[
i];
426 bool pvCont = vid.isPVContributor();
428 pveVec[iv].nSrc[is]++;
439 nclTPC = tpcTr->getNClusters();
440 if (nclTPC < mMinTPCClusters) {
444 bool ambig = vid.isAmbiguous();
446 if (abs(trc.getEta()) > mMaxEta) {
449 if (iv < nv - 1 && is == GTrackID::TPC && tpcTr && !tpcTr->hasBothSidesClusters()) {
450 float corz = vdrift * (tpcTr->getTime0() * mTPCTBinMUS - pvvec[iv].getTimeStamp().getTimeStamp());
451 if (tpcTr->hasASideClustersOnly()) {
454 trc.setZ(trc.getZ() + corz);
456 float xmin = trc.getX();
458 if (!prop->propagateToDCA(iv == nv - 1 ? vtxDummy : pvvec[iv], trc, prop->getNominalBz(), 2., o2::base::PropagatorF::MatCorrType::USEMatCorrLUT, &dca)) {
461 bool hasITS = GTrackID::getSourceDetectorsMask(is)[
GTrackID::ITS];
462 if (std::abs(dca.getY()) > (hasITS ? getDCAYCut(trc.getPt()) : mTPCDCAYCut) ||
463 std::abs(dca.getZ()) > (hasITS ? getDCAZCut(trc.getPt()) : mTPCDCAZCut)) {
466 if (trc.getPt() < mMinPt) {
470 pveVec[iv].nSrcA[is]++;
472 pveVec[iv].nSrcAU[is]++;
475 if (!hasITS && mStoreWithITSOnly) {
479 auto& trcExt = trcExtVec.emplace_back();
480 recoData.
getTrackTime(vid, trcExt.ttime, trcExt.ttimeE);
482 trcExt.hashIU = trc.hash();
486 trcExt.dcaTPC.set(-999.f, -999.f);
490 if (tpcTr->hasASideClusters()) {
493 if (tpcTr->hasCSideClusters()) {
501 if (iv < nv - 1 && is == GTrackID::TPC && tpcTr && !tpcTr->hasBothSidesClusters()) {
502 float corz = vdrift * (tpcTr->getTime0() * mTPCTBinMUS - pvvec[iv].getTimeStamp().getTimeStamp());
503 if (tpcTr->hasASideClustersOnly()) {
506 tmpTPC.setZ(tmpTPC.getZ() + corz);
508 if (!prop->propagateToDCA(iv == nv - 1 ? vtxDummy : pvvec[iv], tmpTPC, prop->getNominalBz(), 2., o2::base::PropagatorF::MatCorrType::USEMatCorrLUT, &trcExt.dcaTPC)) {
509 trcExt.dcaTPC.set(-999.f, -999.f);
512 fillTPCClInfo(*tpcTr, trcExt, tsuse);
513 trcExt.chi2TPC = tpcTr->getChi2();
518 trcExt.q2ptITS = itsTr.getQ2Pt();
519 trcExt.nClITS = itsTr.getNClusters();
520 for (
int il = 0; il < 7; il++) {
521 if (itsTr.hasHitOnLayer(il)) {
522 trcExt.pattITS |= 0x1 << il;
527 trcExt.nClITS = itsTrf.getNClusters();
528 for (
int il = 0; il < 7; il++) {
529 if (itsTrf.hasHitOnLayer(il)) {
530 trcExt.pattITS |= 0x1 << il;
536 trcExt.nClTPC = nclTPC;
540 trcExt.q2ptITSTPC = trTPCITS.getQ2Pt();
541 trcExt.chi2ITSTPC = trTPCITS.getChi2Match();
552 float tpcOccBef = 0., tpcOccAft = 0.;
554 int tb = pveVec[iv].getTimeStamp().getTimeStamp() * mTPCTBinMUSInv * mNTPCOccBinLengthInv;
555 tpcOccBef = tb < 0 ? mTBinClOccBef[0] : (tb >= mTBinClOccBef.size() ? mTBinClOccBef.back() : mTBinClOccBef[tb]);
556 tpcOccAft = tb < 0 ? mTBinClOccAft[0] : (tb >= mTBinClOccAft.size() ? mTBinClOccAft.back() : mTBinClOccAft[tb]);
557 int tbc = pveVec[iv].getTimeStamp().getTimeStamp() * mTPCTBinMUSInv * mNTPCOccBinLengthInv - groupOcc / 2.;
558 for (
int iob = 0; iob < mNOccBinsDrift; iob++) {
560 for (
int ig = 0; ig < groupOcc; ig++) {
561 int ocb = tbc + ig + groupOcc * iob;
562 if (ocb < 0 || ocb >= (
int)mMltHistTB.size()) {
566 sm += mMltHistTB[ocb];
568 tpcOccAftV[iob] = sm;
571 for (
int ig = 0; ig < groupOcc; ig++) {
572 int ocb = tbc + ig - groupOcc * iob;
573 if (ocb < 0 || ocb >= (
int)mMltHistTB.size()) {
577 sm += mMltHistTB[ocb];
579 tpcOccBefV[iob] = sm;
583 <<
"orbit=" << recoData.
startIR.
orbit <<
"tfID=" << TFCount
584 <<
"tpcOccBef=" << tpcOccBef <<
"tpcOccAft=" << tpcOccAft
585 <<
"tpcOccBefV=" << tpcOccBefV <<
"tpcOccAftV=" << tpcOccAftV
586 <<
"pve=" << pveVec[iv] <<
"trc=" << trcExtVec <<
"\n";
589 for (
int it0 = 0; it0 < (
int)trcExtVec.size(); it0++) {
590 const auto& tr0 = trcExtVec[it0];
591 if (tr0.nClTPC < 1) {
594 for (
int it1 = it0 + 1; it1 < (
int)trcExtVec.size(); it1++) {
595 const auto& tr1 = trcExtVec[it1];
596 if (tr1.nClTPC < 1) {
600 if (std::abs(tr0.track.getTgl() - tr1.track.getTgl()) > 0.25) {
603 auto dphi = tr0.track.getPhi() - tr1.track.getPhi();
609 if (std::abs(dphi) > 0.25) {
612 auto& pr = trcPairsVec.emplace_back();
613 assignRecTrack(tr0, pr.tr0);
614 assignRecTrack(tr1, pr.tr1);
616 pr.nshTPC = shinfo.first;
617 pr.nshTPCRow = shinfo.second;
620 (*mDBGOut) <<
"pairs" <<
"pr=" << trcPairsVec <<
"\n";
624 int nvtot = mMaxNeighbours < 0 ? -1 : (
int)pveVec.size();
626 auto insSlot = [maxSlots = mMaxNeighbours](std::vector<float>& vc,
float v,
int slot, std::vector<int>& vid,
int id) {
627 for (
int i = maxSlots - 1;
i > slot;
i--) {
628 std::swap(vc[
i], vc[
i - 1]);
629 std::swap(vid[
i], vid[
i - 1]);
635 for (
int cnt = 0; cnt < nvtot; cnt++) {
636 const auto& pve = pveVec[cnt];
637 float tv = pve.getTimeStamp().getTimeStamp();
638 std::vector<o2::dataformats::PrimaryVertexExt> pveT(mMaxNeighbours);
639 std::vector<o2::dataformats::PrimaryVertexExt> pveZ(mMaxNeighbours);
640 std::vector<int> idT(mMaxNeighbours), idZ(mMaxNeighbours);
641 std::vector<float> dT(mMaxNeighbours), dZ(mMaxNeighbours);
642 for (
int i = 0;
i < mMaxNeighbours;
i++) {
643 idT[
i] = idZ[
i] = -1;
644 dT[
i] = mMaxVTTimeDiff;
647 int cntM = cnt - 1, cntP = cnt + 1;
648 for (; cntM >= 0; cntM--) {
649 const auto& vt = pveVec[cntM];
650 auto dtime = std::abs(tv - vt.getTimeStamp().getTimeStamp());
651 if (dtime > mMaxVTTimeDiff) {
654 for (
int i = 0;
i < mMaxNeighbours;
i++) {
656 insSlot(dT, dtime,
i, idT, cntM);
660 auto dz = std::abs(pve.getZ() - vt.getZ());
661 for (
int i = 0;
i < mMaxNeighbours;
i++) {
663 insSlot(dZ, dz,
i, idZ, cntM);
668 for (; cntP < nvtot; cntP++) {
669 const auto& vt = pveVec[cntP];
670 auto dtime = std::abs(tv - vt.getTimeStamp().getTimeStamp());
671 if (dtime > mMaxVTTimeDiff) {
674 for (
int i = 0;
i < mMaxNeighbours;
i++) {
676 insSlot(dT, dtime,
i, idT, cntP);
680 auto dz = std::abs(pve.getZ() - vt.getZ());
681 for (
int i = 0;
i < mMaxNeighbours;
i++) {
683 insSlot(dZ, dz,
i, idZ, cntP);
688 for (
int i = 0;
i < mMaxNeighbours;
i++) {
690 pveT[
i] = pveVec[idT[
i]];
695 for (
int i = 0;
i < mMaxNeighbours;
i++) {
697 pveZ[
i] = pveVec[idZ[
i]];
702 (*mDBGOutVtx) <<
"pvExt"
706 <<
"tfID=" << TFCount
751 std::vector<OutputSpec> outputs;
752 auto dataRequest = std::make_shared<DataRequest>();
754 dataRequest->requestTracks(srcTracks, useMC);
755 dataRequest->requestClusters(srcClusters, useMC);
756 dataRequest->requestPrimaryVertices(useMC);
757 dataRequest->inputs.emplace_back(
"meanvtx",
"GLO",
"MEANVERTEX", 0, Lifetime::Condition,
ccdbParamSpec(
"GLO/Calib/MeanVertex", {}, 1));
758 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(
false,
768 {
"max-vtx-neighbours", VariantType::Int, 3, {
"Max PV neighbours fill, no PV study if < 0"}},
769 {
"max-vtx-timediff", VariantType::Float, 90.f, {
"Max PV time difference to consider"}},
770 {
"dcay-vs-pt", VariantType::String,
"0.0105 + 0.0350 / pow(x, 1.1)", {
"Formula for global tracks DCAy vs pT cut"}},
771 {
"dcaz-vs-pt", VariantType::String,
"0.0105 + 0.0350 / pow(x, 1.1)", {
"Formula for global tracks DCAy vs pT cut"}},
772 {
"min-tpc-clusters", VariantType::Int, 60, {
"Cut on TPC clusters"}},
773 {
"max-tpc-dcay", VariantType::Float, 5.f, {
"Cut on TPC dcaY"}},
774 {
"max-tpc-dcaz", VariantType::Float, 5.f, {
"Cut on TPC dcaZ"}},
775 {
"max-eta", VariantType::Float, 1.0f, {
"Cut on track eta"}},
776 {
"min-pt", VariantType::Float, 0.1f, {
"Cut on track pT"}},
777 {
"with-its-only", VariantType::Bool,
false, {
"Store tracks with ITS only"}},
778 {
"pair-correlations", VariantType::Bool,
false, {
"Do pairs correlation"}},
779 {
"occ-weight-fun", VariantType::String,
"(x>=-40&&x<-5) ? (1./1225*pow(x+40,2)) : ((x>-5&&x<15) ? 1. : ((x>=15&&x<40) ? (-0.4/25*x+1.24 ) : ( (x>40&&x<100) ? -0.4/60*x+0.6+0.8/3 : 0)))", {
"Occupancy weighting f-n vs time in musec"}},
780 {
"noccbins", VariantType::Int, 10, {
"Number of occupancy bins per full drift time"}},
781 {
"min-x-prop", VariantType::Float, 100.f, {
"track should be propagated to this X at least"}},
790 AlgorithmSpec{adaptFromTask<TrackingStudySpec>(dataRequest, ggRequest, srcTracks, useMC, sclOpts)},