From 66230275bd552e91b444c00b0aab914c5b3a97f2 Mon Sep 17 00:00:00 2001 From: creetz16 Date: Tue, 6 May 2025 16:54:42 +0200 Subject: [PATCH 1/7] Add decay3body builder helper --- PWGLF/Utils/decay3bodyBuilderHelper.h | 719 ++++++++++++++++++++++++++ 1 file changed, 719 insertions(+) create mode 100644 PWGLF/Utils/decay3bodyBuilderHelper.h diff --git a/PWGLF/Utils/decay3bodyBuilderHelper.h b/PWGLF/Utils/decay3bodyBuilderHelper.h new file mode 100644 index 00000000000..7c409f96f67 --- /dev/null +++ b/PWGLF/Utils/decay3bodyBuilderHelper.h @@ -0,0 +1,719 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef PWGLF_UTILS_DECAY3BODYBUILDERHELPER_H_ +#define PWGLF_UTILS_DECAY3BODYBUILDERHELPER_H_ + +#include +#include +#include +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisDataModel.h" +#include "ReconstructionDataFormats/Track.h" +#include "DetectorsBase/GeometryManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" +#include "Tools/KFparticle/KFUtilities.h" + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +/// includes KFParticle +#include "KFParticle.h" +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticleBase.h" +#include "KFVertex.h" + +namespace o2 +{ +namespace pwglf +{ + +//_______________________________________________________________________ +// Deca3body information storage +struct decay3bodyCandidate { + // indexing + int collisionID = -1; + int decay3bodyID = -1; + int trackPosID = -1; + int trackNegID = -1; + int trackBachID = -1; + + // daughter properties + std::array trackPosMom = {0.0f, 0.0f, 0.0f}; + std::array trackNegMom = {0.0f, 0.0f, 0.0f}; + std::array trackBachMom = {0.0f, 0.0f, 0.0f}; + std::array trackPosPos = {0.0f, 0.0f, 0.0f}; + std::array trackNegPos = {0.0f, 0.0f, 0.0f}; + std::array trackBachPos = {0.0f, 0.0f, 0.0f}; + std::array trackDCAxyToPV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach + std::array trackDCAzToPV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach + std::array tpcNsigma = {0.0f, 0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + float tofNsigmaDeuteron = 0.0f; + float averageITSClusSizeDeuteron = 0.0f; + int pidForTrackingDeuteron = 0; + + // vertex properties + int charge = -1; + float momentum[3]; + float position[3]; + // std::array momentum = {0.0f, 0.0f, 0.0f}; + // std::array position = {0.0f, 0.0f, 0.0f}; + // float dcaToPV = 0.0f; + // float dcaxyToPV = 0.0f; + float chi2 = 0.0f; + float trackedClSize = 0.0f; + float daughterDCAatSV = 0.0f; // quadratic sum of DCA between daughters at SV + std::array daughterDCAtoSV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach + + // covariance matrix + float trackPosCov[21] = {0.0f}; + float trackNegCov[21] = {0.0f}; + float trackBachCov[21] = {0.0f}; + float covariance[21] = {0.0f}; +}; + +//_______________________________________________________________________ +// builder helper class +class Decay3BodyBuilderHelper +{ + public: + strangenessBuilderHelper() + { + // standards hardcoded in builder ... + // ...but can be changed easily since fitter is public + fitter3body.setPropagateToPCA(true); + fitter3body.setMaxR(200.); + fitter3body.setMinParamChange(1e-3); + fitter3body.setMinRelChi2Change(0.9); + fitter3body.setMaxDZIni(1e9); + fitter3body.setMaxDXYIni(4.0f); + fitter3body.setMaxChi2(1e9); + fitter3body.setUseAbsDCA(true); + fitter3body.setWeightedFinalPCA(false); + + // LUT has to be loaded later + lut = nullptr; + fitter3body.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrLUT); + + // mag field has to be set later + fitter3body.setBz(-999.9f); // will NOT make sense if not changed + }; + + o2::base::MatLayerCylSet* lut; // material LUT for DCA fitter + o2::vertexing::DCAFitterN<2> fitterV0; // 2-prong o2 dca fitter + o2::vertexing::DCAFitterN<3> fitter3body; // 3-prong o2 dca fitter + + decay3bodyCandidate decay3body; // storage for Decay3body candidate properties + + // decay3body candidate criteria + struct { + // daughter tracks + float maxEtaDaughters; + int minTPCNClProton; + int minTPCNClPion; + int minTPCNClBach; + float minDCAProtonToPV; + float minDCAPionToPV; + float minDCABachToPV; + float minPtProton; + float minPtPion; + float minPtBach; + float maxPtProton; + float maxPtPion; + float maxPtBach; + float maxTPCnSigma; + float minTOFnSigmaDeuteron; + float maxTOFnSigmaDeuteron; + float minPBachUseTOF; + float maxDCADauAtSV; + // candidate + float maxRapidity; + float minPt; + float maxPt; + float minMass; + float maxMass; + float minCtau; + float maxCtau; + float minCosPA; + float maxChi2; + } decay3bodyselections; + + //_______________________________________________________________________ + // build Decay3body from three tracks, including V0 building. + template + bool buildDecay3BodyCandidate(TCollision const& collision, + TTrack const& trackPos, + TTrack const& trackNeg, + TTrack const& trackBach, + int decay3bodyIndex, + float todNsigmaDeuteron, + float trackedClSize, + int bachelorcharge = 1, + bool useKFParticle = false, + bool kfSetTopologicalConstraint = false, + bool useSelections = true, + bool useTPCforPion = false, + bool acceptTPCOnly = false, + bool calculateCovariance = true) + { + int collisionIndex = collision.globalIndex(); + float pvX = collision.posX(); + float pvY = collision.posY(); + float pvZ = collision.posZ(); + bool isMatter = trackBach.sign() > 0 ? true : false; + + auto trackParCovPos = getTrackParCov(trackPos); + auto trackParCovNeg = getTrackParCov(trackNeg); + auto trackParCovBach = getTrackParCov(trackBach); + + decay3body.collisionID = collisionIndex; + decay3body.decay3bodyID = decay3bodyIndex; + decay3body.trackPosID = trackPos.globalIndex(); + decay3body.trackNegID = trackNeg.globalIndex(); + decay3body.trackBachID = trackBach.globalIndex(); + + //_______________________________________________________________________ + // track selections + if constexpr (useSelections) { + // proton track quality + if (isMatter && trackPos.tpcNCls() < decay3bodyselections.minTPCNClProton) { + decay3body = {}; + return false; + } else if (!isMatter && trackNeg.tpcNCls() < decay3bodyselections.minTPCNClProton) { + decay3body = {}; + return false; + } + // pion track quality + if (useTPCforPion) { + if (isMatter && trackNeg.tpcNCls() < decay3bodyselections.minTPCNClPion) { + decay3body = {}; + return false; + } else if (!isMatter && trackPos.tpcNCls() < decay3bodyselections.minTPCNClPion) { + decay3body = {}; + return false; + } + } + // bachelor track quality + if (trackBach.tpcNCls() < decay3bodyselections.minTPCNClBach) { + decay3body = {}; + return false; + } + + // track signs + if (trackPos.sign() != +1 || trackNeg.sign() != -1) { + decay3body = {}; + return false; + } + + // track eta + if (std::fabs(trackPos.eta()) > decay3bodyselections.maxEtaDaughters) { + decay3body = {}; + return false; + } + if (std::fabs(trackNeg.eta()) > decay3bodyselections.maxEtaDaughters) { + decay3body = {}; + return false; + } + if (std::fabs(trackBach.eta()) > decay3bodyselections.maxEtaDaughters) { + decay3body = {}; + return false; + } + + // TPC only + if (!acceptTPCOnly && !trackPos.hasITS()) { + decay3body = {}; + return false; + } + if (!acceptTPCOnly && !trackNeg.hasITS()) { + decay3body = {}; + return false; + } + if (!acceptTPCOnly && !trackBach.hasITS()) { + decay3body = {}; + return false; + } + + // daughter TPC PID + if (isMatter) { + if (std::fabs(trackPos.tpcNsigmaPr()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } else if(useTPCforPion && std::fabs(trackNeg.tpcNsigmaPi()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } + } else if (!isMatter) { + if (std::fabs(trackNeg.tpcNsigmaPr()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } else if (useTPCforPion && std::fabs(trackPos.tpcNsigmaPi()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } + } + if (std::fabs(trackBach.tpcNsigmaDeuteron()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } + + // deuteron TOF PID + if ((tofNsigmaDeuteron < decay3bodyselections.minTOFnSigmaDeuteron || tofNsigmaDeuteron > decay3bodyselections.maxTOFnSigmaDeuteron) && trackBach.p() > decay3bodyselections.minPBachUseTOF) { + decay3body = {}; + return false; + } + } // end of selections + + //_______________________________________________________________________ + // daughter track DCA to PV associated with decay3body + o2::dataformats::VertexBase mPV; + o2::dataformats::DCA mDcaInfoCov; + auto trackParCovPosCopy = trackParCovPos; + auto trackParCovNegCopy = trackParCovNeg; + auto trackParCovBachCopy = trackParCovBach; + mPV.setPos({pvX, pvY, pvZ}); + mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + + // positive track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPosCopy, 2.f, matCorr, &mDcaInfoCov); + decay3body.trackDCAxyToPV[0] = mDcaInfoCov.getY(); + decay3body.trackDCAzToPV[0] = mDcaInfoCov.getZ(); + auto trackPosDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[0] * decay3body.trackDCAxyToPV[0] + decay3body.trackDCAzToPV[0] * decay3body.trackDCAzToPV[0]); + if constexpr (useSelections) { + if (isMatter && trackPosDCAToPV < decay3bodyselections.minDCAProtonToPV) { + decay3body = {}; + return false; + } else if (!isMatter && trackPosDCAToPV < decay3bodyselections.minDCAPionToPV) { + decay3body = {}; + return false; + } + } + // negative track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParNegPosCopy, 2.f, matCorr, &mDcaInfoCov); + decay3body.trackDCAxyToPV[1] = mDcaInfoCov.getY(); + decay3body.trackDCAzToPV[1] = mDcaInfoCov.getZ(); + auto trackNegDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[1] * decay3body.trackDCAxyToPV[1] + decay3body.trackDCAzToPV[1] * decay3body.trackDCAzToPV[1]); + if constexpr (useSelections) { + if (isMatter && trackNegDCAToPV < decay3bodyselections.minDCAPionToPV) { + decay3body = {}; + return false; + } else if (!isMatter && trackNegDCAToPV < decay3bodyselections.minDCAProtonToPV) { + decay3body = {}; + return false; + } + } + // bachelor track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovBachCopy, 2.f, matCorr, &mDcaInfoCov); + decay3body.trackDCAxyToPV[2] = mDcaInfoCov.getY(); + decay3body.trackDCAzToPV[2] = mDcaInfoCov.getZ(); + auto trackBachDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[2] * decay3body.trackDCAxyToPV[2] + decay3body.trackDCAzToPV[2] * decay3body.trackDCAzToPV[2]); + if constexpr (useSelections) { + if (trackBachDCAToPV < decay3bodyselections.minDCABachToPV) { + decay3body = {}; + return false; + } + } + + //_______________________________________________________________________ + // fit 3body vertex + if (!useKFParticle) { + fitVertexWithDCAFitter(collision, trackParCovPos, trackParCovNeg, trackParCovBach, bachelorcharge, calculateCovariance); + } else { + fitVertexWithKF(collision, trackParCovPos, trackParCovNeg, trackParCovBach, bachelorcharge, kfSetTopologicalConstraint, calculateCovariance); + } + + //_______________________________________________________________________ + // get vertex information + // daughter pT + auto trackPosPt = std::sqrt(decay3body.trackPosMom[0] * decay3body.trackPosMom[0] + decay3body.trackPosMom[1] * decay3body.trackPosMom[1]); + auto trackNegPt = std::sqrt(decay3body.trackNegMom[0] * decay3body.trackNegMom[0] + decay3body.trackNegMom[1] * decay3body.trackNegMom[1]); + auto trackBachPt = std::sqrt(decay3body.trackBachMom[0] * decay3body.trackBachMom[0] + decay3body.trackBachMom[1] * decay3body.trackBachMom[1]); + + // DCA between daughters at SV + decay3body.daughterDCAatSV = std::hypot( + std::hypot(decay3body.trackPosPos[0] - decay3body.trackNegPos[0], + decay3body.trackPosPos[1] - decay3body.trackNegPos[1], + decay3body.trackPosPos[2] - decay3body.trackNegPos[2]), + std::hypot(decay3body.trackPosPos[0] - decay3body.trackBachPos[0], + decay3body.trackPosPos[1] - decay3body.trackBachPos[1], + decay3body.trackPosPos[2] - decay3body.trackBachPos[2]), + std::hypot(decay3body.trackNegPos[0] - decay3body.trackBachPos[0], + decay3body.trackNegPos[1] - decay3body.trackBachPos[1], + decay3body.trackNegPos[2] - decay3body.trackBachPos[2])); + + // daughter DCA to SV + // positive daughter + decay3body.daughterDCAtoSV[0] = std::hypot( + decay3body.trackPosPos[0] - decay3body.position[0], + decay3body.trackPosPos[1] - decay3body.position[1], + decay3body.trackPosPos[2] - decay3body.position[2]); + // negative daughter + decay3body.daughterDCAtoSV[1] = std::hypot( + decay3body.trackNegPos[0] - decay3body.position[0], + decay3body.trackNegPos[1] - decay3body.position[1], + decay3body.trackNegPos[2] - decay3body.position[2]); + // bachelor daughter + decay3body.daughterDCAtoSV[2] = std::hypot( + decay3body.trackBachPos[0] - decay3body.position[0], + decay3body.trackBachPos[1] - decay3body.position[1], + decay3body.trackBachPos[2] - decay3body.position[2]); + + //_____________________________________________________ + // selections after vertex fit + if constexpr (useSelections) { + // daughter pT + // proton + if (isMatter && (trackPosPt < decay3bodyselections.minPtProton || trackPosPt > decay3bodyselections.maxPtProton)) { + decay3body = {}; + return false; + } else if (!isMatter && (trackNegPt < decay3bodyselections.minPtProton || trackNegPt > decay3bodyselections.maxPtProton)) { + decay3body = {}; + return false; + } + // pion + if (isMatter && (trackNegPt < decay3bodyselections.minPtPion || trackNegPt > decay3bodyselections.maxPtPion)) { + decay3body = {}; + return false; + } else if (!isMatter && (trackPosPt < decay3bodyselections.minPtPion || trackPosPt > decay3bodyselections.maxPtPion)) { + decay3body = {}; + return false; + } + // bachelor + if (trackBachPt < decay3bodyselections.minPtBach || trackBachPt > decay3bodyselections.maxPtBach) { + decay3body = {}; + return false; + } + + // daughter DCAs at SV + if (decay3body.daughterDCAatSV > decay3bodyselections.maxDCADauAtSV) { + decay3body = {}; + return false; + } + + // rapidity + float rapidity = RecoDecay::y(std::array{decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]}, o2::constants::physics::MassHyperTriton); + if (std::fabs(rapidity) > decay3bodyselections.maxRapidity) { + decay3body = {}; + return false; + } + + // pT + float pT = RecoDecay::pt(std::array{decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]}); + if (pT < decay3bodyselections.minPt || pT > decay3bodyselections.maxPt) { + decay3body = {}; + return false; + } + + // mass window + if (decay3body.mass < decay3bodyselections.minMass || decay3body.mass > decay3bodyselections.maxMass) { + decay3body = {}; + return false; + } + + // pointing angle + float cpa = RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{decay3body.position[0], decay3body.position[1], decay3body.position[2]}, std::array{decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]}); + if (cpa < decay3bodyselections.minCosPA) { + decay3body = {}; + return false; + } + + // vertex chi2 + if (decay3body.chi2 > decay3bodyselections.maxChi2) { + decay3body = {}; + return false; + } + + // ctau + float P = RecoDecay::sqrtSumOfSquares(decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]); + float ctau = std::sqrt(std::pow(decay3body.position[0] - pvX, 2) + std::pow(decay3body.position[1] - pvY, 2) + std::pow(decay3body.position[2] - pvZ, 2)) / (P + 1E-10) * o2::constants::physics::MassHyperTriton; + if (ctau < decay3bodyselections.minCtau || ctau > decay3bodyselections.maxCtau) { + decay3body = {}; + return false; + } + } + + //_______________________________________________________________________ + // fill remaining candidate information + // daughter PID + if (isMatter) { + decay3body.tpcNsigma[0] = trackPos.tpcNsigmaPr(); + decay3body.tpcNsigma[1] = trackNeg.tpcNsigmaPi(); + } else if (!isMatter) { + decay3body.tpcNsigma[0] = trackNeg.tpcNsigmaPr(); + decay3body.tpcNsigma[1] = trackPos.tpcNsigmaPi(); + } + decay3body.tpcNsigma[2] = trackBach.tpcNsigmaDeuteron(); + decay3body.tpcNsigma[3] = trackBach.tpcNsigmaPi(); + // recalculated bachelor TOF PID + decay3body.tofNsigmaDeuteron = todNsigmaDeuteron; + + // average ITS cluster size of deuteron track + double averageClusterSizeDeuteron(0); + int nCls(0); + for (int i = 0; i < 7; i++) { + int clusterSize = trackBach.itsClsSizeInLayer(i); + averageClusterSizeDeuteron += static_cast(clusterSize); + if (clusterSize > 0) + nCls++; + } + averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nCls); + decay3body.averageITSClusSizeDeuteron = averageITSClusSizeDeuteron; + + // PID for tracking of deuteron track + decay3body.pidForTrackingDeuteron = trackBach.pidForTracking(); + + // tracked cluster size + decay3body.trackedClSize = trackedClSize; + + return true; + } + + //_______________________________________________________________________ + // build Decay3body from V0 and bachelor + // template <> + // bool buildDecay3BodyCandidate() + // { + // return true; + // } + + //___________________________________________________________________________________ + // functionality to fit 3body vertex with KFParticle and fill vertex information + template + void fitVertexWithKF(TCollision const& collision, + TTrackParCov const& trackParCovPos, + TTrackParCov const& trackParCovNeg, + TTrackParCov const& trackParCovBach, + int bachelorcharge = 1, + bool kfSetTopologicalConstraint = true, + bool calculateCovariance = true) + { + bool isMatter = trackParCovBach.sign() > 0 ? true : false; + + // initialise KF primary vertex + KPFVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle kfpv(kfpVertex); + + // create KFParticle objects + KFParticle kfpProton, kfpPion, kfpDeuteron; + if (isMatter) { + kfpProton = createKFParticleFromTrackParCov(trackParCovPos, trackParCovPos.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovNeg, trackParCovNeg.sign(), constants::physics::MassPionCharged); + } else if (!isMatter) { + kfpProton = createKFParticleFromTrackParCov(trackParCovNeg, trackParCovNeg.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovPos, trackParCovPos.sign(), constants::physics::MassPionCharged); + } + kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, trackParCovBach.sign(), constants::physics::MassDeuteron); + + // construct vertex + KFParticle KFH3L; + int nDaughters3body = 3; + const KFParticle* Daughters3body[3] = {&kfpProton, &kfpPion, &kfpDeuteron}; + KFH3L.SetConstructMethod(2); + try { + KFH3L.Construct(Daughters3body, nDaughters3body); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create Hyper triton 3-body vertex." << e.what(); + return; + } + + // topological constraint + if (kfSetTopologicalConstraint) { + KFH3L.SetProductionVertex(kfpv); + KFH3L.TransportToDecayVertex(); + } + + // get vertex position and momentum + decay3body.position[0] = KFH3L.GetX(); + decay3body.position[1] = KFH3L.GetY(); + decay3body.position[2] = KFH3L.GetZ(); + decay3body.momentum[0] = KFH3L.GetPx(); + decay3body.momentum[1] = KFH3L.GetPy(); + decay3body.momentum[2] = KFH3L.GetPz(); + + // get charge + decay3body.charge = KFH3L.GetQ(); + + // transport all daughter tracks to hypertriton vertex + kfpProton.TransportToPoint(decay3body.position); + kfpPion.TransportToPoint(decay3body.position); + kfpDeuteron.TransportToPoint(decay3body.position); + + // daughter momenta and positions + if (isMatter) { + decay3body.trackPosMom[0] = kfpProton.GetPx(); + decay3body.trackPosMom[1] = kfpProton.GetPy(); + decay3body.trackPosMom[2] = kfpProton.GetPz(); + decay3body.trackNegMom[0] = kfpPion.GetPx(); + decay3body.trackNegMom[1] = kfpPion.GetPy(); + decay3body.trackNegMom[2] = kfpPion.GetPz(); + decay3body.trackPosPos[0] = kfpProton.GetX(); + decay3body.trackPosPos[1] = kfpProton.GetY(); + decay3body.trackPosPos[2] = kfpProton.GetZ(); + decay3body.trackNegPos[0] = kfpPion.GetX(); + decay3body.trackNegPos[1] = kfpPion.GetY(); + decay3body.trackNegPos[2] = kfpPion.GetZ(); + } else { + decay3body.trackPosMom[0] = kfpPion.GetPx(); + decay3body.trackPosMom[1] = kfpPion.GetPy(); + decay3body.trackPosMom[2] = kfpPion.GetPz(); + decay3body.trackNegMom[0] = kfpProton.GetPx(); + decay3body.trackNegMom[1] = kfpProton.GetPy(); + decay3body.trackNegMom[2] = kfpProton.GetPz(); + decay3body.trackPosPos[0] = kfpPion.GetX(); + decay3body.trackPosPos[1] = kfpPion.GetY(); + decay3body.trackPosPos[2] = kfpPion.GetZ(); + decay3body.trackNegPos[0] = kfpProton.GetX(); + decay3body.trackNegPos[1] = kfpProton.GetY(); + decay3body.trackNegPos[2] = kfpProton.GetZ(); + } + decay3body.trackBachMom[0] = kfpDeuteron.GetPx(); + decay3body.trackBachMom[1] = kfpDeuteron.GetPy(); + decay3body.trackBachMom[2] = kfpDeuteron.GetPz(); + decay3body.trackBachPos[0] = kfpDeuteron.GetX(); + decay3body.trackBachPos[1] = kfpDeuteron.GetY(); + decay3body.trackBachPos[2] = kfpDeuteron.GetZ(); + for (int i = 0; i < 3; i++) { + trackBachMom[i] *= bachelorcharge; + } + + // candidate mass + float mass, massErr; + KFH3L.GetMass(mass, massErr); + decay3body.mass = mass; + + // vertex chi2 + decay3body.chi2 = KFH3L.GetChi2() / KFH3L.GetNDF(); + + // caluclate covariance matrices + if (calculateCovariance) { + // candidate covariance matrix + o2::gpu::gpustd::array covKF; + for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) + covKF[i] = KFH3L.GetCovariance(i); + decay3body.covariance[i] = covKF[i]; + } + // daughter track covariance matrices + for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) + decay3body.trackPosCov[i] = kfpProton.GetCovariance(i); + decay3body.trackNegCov[i] = kfpPion.GetCovariance(i); + decay3body.trackBachCov[i] = kfpDeuteron.GetCovariance(i); + } + } + + return; + } + + //_______________________________________________________________________ + // functionality to fit 3body vertex with DCAFitter + template + void fitVertexWithDCAFitter(TCollision const& collision, + TTrackParCov const& trackParCovPos, + TTrackParCov const& trackParCovNeg, + TTrackParCov const& trackParCovBach + int bachelorcharge = 1, + bool calculateCovariance = true) + { + bool isMatter = trackParCovBach.sign() > 0 ? true : false; + + // fit the vertex + int n3bodyVtx = fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); + if (n3bodyVtx == 0) { // discard this pair + return; + } + + // get vertex position + const auto& vtxXYZ = fitter3body.getPCACandidate(); + for (int i = 0; i < 3; i++) { + decay3body.position[i] = vtxXYZ[i]; + } + + // get daughter momenta + const auto& propagatedTrackPos = fitter3body.getTrack(0); + const auto& propagatedTrackNeg = fitter3body.getTrack(1); + const auto& propagatedTrackBach = fitter3body.getTrack(2); + propagatedTrackPos.getPxPyPzGlo(trackPosMom); + propagatedTrackNeg.getPxPyPzGlo(trackNegMom); + propagatedTrackBach.getPxPyPzGlo(trackBachMom); + for (int i = 0; i < 3; i++) { + trackBachMom[i] *= bachelorcharge; + } + + // calculate candidate momentum + decay3body.momentum[0] = trackPosMom[0] + trackNegMom[0] + trackBachMom[0]; + decay3body.momentum[1] = trackPosMom[1] + trackNegMom[1] + trackBachMom[1]; + decay3body.momentum[2] = trackPosMom[2] + trackNegMom[2] + trackBachMom[2]; + + // candidate mass + if (isMatter) { + decay3body.mass = RecoDecay::m( + std::array{std::array{trackPosMom[0], trackPosMom[1], trackPosMom[2]}, + std::array{trackNegMom[0], trackNegMom[1], trackNegMom[2]}, + std::array{trackBachMom[0], trackBachMom[1], trackBachMom[2]}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + } else { + decay3body.mass = RecoDecay::m( + std::array{std::array{trackPosMom[0], trackPosMom[1], trackPosMom[2]}, + std::array{trackNegMom[0], trackNegMom[1], trackNegMom[2]}, + std::array{trackBachMom[0], trackBachMom[1], trackBachMom[2]}}, + std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); + } + + // vertex chi2 at PCA + decay3body.chi2 = fitter3body.getChhi2AtPCACandidate(): + + // caluclate covariance matrices + if (calculateCovariance) { + // candidate position covariance matrix + auto covVtxV = fitter3body.calcPCACovMatrix(0); + decay3body.covariance[0] = covVtxV(0, 0); + decay3body.covariance[1] = covVtxV(1, 0); + decay3body.covariance[2] = covVtxV(1, 1); + decay3body.covariance[3] = covVtxV(2, 0); + decay3body.covariance[4] = covVtxV(2, 1); + decay3body.covariance[5] = covVtxV(2, 2); + // daughter covariance matrices + std::array covTpos = {0.}; + std::array covTneg = {0.}; + std::array covTbach = {0.}; + propagatedTrackPos.getCovXYZPxPyPzGlo(covTpos); + propagatedTrackNeg.getCovXYZPxPyPzGlo(covTneg); + propagatedTrackBach.getCovXYZPxPyPzGlo(covTbach); + for (int i = 0; i < 21; i++) { + decay3body.trackPosCov[i] = covTpos[i]; + decay3body.trackNegCov[i] = covTneg[i]; + decay3body.trackBachCov[i] = covTbach[i]; + } + // candidate momentum covairance matrix + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + decay3body.covariance[MomInd[i]] = covTpos[MomInd[i]] + covTneg[MomInd[i]] + covTbach[MomInd[i]]; + } + /// WARNING: position-momentum covariances are not calculated in the DCAFitter - remain zero + } + + return; + } + + private: + // internal helper to calculate DCA (3D) of a straight line to a given PV analytically + float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) + { + return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); + } + +}; + +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_DECAY3BODYBUILDERHELPER_H_ \ No newline at end of file From 90654dc43aedcb1dbb125eee08ac95c1bdeac9b1 Mon Sep 17 00:00:00 2001 From: creetz16 Date: Fri, 9 May 2025 13:22:39 +0200 Subject: [PATCH 2/7] Save changes to decay3bodybuilder --- .../Nuspex/decay3bodybuilder_new.cxx | 2000 +++++++++++++++++ PWGLF/Utils/decay3bodyBuilderHelper.h | 183 +- 2 files changed, 2170 insertions(+), 13 deletions(-) create mode 100644 PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx new file mode 100644 index 00000000000..296ad0503a6 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx @@ -0,0 +1,2000 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// ======================== +/// \file decay3bodybuilder.cxx +/// \brief Builder task for 3-body decay reconstruction (p + pion + bachelor) +/// \author Yuanzhe Wang +/// \author Carolina Reetz +// ======================== + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "DCAFitter/DCAFitterN.h" +#include "ReconstructionDataFormats/Track.h" +#include "DetectorsVertexing/SVertexHypothesis.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/Reduced3BodyTables.h" +#include "PWGLF/DataModel/Vtx3BodyTables.h" +#include "PWGLF/DataModel/pidTOFGeneric.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "TableHelper.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DataFormatsCalibration/MeanVertexObject.h" + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +// includes KFParticle +#include "KFParticle.h" +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticleBase.h" +#include "KFVertex.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +static constexpr int nParameters = 1; +static const std::vector tableNames { + "Decay3BodyIndices", + "StoredDecay3BodyCores", + "Decay3BodyCovs", + "Decay3BodyDaughterCovs", + "McDecay3BodyLabels" +}; + +static constexpr int nTablesConst = 5; + +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[nTablesConst][nParameters]{ + {0}, // Decay3BodyIndices + {0}, // StoredDecay3BodyCores + {0}, // Decay3BodyCovs + {0}, // Decay3BodyDaughterCovs + {0} // McDecay3BodyLabels +}; + +using FullTracksExtIU = soa::Join; +using FullTracksExtPIDIU = soa::Join; +using FullTracksExtIULabeled = soa::Join; +using FullTracksExtIUwithEvTimes = soa::Join; +using FullTracksExtPIDIUwithEvTimes = soa::Join; + +using ColwithEvTimes = o2::soa::Join; +using ColwithEvTimesMults = o2::soa::Join; + +using ReducedCollisionsMults = soa::Join; +using ReducedCollisionsMultsCents = soa::Join; + +// namespace +// { +// const float pidCutsLambda[o2::vertexing::SVertexHypothesis::NPIDParams] = {0., 20, 0., 5.0, 0.0, 1.09004e-03, 2.62291e-04, 8.93179e-03, 2.83121}; // Lambda +// } // namespace + +// struct VtxCandidate { +// int track0Id; +// int track1Id; +// int track2Id; +// int collisionId; +// int decay3bodyId; +// float vtxPos[3]; +// float track0P[3]; +// float track1P[3]; +// float track2P[3]; +// float dcadaughters; +// float daudcaxytopv[3]; // 0 - proton, 1 - pion, 2 - bachelor +// float daudcatopv[3]; // 0 - proton, 1 - pion, 2 - bachelor +// float bachelortofNsigma; +// }; + +// struct kfCandidate { +// // hypertriton +// int collisionID; +// int trackPosID; +// int trackNegID; +// int trackBachID; +// int decay3bodyID; +// float mass; +// float pos[3]; +// float posErr[3]; +// float mom[4]; +// float momErr[4]; +// float charge; +// float dcaToPV[2]; // 3D, xy +// float cpaToPV[2]; // 3D, xy +// float cpaToPVtopo[2]; // 3D, xy +// float decLen[2]; // 3D, xy +// float ldl; +// float chi2geoNDF; +// float chi2topoNDF; +// float ctau; +// float trackedClSize; +// float DeltaPhiRotDeuteron; +// float DeltaPhiRotProton; +// // V0 +// float massV0; +// float chi2massV0; +// float cpaV0ToPV; +// // daughter momenta +// float protonMom[3]; +// float pionMom[3]; +// float deuteronMom[3]; +// float tpcInnerParam[3]; // proton, pion, deuteron +// // daughter track quality +// int tpcNClDaughters[3]; // proton, pion, deuteron +// float tpcChi2NClDeuteron; +// // daughter DCAs KF +// float DCAdaughterToPV[3]; // proton, pion, deuteron +// float DCAdaughterToPVxy[3]; // proton, pion, deuteron +// float DCAdaughterToSVxy[3]; // proton, pion, deuteron +// float DCAprotonToPion; +// float DCAprotonToDeuteron; +// float DCApionToDeuteron; +// float DCAvtxDaughters3D; +// // daughter DCAs to PV propagated with material +// float trackDCAxy[3]; // pos, neg, bach +// float trackDCA[3]; // pos, neg, bach +// // daughter signs +// float daughterCharge[3]; // proton, pion, deuteron +// // daughter PID +// float tpcNsigma[4]; // proton, pion, deuteron, bach with pion hyp +// float tpcdEdx[3]; // proton, pion, deuteron +// float tofNsigmaDeuteron; +// float averageClusterSizeDeuteron; +// float pidForTrackingDeuteron; +// }; + +struct decay3bodyBuilder { + + // helper object + o2::pwglf::decay3bodyBuilderHelper helper; + + // table index : match order above + enum tableIndex { kDecay3BodyIndices = 0, + kStoredDecay3BodyCores, + kDecay3BodyCovs, + kDecay3BodyDaughterCovs, + kMcDecay3BodyLabels, + kMcDecay3BodyCores, + kMcDecay3BodyCollRefs, + nTables }; + + struct : ProducesGroup { + Produces decay3bodyindices; + Produces decay3bodycores; + Produces decay3bodycovs; + Produces decay3bodydaugcovs; + Produces mcdecay3bodylabels; + } products; + + Configurable> enabledTables{"enabledTables", {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, "Produce this table: 0 - false, 1 - true"} + std::vector mEnabledTables; // Vector of enabled tables + + // general options + Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; + Configurable doTrackQA{"doTrackQA", false, "Flag to fill QA histograms for daughter tracks."}; + Configurable doVertexQA{"doVertexQA", false, "Flag to fill QA histograms for PV."}; + + // data processing options + Configurable doSkimmedProcessing{"doSkimmedProcessing", false, "Apply Zoroo counting in case of skimmed data input"}; + Configurable triggerList{"triggerList", "fTriggerEventF1Proton, fTrackedOmega, fTrackedXi, fOmegaLargeRadius, fDoubleOmega, fOmegaHighMult, fSingleXiYN, fQuadrupleXi, fDoubleXi, fhadronOmega, fOmegaXi, fTripleXi, fOmega, fGammaVeryLowPtEMCAL, fGammaVeryLowPtDCAL, fGammaHighPtEMCAL, fGammaLowPtEMCAL, fGammaVeryHighPtDCAL, fGammaVeryHighPtEMCAL, fGammaLowPtDCAL, fJetNeutralLowPt, fJetNeutralHighPt, fGammaHighPtDCAL, fJetFullLowPt, fJetFullHighPt, fEMCALReadout, fPCMandEE, fPHOSnbar, fPCMHighPtPhoton, fPHOSPhoton, fLD, fPPPHI, fPD, fLLL, fPLL, fPPL, fPPP, fLeadingPtTrack, fHighFt0cFv0Flat, fHighFt0cFv0Mult, fHighFt0Flat, fHighFt0Mult, fHighMultFv0, fHighTrackMult, fHfSingleNonPromptCharm3P, fHfSingleNonPromptCharm2P, fHfSingleCharm3P, fHfPhotonCharm3P, fHfHighPt2P, fHfSigmaC0K0, fHfDoubleCharm2P, fHfBeauty3P, fHfFemto3P, fHfFemto2P, fHfHighPt3P, fHfSigmaCPPK, fHfDoubleCharm3P, fHfDoubleCharmMix, fHfPhotonCharm2P, fHfV0Charm2P, fHfBeauty4P, fHfV0Charm3P, fHfSingleCharm2P, fHfCharmBarToXiBach, fSingleMuHigh, fSingleMuLow, fLMeeHMR, fDiMuon, fDiElectron, fLMeeIMR, fSingleE, fTrackHighPt, fTrackLowPt, fJetChHighPt, fJetChLowPt, fUDdiffLarge, fUDdiffSmall, fITSextremeIonisation, fITSmildIonisation, fH3L3Body, fHe, fH2", "List of triggers used to select events"}; + + // CCDB options + struct : ConfigurableGroup { + std::string prefix = "ccdb"; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } ccdbConfigurations; + + // Decay3body building options + struct : ConfigurableGroup { + std::string prefix = "decay3bodyBuilderOpts"; + // building options + Configurable useKFParticle{"useKFParticle", false, "Use KFParticle for decay3body building"}; + Configurable kfSetTopologicalConstraint{"kfSetTopologicalConstraint", false, "Set topological vertex constraint in case of KFParticle reconstruction"}; + Configurable useSelections{"useSelections", true, "Apply selections during decay3body building"}; + Configurable acceptTPCOnly{"acceptTPCOnly", false, "Accept TPC only tracks as daughters"}; + Configurable calculateCovariance{"calculateCovariance", true, "Calculate candidate and daughter covariance matrices"}; + // daughter track selections + Configurable maxEtaDaughters{"maxEtaDaughters", 0.9, "Max eta of daughters"}; + Configurable minTPCNClProton{"minTPCNClProton", 90, "Min TPC NClusters of proton daughter"}; + Configurable minTPCNClPion{"minTPCNClPion", 70, "Min TPC NClusters of pion daughter"}; + Configurable minTPCNClBach{"minTPCNClBach", 100, "Min TPC NClusters of bachelor daughter"}; + Configurable minDCAProtonToPV{"minDCAProtonToPV", 0.1, "Min DCA of proton to PV"}; + Configurable minDCAPionToPV{"minDCAPionToPV", 0.1, "Min DCA of pion to PV"}; + Configurable minDCABachToPV{"minDCABachToPV", 0.1, "Min DCA of bachelor to PV"}; + Configurable minPtProton{"minPtProton", 0.3, "Min Pt of proton daughter"}; + Configurable minPtPion{"minPtPion", 0.1, "Min Pt of pion daughter"}; + Configurable minPtBach{"minPtBach", 0.6, "Min Pt of bachelor daughter"}; + Configurable maxPtProton{"maxPtProton", 5.0, "Max Pt of proton daughter"}; + Configurable maxPtPion{"maxPtPion", 1.2, "Max Pt of pion daughter"}; + Configurable maxPtBach{"maxPtBach", 10.0, "Max Pt of bachelor daughter"}; + Configurable maxTPCnSigma{"maxTPCnSigma", 5.0, "Min/max TPC nSigma of daughter tracks"}; + Configurable minTOFnSigmaDeuteron{"minTOFnSigmaDeuteron", -5.0, "Min TOF nSigma of deuteron daughter"}; + Configurable maxTOFnSigmaDeuteron{"maxTOFnSigmaDeuteron", 5.0, "Max TOF nSigma of deuteron daughter"}; + Configurable minPBachUseTOF{"minPBaChUseTOF", 1.0, "Min P of bachelor to use TOF PID"}; + Configurable maxDCADauAtSV{"maxDCADauAtSV", 0.5, "Max DCA of daughters at SV (quadratic sum of daughter DCAs between each other)"}; + // candidate selections + Configurable maxRapidity{"maxRapidity", 1.0, "Max rapidity of decay3body vertex"}; + Configurable minPt{"minPt", 2.0, "Min Pt of decay3body candidate"}; + Configurable maxPt{"maxPt", 5.0, "Max Pt of decay3body candidate"}; + Configurable minMass{"minMass", 2.96, "Min mass of decay3body candidate"}; + Configurable maxMass{"maxMass", 3.04, "Max mass of decay3body candidate"}; + Configurable minCtau{"minCtau", 0.0, "Min ctau of decay3body candidate"}; + Configurable maxCtau{"maxCtau", 100.0, "Max ctau of decay3body candidate"}; + Configurable minCosPA{"minCosPA", 0.9, "Min cosPA of decay3body candidate"}; + Configurable maxChi2{"maxChi2", 100.0, "Max chi2 of decay3body candidate"}; + } decay3bodyBuilderOpts; + + struct : ConfigurableGroup { + std::string prefix = "eventMixingOpts"; + Configurable minPt2V0{"minPt2V0", 0.5, "Min Pt squared of V0"}; + Configurable maxTgl2V0{"maxTgl2V0", 4, "Max tgl squared of V0"}; + Configurable maxDCAXY2ToMeanVertex3bodyV0{"maxDCAXY2ToMeanVertex3bodyV0", 4, "Max DCA XY squared of V0 to mean vertex"}; + Configurable minCosPAXYMeanVertex3bodyV0{"minCosPAXYMeanVertex3bodyV0", 0.9, "Min cosPA XY of V0 to mean vertex"}; + Configurable minCosPA3bodyV0{"minCosPA3bodyV0", 0.8, "Min cosPA of V0"}; + Configurable maxRDiffV03body{"maxRDiffV03body", 3, "Max RDiff of V0 to 3body"}; + Configurable minPt3Body{"minPt3Body", 0.5, "Min Pt of 3body"}; + Configurable maxTgl3Body{"maxTgl3Body", 0.01, "Max tgl of 3body"}; + Configurable maxDCAXY3Body{"maxDCAXY3Body", 0.5, "Max DCA XY of 3body"}; + Configurable maxDCAZ3Body{"maxDCAZ3Body", 1.0, "Max DCA Z of 3body"}; + } eventMixingOpts; + + struct : ConfigurableGroup { + std::string prefix = "tofPIDOpts"; + Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; + Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; + Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; + Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + } tofPIDOpts; + + + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + int mRunNumber; + o2::base::MatLayerCylSel* lut = nullptr; + + HistogramRegistry registry{"Registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + std::vector sorted_decay3body; + + // bachelor TOF PID + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init base on the hypothesis + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + + // event mixing selection + std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda + bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc + + // skimmed processing + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + + // ========================== + std::vector VtxCandidates; + + std::unordered_map ccdbCache; // Maps runNumber -> d_bz + std::unordered_map> grpMagCache; // Maps runNumber -> grpmap + + + std::vector fTrackedClSizeVector; + + // Configurables + Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; + + enum Hyp3Body { kH3L = 0, + kH4L, + kHe4L, + kHe5L, + kNHyp3body }; + + enum VtxStep { kVtxAll = 0, + kVtxTPCNcls, + kVtxPIDCut, + kVtxhasSV, + kVtxDcaDau, + kVtxCosPA, + kNVtxSteps }; + + enum kfvtxstep { kKfVtxAll = 0, + kKfVtxCharge, + kKfVtxEta, + kKfVtxTPCNcls, + kKfVtxTPCRows, + kKfVtxTPCPID, + kKfVtxDCAxyPV, + kKfVtxDCAzPV, + kKfVtxV0MassConst, + kKfVtxhasSV, + kKfVtxDcaDau, + kKfVtxDcaDauVtx, + kKfVtxDauPt, + kKfVtxRap, + kKfVtxPt, + kKfVtxMass, + kKfVtxCosPA, + kKfVtxCosPAXY, + kKfVtxChi2geo, + kKfVtxTopoConstr, + kKfVtxChi2topo, + kKfNVtxSteps }; + + + + // for KFParticle reconstruction + struct : ConfigurableGroup { + Configurable cfgOnlyKeepInterestedTrigger{"kfparticleConfigurations.cfgOnlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; + Configurable fillCandidateFullTable{"kfparticleConfigurations.fillCandidateFullTable", false, "Switch to fill full table with candidate properties"}; + Configurable doSel8selection{"kfparticleConfigurations.doSel8selection", true, "flag for sel8 event selection"}; + Configurable doPosZselection{"kfparticleConfigurations.doPosZselection", true, "flag for posZ event selection"}; + + Configurable applyTopoSel{"kfparticleConfigurations.applyTopoSel", false, "Apply selection constraining the mother to the PV with KFParticle"}; + Configurable maxChi2topo{"kfparticleConfigurations.maxChi2topo", 1000., "Maximum chi2 topological with KFParticle"}; + // 3body mixing + Configurable mixingType{"kfparticleConfigurations.mixingType", 0, "0: mix V0 from one event with bachelor from another, 1: mix pion and bachelor from one event with proton from another "}; + ConfigurableAxis bins3BodyRadius{"kfparticleConfigurations.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}, "Mixing bins - 3body radius"}; + // ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f*TMath::Pi()/180, -170.0f*TMath::Pi()/180, -160.0f*TMath::Pi()/180, -150.0f*TMath::Pi()/180, -140.0f*TMath::Pi()/180, -130.0f*TMath::Pi()/180, -120.0f*TMath::Pi()/180, -110.0f*TMath::Pi()/180, -100.0f*TMath::Pi()/180, -90.0f*TMath::Pi()/180, -80.0f*TMath::Pi()/180, -70.0f*TMath::Pi()/180, -60.0f*TMath::Pi()/180, -50.0f*TMath::Pi()/180, -40.0f*TMath::Pi()/180, -30.0f*TMath::Pi()/180, -20.0f*TMath::Pi()/180, -10.0f*TMath::Pi()/180, 0.0f, 10.0f*TMath::Pi()/180, 20.0f*TMath::Pi()/180, 30.0f*TMath::Pi()/180, 40.0f*TMath::Pi()/180, 50.0f*TMath::Pi()/180, 60.0f*TMath::Pi()/180, 70.0f*TMath::Pi()/180, 80.0f*TMath::Pi()/180, 90.0f*TMath::Pi()/180, 100.0f*TMath::Pi()/180, 110.0f*TMath::Pi()/180, 120.0f*TMath::Pi()/180, 130.0f*TMath::Pi()/180, 140.0f*TMath::Pi()/180, 150.0f*TMath::Pi()/180, 160.0f*TMath::Pi()/180, 170.0f*TMath::Pi()/180, 180.0f*TMath::Pi()/180}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPosZ{"kfparticleConfigurations.bins3BodyPosZ", {VARIABLE_WIDTH, -300.0f, -42.0f, -13.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 13.0f, 42.0f, 300.0f}, "Mixing bins - 3body z position"}; + Configurable selectVtxZ3bodyMixing{"kfparticleConfigurations.selectVtxZ3bodyMixing", true, "Select same VtxZ events in case of 3body mixing"}; + Configurable VtxZBin3bodyMixing{"kfparticleConfigurations.VtxZBin3bodyMixing", 1., "Bin width for event vtx z position in case of 3body mixing"}; + } kfparticleConfigurations; + + //------------------------------------------------------------------ + // Sets for DCAFitter event mixing + struct : ConfigurableGroup { + // Binning for mixing events + ConfigurableAxis binsVtxZ{"dcaFitterEMSel.binsVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis binsMultiplicity{"dcaFitterEMSel.binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - multiplicity"}; + Configurable maxDeltaRadiusColMixing{"dcaFitterEMSel.maxDeltaRadiusColMixing", 2., "max difference between pv z position in case of collision mixing"}; + Configurable maxDeltaPhiColMixing{"dcaFitterEMSel.maxDeltaPhiColMixing", 30., "max difference between Phi of monther particle in case of collision mixing (degree)"}; + // Configurations for mixing decay3bodys + // Configurable cfgUseDCAFitterInfo{"dcaFitterEMSel.cfgUseDCAFitterInfo", true, ""}; // if use information from dcatFitter while mixing reduced 3bodys + Configurable cfgMix3BodyMethod{"dcaFitterEMSel.cfgMix3BodyMethod", 0, ""}; // 0: bachelor, 1: pion, 2: proton + Configurable cfgApplyV0Cut{"dcaFitterEMSel.cfgApplyV0Cut", true, "if apply V0 cut while performing event-mixing"}; + ConfigurableAxis bins3BodyRadius{"dcaFitterEMSel.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 2.0f, 4.0f, 7.0f, 10.0f, 14.0f, 18.0f, 22.0f, 30.0f, 40.0f}, "Mixing bins - 3body radius"}; + ConfigurableAxis bins3BodyPhi{"dcaFitterEMSel.bins3BodyPhi", {VARIABLE_WIDTH, -3.15, -2.15, -1, 0, 1, 2.15, 3.15}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPhiDegree{"dcaFitterEMSel.bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPosZ{"dcaFitterEMSel.bins3BodyPosZ", {VARIABLE_WIDTH, -500.0f, -200.0f, -100.0f, -70.0f, -60.0f, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -20.0f, -15.0f, -13.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f, 13.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f, 60.0f, 70.0f, 100.0f, 200.0f, 500.0f}, "3body SV z position"}; + Configurable selectPVPosZ3bodyMixing{"dcaFitterEMSel.selectPVPosZ3bodyMixing", true, "Select same pvPosZ events in case of 3body mixing"}; + Configurable maxDeltaPVPosZ3bodyMixing{"dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing", 1., "max difference between pv z position in case of 3body mixing"}; + } dcaFitterEMSel; + + SliceCache cache; + using BinningTypeColEM = ColumnBinningPolicy; + using Binning3BodyDCAFitter = ColumnBinningPolicy; + using Binning3BodyKFInfo = ColumnBinningPolicy; + + // KF event mixing + using BinningTypeKF = ColumnBinningPolicy; + + // 3body mixing + using Binning3Body = ColumnBinningPolicy; + + // Filters and slices + Preslice perCollision = o2::aod::decay3body::collisionId; + Preslice perReducedCollision = o2::aod::reduceddecay3body::collisionId; + + int mRunNumber; + float d_bz; + + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda + bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc + o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; + + + // ========================== + + + + + + void init(InitContext&) + { + zorroSummary.setObject(zorro.getZorroSummary()); + + mRunNumber = 0; + d_bz = 0; + + mEnabledTables.resize(nTables, 0); + + // CCDB options + ccdb->setURL(ccdbConfigurations.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // Set material correction + if (useMatCorrType == 1) { + LOGF(info, "TGeo correction requested, loading geometry"); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(ccdbConfigurations.geoPath); + } + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; + } + if (useMatCorrType == 2) { + LOGF(info, "LUT correction requested, loading LUT"); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbConfigurations.lutPath)); + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + } + + fitterV0.setMatCorrType(matCorr); + fitter3body.setMatCorrType(matCorr); + + // set bachelor PID + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + + // set decay3body parameters in the helper + helper.decay3bodyselections.maxEtaDaughters = decay3bodyBuilderOpts.maxEtaDaughters; + helper.decay3bodyselections.minTPCNClProton = decay3bodyBuilderOpts.minTPCNClProton; + helper.decay3bodyselections.minTPCNClPion = decay3bodyBuilderOpts.minTPCNClPion; + helper.decay3bodyselections.minTPCNClBach = decay3bodyBuilderOpts.minTPCNClBach; + helper.decay3bodyselections.minDCAProtonToPV = decay3bodyBuilderOpts.minDCAProtonToPV; + helper.decay3bodyselections.minDCAPionToPV = decay3bodyBuilderOpts.minDCAPionToPV; + helper.decay3bodyselections.minDCABachToPV = decay3bodyBuilderOpts.minDCABachToPV; + helper.decay3bodyselections.minPtProton = decay3bodyBuilderOpts.minPtProton; + helper.decay3bodyselections.minPtPion = decay3bodyBuilderOpts.minPtPion; + helper.decay3bodyselections.minPtBach = decay3bodyBuilderOpts.minPtBach; + helper.decay3bodyselections.maxPtProton = decay3bodyBuilderOpts.maxPtProton; + helper.decay3bodyselections.maxPtPion = decay3bodyBuilderOpts.maxPtPion; + helper.decay3bodyselections.maxPtBach = decay3bodyBuilderOpts.maxPtBach; + helper.decay3bodyselections.maxTPCnSigma = decay3bodyBuilderOpts.maxTPCnSigma; + helper.decay3bodyselections.minTOFnSigmaDeuteron = decay3bodyBuilderOpts.minTOFnSigmaDeuteron; + helper.decay3bodyselections.maxTOFnSigmaDeuteron = decay3bodyBuilderOpts.maxTOFnSigmaDeuteron; + helper.decay3bodyselections.minPBachUseTOF = decay3bodyBuilderOpts.minPBachUseTOF; + helper.decay3bodyselections.maxDCADauAtSV = decay3bodyBuilderOpts.maxDCADauAtSV; + helper.decay3bodylelections.maxRapidity = decay3bodyBuilderOpts.maxRapidity; + helper.decay3bodyselections.minPt = decay3bodyBuilderOpts.minPt; + helper.decay3bodyselections.maxPt = decay3bodyBuilderOpts.maxPt; + helper.decay3bodyselections.minMass = decay3bodyBuilderOpts.minMass; + helper.decay3bodyselections.maxMass = decay3bodyBuilderOpts.maxMass; + helper.decay3bodyselections.minCtau = decay3bodyBuilderOpts.minCtau; + helper.decay3bodyselections.maxCtau = decay3bodyBuilderOpts.maxCtau; + helper.decay3bodyselections.minCosPA = decay3bodyBuilderOpts.minCosPA; + helper.decay3bodyselections.maxChi2 = decay3bodyBuilderOpts.maxChi2; + + // set SVertexer selection parameters in the helper + helper.svselections.minPt2V0 = eventMixingOpts.minPt2V0; + helper.svselections.maxTgl2V0 = eventMixingOpts.maxTgl2V0; + helper.svselections.maxDCAXY2ToMeanVertex3bodyV0 = eventMixingOpts.maxDCAXY2ToMeanVertex3bodyV0; + helper.svselections.minCosPAXYMeanVertex3bodyV0 = eventMixingOpts.minCosPAXYMeanVertex3bodyV0; + helper.svselections.minCosPA3bodyV0 = eventMixingOpts.minCosPA3bodyV0; + helper.svselections.maxRDiffV03body = eventMixingOpts.maxRDiffV03body; + helper.svselections.minPt3Body = eventMixingOpts.minPt3Body; + helper.svselections.maxTgl3Body = eventMixingOpts.maxTgl3Body; + helper.svselections.maxDCAXY3Body = eventMixingOpts.maxDCAXY3Body; + helper.svselections.maxDCAZ3Body = eventMixingOpts.maxDCAZ3Body; + + // configure tables to generate + // setup bookkeeping histograms + auto h = registry.add("hTableBuildingStatistics", "hTableBuildingStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + auto h2 = registry.add("hInputStatistics", "hInputStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + h2->SetTitle("Input table sizes"); + + for (int i = 0; i < nTables; i++) { + h->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); + h->SetBinContent(i + 1, -1); // mark all as disabled to start + + int f = enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + mEnabledTables[i] = 1; + h->SetBinContent(i + 1, 0); // mark enabled + } + } + + // list enabled process functions + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, " Decay3body builder: basic configuration listing"); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + if (doprocessRealData) { + LOGF(info, " ===> process function enabled: processRealData"); + } + if (doprocessRealDataReduced) { + LOGF(info, " ===> process function enabled: processRealData"); + } + if (doprocessMonteCarlo) { + LOGF(info, " ===> process function enabled: processMonteCarlo"); + } + if (doprocessEventMixing) { + LOGF(info, " ===> process function enabled: processEventMixing"); + } + + // list enabled tables + for (int i = 0; i < nTables; i++) { + // printout to be improved in the future + if (mEnabledTables[i]) { + LOGF(info, " -~> Table enabled: %s", tableNames[i]); + } + } + // print base cuts + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, "-~> max daughter eta ..............: %i", decay3bodyBuilderOpts.maxEtaDaughters.value); + LOGF(info, "-~> min TPC ncls proton ...........: %i", decay3bodyBuilderOpts.minTPCNClProton.value); + LOGF(info, "-~> min TPC ncls pion .............: %i", decay3bodyBuilderOpts.minTPCNClPion.value); + LOGF(info, "-~> min TPC ncls bach .............: %i", decay3bodyBuilderOpts.minTPCNClBach.value); + LOGF(info, "-~> min DCA proton to PV ..........: %f", decay3bodyBuilderOpts.minDCAProtonToPV.value); + LOGF(info, "-~> min DCA pion to PV ............: %f", decay3bodyBuilderOpts.minDCAPionToPV.value); + LOGF(info, "-~> min DCA bach to PV ............: %f", decay3bodyBuilderOpts.minDCABachToPV.value); + LOGF(info, "-~> min pT proton .................: %f", decay3bodyBuilderOpts.minPtProton.value); + LOGF(info, "-~> min pT pion ...................: %f", decay3bodyBuilderOpts.minPtPion.value); + LOGF(info, "-~> min pT bach ...................: %f", decay3bodyBuilderOpts.minPtBach.value); + LOGF(info, "-~> max pT proton .................: %f", decay3bodyBuilderOpts.maxPtProton.value); + LOGF(info, "-~> max pT pion ...................: %f", decay3bodyBuilderOpts.maxPtPion.value); + LOGF(info, "-~> max pT bach ...................: %f", decay3bodyBuilderOpts.maxPtBach.value); + LOGF(info, "-~> max TPC nSigma ...............: %f", decay3bodyBuilderOpts.maxTPCnSigma.value); + LOGF(info, "-~> min TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.minTOFnSigmaDeuteron.value); + LOGF(info, "-~> max TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.maxTOFnSigmaDeuteron.value); + LOGF(info, "-~> min p bach use TOF ...........: %f", decay3bodyBuilderOpts.minPBachUseTOF.value); + LOGF(info, "-~> max DCA dau at SV ............: %f", decay3bodyBuilderOpts.maxDCADauAtSV.value); + LOGF(info, "-~> max rapidity .................: %f", decay3bodyBuilderOpts.maxRapidity.value); + LOGF(info, "-~> min pT .......................: %f", decay3bodyBuilderOpts.minPt.value); + LOGF(info, "-~> max pT .......................: %f", decay3bodyBuilderOpts.maxPt.value); + LOGF(info, "-~> min mass .....................: %f", decay3bodyBuilderOpts.minMass.value); + LOGF(info, "-~> max mass .....................: %f", decay3bodyBuilderOpts.maxMass.value); + LOGF(info, "-~> min ctau .....................: %f", decay3bodyBuilderOpts.minCtau.value); + LOGF(info, "-~> max ctau .....................: %f", decay3bodyBuilderOpts.maxCtau.value); + LOGF(info, "-~> min cosPA ....................: %f", decay3bodyBuilderOpts.minCosPA.value); + LOGF(info, "-~> max chi2 .....................: %f", decay3bodyBuilderOpts.maxChi2.value); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + // Add histograms separately for different process functions + if (doprocessRealData == true || doprocessRealDataReduced == true) { + registry.add("hEventCounter", "Counters/hEventCounter", HistType::kTH1F, {{1, 0.0f, 1.0f}}); + } + + if (doTrackQA) { + registry.add("QA/Tracks/hTrackPosTPCNcls", "hTrackPosTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackNegTPCNcls", "hTrackNegTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackBachTPCNcls", "hTrackBachTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackPosHasTPC", "hTrackPosHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackNegHasTPC", "hTrackNegHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackBachHasTPC", "hTrackBachHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackProtonTPCPID", "hTrackProtonTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackPionTPCPID", "hTrackPionTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackBachTPCPID", "hTrackBachTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackProtonPt", "hTrackProtonPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + registry.add("QA/Tracks/hTrackPionPt", "hTrackPionPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + registry.add("QA/Tracks/hTrackBachPt", "hTrackBachPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + } + if (doEventQA) { + registry.add("QA/Event/hAllSelEventsVtxZ", "hAllSelEventsVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + registry.add("QA/Event/hVtxX", "hVtxX", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV X (cm)"}}); + registry.add("QA/Event/hVtxY", "hVtxY", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV Y (cm)"}}); + registry.add("QA/Event/hVtxZ", "hVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + registry.add("QA/Event/hVtxCovXX", "hVtxCovXX", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XX) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYY", "hVtxCovYY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovZZ", "hVtxCovZZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(ZZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXY", "hVtxCovXY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXZ", "hVtxCovXZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYZ", "hVtxCovYZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); + } + + // if (doprocessRun3 == true || doprocessRun3Reduced || doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { + // auto hVtx3BodyCounter = registry.add("hVtx3BodyCounter", "hVtx3BodyCounter", HistType::kTH1D, {{6, 0.0f, 6.0f}}); + // hVtx3BodyCounter->GetXaxis()->SetBinLabel(1, "Total"); + // hVtx3BodyCounter->GetXaxis()->SetBinLabel(2, "TPCNcls"); + // hVtx3BodyCounter->GetXaxis()->SetBinLabel(3, "PIDCut"); + // hVtx3BodyCounter->GetXaxis()->SetBinLabel(4, "HasSV"); + // hVtx3BodyCounter->GetXaxis()->SetBinLabel(5, "DcaDau"); + // hVtx3BodyCounter->GetXaxis()->SetBinLabel(6, "CosPA"); + // registry.add("hBachelorTOFNSigmaDe", "", HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}); + // } + + // if (doprocessRun3ReducedEM == true) { + // registry.add("hEventCount", "hEventCount", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + // registry.add("hEventPairs", "hEventPairs", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + // registry.add("hDecay3BodyPairsBeforeCut", "hDecay3BodyPairsBeforeCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + // registry.add("hDecay3BodyPairsAfterCut", "hDecay3BodyPairsAfterCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + // registry.add("hRadius0", "hRadius0", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + // registry.add("hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + // registry.add("hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{400, -20.0f, 20.0f, "#Delta Radius (cm)"}}); + // registry.add("hPhi0", "hPhi0", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); + // registry.add("hPhi1", "hPhi1", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); + // registry.add("hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, -180.0f, 180.0f, "#Delta #phi (degree)"}}); + // } + + // if (doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { + // registry.add("hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}); + // registry.add("hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {dcaFitterEMSel.bins3BodyPosZ}); + // auto h3bodyCombinationCounter = registry.add("h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "bach sign/ID"); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "not same collision"); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "collision VtxZ"); + // } + + // if (doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { + // doUpdateGRPMagField = true; + // registry.add("h3bodyEMCutCounter", "h3bodyEMCutCounter", HistType::kTH1D, {{14, 0.0f, 14.0f}}); + // } + + // if (doprocessRun3withKFParticle == true || doprocessRun3withKFParticleStrangenessTracking == true || doprocessRun3withKFParticleReduced == true || doprocessRun3withKFParticleReducedEM == true || doprocessRun3withKFParticleReduced3bodyMixing == true) { + // auto hEventCounterZorro = registry.add("Counters/hEventCounterZorro", "hEventCounterZorro", HistType::kTH1D, {{2, -0.5, 1.5}}); + // hEventCounterZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); + // hEventCounterZorro->GetXaxis()->SetBinLabel(2, "Zorro after evsel"); + // auto hEventCounterKFParticle = registry.add("Counters/hEventCounterKFParticle", "hEventCounterKFParticle", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + // hEventCounterKFParticle->GetXaxis()->SetBinLabel(1, "total"); + // hEventCounterKFParticle->GetXaxis()->SetBinLabel(2, "sel8"); + // hEventCounterKFParticle->GetXaxis()->SetBinLabel(3, "vertexZ"); + // hEventCounterKFParticle->GetXaxis()->SetBinLabel(4, "has candidate"); + // hEventCounterKFParticle->LabelsOption("v"); + // auto hVtx3BodyCounterKFParticle = registry.add("Counters/hVtx3BodyCounterKFParticle", "hVtx3BodyCounterKFParticle", HistType::kTH1D, {{21, 0.0f, 21.0f}}); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(1, "Total"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(2, "Charge"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(3, "Eta"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(4, "TPCNcls"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(5, "TPCRows"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(6, "TPCpid"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(7, "DCAxyPV"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(8, "DCAzPV"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(9, "V0MassConst"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(10, "HasSV"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(11, "DcaDau"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(12, "DCADauVtx"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(13, "DauPt"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(14, "Rapidity"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(15, "Pt"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(16, "Mass"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(17, "CosPA"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(18, "CosPAXY"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(19, "Chi2geo"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(20, "TopoConstr"); + // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(21, "Chi2topo"); + // hVtx3BodyCounterKFParticle->LabelsOption("v"); + // } + + // if (doprocessRun3withKFParticleReducedEM == true) { + // registry.add("QA/EM/hPairCounterMixing", "hPairCounterMixing", HistType::kTH1D, {{1, 0.0f, 1.0f}}); + // auto hCombinationCounterMixing = registry.add("QA/EM/hCombinationCounterMixing", "hCombinationCounterMixing", HistType::kTH1D, {{3, 0.0f, 3.0f}}); + // hCombinationCounterMixing->GetXaxis()->SetBinLabel(1, "total"); + // hCombinationCounterMixing->GetXaxis()->SetBinLabel(2, "bach sign/ID"); + // hCombinationCounterMixing->GetXaxis()->SetBinLabel(3, "radius, phi"); + // hCombinationCounterMixing->LabelsOption("v"); + + // registry.add("QA/EM/hEventBinCounts", "hEventBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); + // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); + // registry.add("QA/EM/hPairBinCounts", "hPairBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); + + // registry.add("QA/EM/hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + // registry.add("QA/EM/hRadius2", "hRadius2", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + // registry.add("QA/EM/hPhi1", "hPhi1", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); + // registry.add("QA/EM/hPhi2", "hPhi2", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); + // registry.add("QA/EM/hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{200, 0.0f, 10.0f, "#Delta Radius (cm)"}}); + // registry.add("QA/EM/hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, 0.0f, 360.0f, "#Delta #phi (degree)"}}); + // } + + // if (doprocessRun3withKFParticleReduced3bodyMixing == true) { + // auto h3bodyCombinationCounter = registry.add("QA/EM/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "not same collision"); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "collision VtxZ"); + // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "bach sign/ID"); + // h3bodyCombinationCounter->LabelsOption("v"); + // // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH3D, {{16, 0, 16, "bins radius"}, {36, 0, 36, "bins phi"}, {12, 0, 12, "bins pos Z"}}); + // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{16, 0, 16, "bins radius"}, {18, 0, 18, "bins phi"}}); + + // AxisSpec radiusAxis = {kfparticleConfigurations.bins3BodyRadius, "Radius (cm)"}; + // AxisSpec phiAxis = {kfparticleConfigurations.bins3BodyPhi, "#phi (degree)"}; + // AxisSpec posZAxis = {kfparticleConfigurations.bins3BodyPosZ, "position in z (cm)"}; + + // registry.add("QA/EM/hRadius", "hRadius", HistType::kTH1F, {radiusAxis}); + // registry.add("QA/EM/hPhi", "hPhi", HistType::kTH1F, {phiAxis}); + // registry.add("QA/EM/hPosZ", "hPosZ", HistType::kTH1F, {posZAxis}); + // } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + if (doSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + + auto timestamp = bc.timestamp(); + o2::parameters::GRPMagField* grpmag = 0x0; + grpmag = ccdb->getForTimeStamp(ccdbConfigurations.grpmagPath, timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + auto d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << magneticField << " kG"; + + // set magnetic field value for DCA fitter + fitterV0.setBz(d_bz); + fitter3body.setBz(d_bz); +// Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(d_bz); +#endif + + if (useMatCorrType == 2) { + // setMatLUT only after magfield has been initalized + // (setMatLUT has implicit and problematic init field call if not) + LOG(info) << "Loading material look-up table for timestamp: " << timestamp; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); + o2::base::Propagator::Instance()->setMatLUT(lut); + helper.lut = lut; + } + + // mark run as configured + mRunNumber = bc.runNumber(); + + // Initial TOF PID Paras, copied from PIDTOF.h + tofPIDOpts.timestamp.value = bc.timestamp(); + ccdb->setTimestamp(tofPIDOpts.timestamp.value); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // TODO: implement the automatic pass name detection from metadata + if (tofPIDOpts.passName.value == "") { + tofPIDOpts.passName.value = "unanchored"; // temporary default + LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << tofPIDOpts.passName.value << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << tofPIDOpts.passName.value << "'"; + + const std::string fname = tofPIDOpts.paramFileName.value; + if (!fname.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << tofPIDOpts.parametrizationPath.value; + if (1) { + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(fname, tofPIDOpts.parametrizationPath.value); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV2, tofPIDOpts.passName.value)) { + if (tofPIDOpts.fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); + } + } else { + mRespParamsV2.setShiftParameters(paramCollection.getPars(tofPIDOpts.passName.value)); + mRespParamsV2.printShiftParameters(); + } + } else { + mRespParamsV2.loadParamFromFile(fname.data(), tofPIDOpts.parametrizationPath.value); + } + } else if (tofPIDOpts.loadResponseFromCCDB) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << tofPIDOpts.parametrizationPath.value << " for timestamp " << timestamp.value; + o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(tofPIDOpts.parametrizationPath.value, timestamp.value); + paramCollection->print(); + if (!paramCollection->retrieveParameters(mRespParamsV2, tofPIDOpts.passName.value)) { // Attempt at loading the parameters with the pass defined + if (tofPIDOpts.fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); + } + } else { // Pass is available, load non standard parameters + mRespParamsV2.setShiftParameters(paramCollection->getPars(tofPIDOpts.passName.value)); + mRespParamsV2.printShiftParameters(); + } + } + mRespParamsV2.print(); + if (tofPIDOpts.timeShiftCCDBPath.value != "") { + if (tofPIDOpts.timeShiftCCDBPath.value.find(".root") != std::string::npos) { + mRespParamsV2.setTimeShiftParameters(tofPIDOpts.timeShiftCCDBPath.value, "gmean_Pos", true); + mRespParamsV2.setTimeShiftParameters(tofPIDOpts.timeShiftCCDBPath.value, "gmean_Neg", false); + } else { + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", tofPIDOpts.timeShiftCCDBPath.value.c_str()), tofPIDOpts.timestamp.value), true); + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", tofPIDOpts.timeShiftCCDBPath.value.c_str()), tofPIDOpts.timestamp.value), false); + } + } + + bachelorTOFPID.SetParams(mRespParamsV2); + } + + void initCCDBfromRunNumber(int runNumber) + { + // set magnetic field only when run number changes + if (mRunNumber == runNumber) { + LOG(debug) << "CCDB initialized for run " << mRunNumber; + return; + } + mRunNumber = runNumber; // Update the last run number + + // Check if the CCDB data for this run is already cached + if (ccdbCache.find(runNumber) != ccdbCache.end()) { + LOG(debug) << "CCDB data already cached for run " << runNumber; + d_bz = ccdbCache[runNumber]; + if (doUpdateGRPMagField == true) { + o2::base::Propagator::initFieldFromGRP(grpMagCache[runNumber].get()); + } + } else { + std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(ccdbConfigurations.grpmagPath, runNumber)); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.grpPath << " of object GRPObject for run number " << runNumber; + } + o2::base::Propagator::initFieldFromGRP(grpmag.get()); + // Fetch magnetic field from ccdb for current collision + d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for run number " << runNumber << " with magnetic field of " << d_bz << " kZG"; + + ccdbCache[runNumber] = d_bz; + grpMagCache[runNumber] = grpmag; + } + + // Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(d_bz); +#endif + // Set field for DCAfitter + fitterV0.setBz(d_bz); + fitter3body.setBz(d_bz); + + mV0Hyps[0].set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, d_bz); + mV0Hyps[1].set(o2::track::PID::Lambda, o2::track::PID::Pion, o2::track::PID::Proton, pidCutsLambda, d_bz); + + if (useMatCorrType == 2) { + // setMatLUT only after magfield has been initalized + o2::base::Propagator::Instance()->setMatLUT(lut); + } + + // cache magnetic field info + ccdbCache[runNumber] = d_bz; + } + + + + + //------------------------------------------------------------------ + // event mixing + template + void doMixed3Body(TMixed3bodys decay3bodys, TBinningType binningType) + { + // Strictly upper index policy for decay3body objects binned by radius, phi + for (const auto& [decay3body0, decay3body1] : selfCombinations(binningType, dcaFitterEMSel.nUseMixed, -1, decay3bodys, decay3bodys)) { + auto tpos0 = decay3body0.template track0_as(); + auto tneg0 = decay3body0.template track1_as(); + auto tbach0 = decay3body0.template track2_as(); + auto tpos1 = decay3body1.template track0_as(); + auto tneg1 = decay3body1.template track1_as(); + auto tbach1 = decay3body1.template track2_as(); + + registry.fill(HIST("h3bodyCombinationCounter"), 0.5); + + // ---------- selections ---------- + if ((tbach0.sign() > 0 && !(tbach1.sign() > 0)) || (tbach0.sign() < 0 && !(tbach1.sign() < 0)) || tbach0.globalIndex() == tbach1.globalIndex()) { // only combine if tbach1 has correct sign and is not same as tbach0 + continue; + } + registry.fill(HIST("h3bodyCombinationCounter"), 1.5); + + if (decay3body0.collisionId() == decay3body1.collisionId()) { // only combine if from different event + continue; + } + registry.fill(HIST("h3bodyCombinationCounter"), 2.5); + + auto c0 = decay3body0.template collision_as(); + auto c1 = decay3body1.template collision_as(); + + if (dcaFitterEMSel.selectPVPosZ3bodyMixing && std::abs(c0.posZ() - c1.posZ()) > dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing) { // only combine if collision similar in PV posZ + continue; + } + registry.fill(HIST("h3bodyCombinationCounter"), 3.5); + + initCCDBfromRunNumber(c0.runNumber()); + + if (dcaFitterEMSel.cfgMix3BodyMethod == 0) { // mix bachelor (deuteron) + fillVtxCand(c0, tpos0, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); + fillVtxCand(c1, tpos1, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); + } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() > 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() < 0)) { // mix piMinus or proton + fillVtxCand(c0, tpos0, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); + fillVtxCand(c1, tpos1, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); + } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() < 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() > 0)) { // mix piPlus or anti-proton + fillVtxCand(c0, tpos1, tneg0, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); + fillVtxCand(c1, tpos0, tneg1, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); + } + + VtxCandidates.clear(); + } // end decay3body combinations loop + } + //------------------------------------------------------------------ + // fill the StoredVtx3BodyDatas table + void fillVtx3BodyTable(VtxCandidate const& candVtx) + { + vtx3bodydata( + candVtx.track0Id, candVtx.track1Id, candVtx.track2Id, candVtx.collisionId, candVtx.decay3bodyId, + candVtx.vtxPos[0], candVtx.vtxPos[1], candVtx.vtxPos[2], + candVtx.track0P[0], candVtx.track0P[1], candVtx.track0P[2], candVtx.track1P[0], candVtx.track1P[1], candVtx.track1P[2], candVtx.track2P[0], candVtx.track2P[1], candVtx.track2P[2], + candVtx.dcadaughters, + candVtx.daudcaxytopv[0], candVtx.daudcaxytopv[1], candVtx.daudcaxytopv[2], + candVtx.daudcatopv[0], candVtx.daudcatopv[1], candVtx.daudcatopv[2], + candVtx.bachelortofNsigma); + } + + //------------------------------------------------------------------ + //-------------------- KFParticle reconstruction ------------------- + //------------------------------------------------------------------ + + template + double getTOFnSigma(TCollision const& collision, TTrack const& track, bool isEventMixing) + { + // TOF PID of deuteron (set motherhyp correctly) + double tofNSigmaDeuteron = -999; + if (track.has_collision() && track.hasTOF()) { + if (isEventMixing) { + tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, collision, collision); + } else { + auto originalcol = track.template collision_as(); + tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); + } + } + return tofNSigmaDeuteron; + } + + + // ______________________________________________________________ + // function to build decay3body candidates + template + void buildDecay3Bodies(TCollision const& collisions, T3Bodies const& decay3bodies, TTrack const& tracks) + { + if (!mEnabledTables[kStoredDecay3BodyCores]) { + return; // don't do if no request for decay3bodies in place + } + + int nDecay3Bodies = 0; + // Loop over all decay3bodies in same time frame + resgistry.fill(HIST("hInputStatistics"), kStoredDecay3BodyCores, decay3bodies.size()); + for (size_t i3body = 0; i3body < decay3bodies.size(); i3body++) { + // Get tracks and generate candidate + auto const& decay3body = decay3bodies[sorted_decay3body[i3body]]; /// TODO: FIX!! + // if collisionId positive: get vertex, negative: origin + float pvX = 0.0f, pvY = 0.0f, pvZ = 0.0f; + if (decay3body.collisionId >= 0) { + auto const& collision = collisions.rawIteratorAt(decay3body.collisionID); + pvX = collision.posX(); + pvY = collision.posY(); + pvZ = collision.posZ(); + } + + // Aquire tracks + auto const& trackPos = tracks.rawIteratorAt(decay3body.trackPosID); + auto const& trackNeg = tracks.rawIteratorAt(decay3body.trackNegID); + auto const& trackBach = tracks.rawIteratorAt(decay3body.traclBachID); + + // Calculate TOD nSigma + /// TODO: Calculate TOD nSigma + + // generate analysis tables + if (mEnabledTables[kDecay3BodyIndices]) { + products.decay3bodyindices(decay3body.) + registry.fill(HIST("hTableBuildingStatistics"), kDecay3BodyIndices); + } + if (mEnabledTables[kStoredDecay3BodyCores]) { + products.decay3bodycores(); + registry.fill(HIST("hTableBuildingStatistics"), kStoredDecay3BodyCores); + } + if (mEnabledTables[kDecay3BodyCovs]) { + products.decay3bodycovs(); + registry.fill(HIST("hTableBuildingStatistics"), kDecay3BodyCovs); + } + + /// TODO: + // ___________________________________________________________ + // MC handling part + // prepare MC containers (not necessarily used) + std::vector mcCascinfos; // Decay3bodyMCCore information + std::vector mcParticleIsReco; + + if constexpr (soa::is_table) { + // do this if provided with a mcParticle table as well + mcParticleIsReco.resize(mcParticles.size(), false); + + if ((mEnabledTables[kMcDEcay3BodyCores] || mEnabledTables[kMcDEcay3BodyLabels] || mEnabledTables[kMcDecay3BodyCollRefs])) { + extractMonteCarloProperties(); + + // generate label table (joinable with Decay3BodyCores) + if (mEnabledTables[kMcDecay3BodyLabels]) { + products.mcDecay3bodylabels(); + registry.fill(HIST("hTableBuildingStatistics"), kMcDecay3BodyLabels); + } + + // mark mcParticle as reconstructed + if (thisDecay3bodyInfo.label > -1) { + mcParticleIsReco[thisDecay3bodyInfo.label] = true; + } + + // generate MC cores table (joinable with Decay3BodyCores) + if (mEnabledTables[kMcDecay3BodyCores]) { + products.mcDecay3bodycores(); + registry.fill(HIST("hTableBuildingStatistics"), kMcDecay3BodyCores); + } + if (mEnabledTables[kMcDecay3BodyCollRefs]) { + products.mcDecay3bodycollrefs(thisDecay3bodyInfo.mcCollision); + registry.fill(HIST("hTableBuildingStatistics"), kMcDecay3BodyCollRefs); + } + } // enabled tables check + } // constexpr requires mcParticles check + } // decay3body loop + + /// TODO: + // ____________________________________________________________ + // MC handling part + if constexpr (soa::is_table) { + if ((mEnabledTables[kMcDEcay3BodyCores] || mEnabledTables[kMcDEcay3BodyLabels] || mEnabledTables[kMcDecay3BodyCollRefs])) { + + } // enabled tables check + } // constexpr requires mcParticles check + } + + // ______________________________________________________________ + // function to get MC properties + template + void extractMonteCarloProperties(TTrack const& trackPos, TTrack const& trackNeg, TTrack const& trackBach, TMMParticles const& mcParticles) + { + // encapsulates acquisition of MC properties from MC + thisDecay3bodyInfo.pdgCode = -1, thisDecay3bodyInfo.pdgCodeMother = -1; + thisDecay3bodyInfo.pdgCodePositive = -1, thisDecay3bodyInfo.pdgCodeNegative = -1; + thisDecay3bodyInfo.pdgCodeBachelor = -1, thisDecay3bodyInfo.pdgCodeV0 = -1; + thisDecay3bodyInfo.isPhysicalPrimary = false; + thisDecay3bodyInfo.xyz[0] = -999.0f, thisDecay3bodyInfo.xyz[1] = -999.0f, thisDecay3bodyInfo.xyz[2] = -999.0f; + thisDecay3bodyInfo.lxyz[0] = -999.0f, thisDecay3bodyInfo.lxyz[1] = -999.0f, thisDecay3bodyInfo.lxyz[2] = -999.0f; + thisDecay3bodyInfo.posP[0] = -999.0f, thisDecay3bodyInfo.posP[1] = -999.0f, thisDecay3bodyInfo.posP[2] = -999.0f; + thisDecay3bodyInfo.negP[0] = -999.0f, thisDecay3bodyInfo.negP[1] = -999.0f, thisDecay3bodyInfo.negP[2] = -999.0f; + thisDecay3bodyInfo.bachP[0] = -999.0f, thisDecay3bodyInfo.bachP[1] = -999.0f, thisDecay3bodyInfo.bachP[2] = -999.0f; + thisDecay3bodyInfo.momentum[0] = -999.0f, thisDecay3bodyInfo.momentum[1] = -999.0f, thisDecay3bodyInfo.momentum[2] = -999.0f; + thisDecay3bodyInfo.label = -1, thisDecay3bodyInfo.motherLabel = -1; + thisDecay3bodyInfo.mcParticlePositive = -1; + thisDecay3bodyInfo.mcParticleNegative = -1; + thisDecay3bodyInfo.mcParticleBachelor = -1; + + // association check + if (trackPos.has_mcParticle() && trackNeg.has_mcParticle() && trackBach.has_mcParticle()) { + auto lMCBachTrack = trackPos.template mcParticle_as(); + auto lMCNegTrack = trackNeg.template mcParticle_as(); + auto lMCPosTrack = trackBach.template mcParticle_as(); + + thisDecay3bodyInfo.mcParticlePositive = lMCPosTrack.globalIndex(); + thisDecay3bodyInfo.mcParticleNegative = lMCNegTrack.globalIndex(); + thisDecay3bodyInfo.mcParticleBachelor = lMCBachTrack.globalIndex(); + thisDecay3bodyInfo.pdgCodePositive = lMCPosTrack.pdgCode(); + thisDecay3bodyInfo.pdgCodeNegative = lMCNegTrack.pdgCode(); + thisDecay3bodyInfo.pdgCodeBachelor = lMCBachTrack.pdgCode(); + thisDecay3bodyInfo.posP[0] = lMCPosTrack.px(); + thisDecay3bodyInfo.posP[1] = lMCPosTrack.py(); + thisDecay3bodyInfo.posP[2] = lMCPosTrack.pz(); + thisDecay3bodyInfo.negP[0] = lMCNegTrack.px(); + thisDecay3bodyInfo.negP[1] = lMCNegTrack.py(); + thisDecay3bodyInfo.negP[2] = lMCNegTrack.pz(); + thisDecay3bodyInfo.bachP[0] = lMCBachTrack.px(); + thisDecay3bodyInfo.bachP[1] = lMCBachTrack.py(); + thisDecay3bodyInfo.bachP[2] = lMCBachTrack.pz(); + } + + // treat pi -> mu + antineutrino decays + + + } + + //------------------------------------------------------------------ + // 3body candidate builder with KFParticle + template + void buildVtx3BodyDataTableKFParticle(TCollision const& collision, TTrack const& trackPos, TTrack const& trackNeg, TTrack const& trackBach, int64_t decay3bodyID, int bachelorcharge, double tofNSigmaDeuteron) + { + gROOT->SetBatch(true); + gRandom->SetSeed(42); + + // initialise KF primary vertex + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle kfpv(kfpVertex); + LOG(debug) << "Created KF PV."; + + // fill event QA histograms --> only for events with a decay3body! + if (kfparticleConfigurations.doVertexQA) { + registry.fill(HIST("QA/Event/hVtxXKF"), kfpv.GetX()); + registry.fill(HIST("QA/Event/hVtxYKF"), kfpv.GetY()); + registry.fill(HIST("QA/Event/hVtxZKF"), kfpv.GetZ()); + registry.fill(HIST("QA/Event/hVtxCovXXKF"), kfpv.GetCovariance(0)); + registry.fill(HIST("QA/Event/hVtxCovYYKF"), kfpv.GetCovariance(2)); + registry.fill(HIST("QA/Event/hVtxCovZZKF"), kfpv.GetCovariance(5)); + registry.fill(HIST("QA/Event/hVtxCovXYKF"), kfpv.GetCovariance(1)); + registry.fill(HIST("QA/Event/hVtxCovXZKF"), kfpv.GetCovariance(3)); + registry.fill(HIST("QA/Event/hVtxCovYZKF"), kfpv.GetCovariance(4)); + registry.fill(HIST("QA/Event/hVtxX"), collision.posX()); + registry.fill(HIST("QA/Event/hVtxY"), collision.posY()); + registry.fill(HIST("QA/Event/hVtxZ"), collision.posZ()); + registry.fill(HIST("QA/Event/hVtxCovXX"), collision.covXX()); + registry.fill(HIST("QA/Event/hVtxCovYY"), collision.covYY()); + registry.fill(HIST("QA/Event/hVtxCovZZ"), collision.covZZ()); + registry.fill(HIST("QA/Event/hVtxCovXY"), collision.covXY()); + registry.fill(HIST("QA/Event/hVtxCovXZ"), collision.covXZ()); + registry.fill(HIST("QA/Event/hVtxCovYZ"), collision.covYZ()); + } + + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxAll); + + auto trackParCovPos = getTrackParCov(trackPos); + auto trackParCovNeg = getTrackParCov(trackNeg); + auto trackParCovBach = getTrackParCov(trackBach); + LOG(debug) << "Got all daughter tracks."; + + bool isMatter = trackBach.sign() > 0 ? true : false; + + // ---------- fill track QA histograms ---------- + if (kfparticleConfigurations.doTrackQA) { + registry.fill(HIST("QA/Tracks/hTrackPosTPCNcls"), trackPos.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackNegTPCNcls"), trackNeg.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackBachTPCNcls"), trackBach.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackPosHasTPC"), trackPos.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackNegHasTPC"), trackNeg.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackBachHasTPC"), trackBach.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackBachITSClusSizes"), trackBach.itsClusterSizes()); + if (isMatter) { + registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPr()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPi()); + registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackPos.pt()); + registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackNeg.pt()); + } else { + registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPr()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPi()); + registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackNeg.pt()); + registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackPos.pt()); + } + registry.fill(HIST("QA/Tracks/hTrackBachTPCPID"), trackBach.sign() * trackBach.tpcInnerParam(), trackBach.tpcNSigmaDe()); + registry.fill(HIST("QA/Tracks/hTrackBachPt"), trackBach.pt()); + } + + // -------- STEP 1: track selection -------- + // collision ID --> not correct? tracks can have different collisions, but belong to one 3prong vertex! + // if (trackPos.collisionId() != trackNeg.collisionId() || trackPos.collisionId() != trackBach.collisionId() || trackNeg.collisionId() != trackBach.collisionId()) { + // continue; + // } + // track IDs --> already checked in SVertexer! + + // track signs (pos, neg, bach) --> sanity check, should already be in SVertexer + if (trackPos.sign() != +1 || trackNeg.sign() != -1) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCharge); + + // track eta + if (std::abs(trackPos.eta()) > kfparticleConfigurations.maxEta || std::abs(trackNeg.eta()) > kfparticleConfigurations.maxEta || std::abs(trackBach.eta()) > kfparticleConfigurations.maxEtaDeuteron) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxEta); + + // number of TPC clusters + if (trackBach.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsBach) { + return; + } + if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { + return; + } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCNcls); + + // number of TPC crossed rows + if (trackBach.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows) { + return; + } + if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { + return; + } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCRows); + + // TPC PID + float tpcNsigmaProton; + float tpcNsigmaPion; + float dEdxProton; + float dEdxPion; + float tpcNsigmaDeuteron = trackBach.tpcNSigmaDe(); + float tpcNsigmaPionBach = trackBach.tpcNSigmaPi(); + float dEdxDeuteron = trackBach.tpcSignal(); + if (isMatter) { // hypertriton (proton, pi-, deuteron) + tpcNsigmaProton = trackPos.tpcNSigmaPr(); + tpcNsigmaPion = trackNeg.tpcNSigmaPi(); + dEdxProton = trackPos.tpcSignal(); + dEdxPion = trackNeg.tpcSignal(); + if (!selectTPCPID(trackPos, trackNeg, trackBach)) { + return; + } + } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) + tpcNsigmaProton = trackNeg.tpcNSigmaPr(); + tpcNsigmaPion = trackPos.tpcNSigmaPi(); + dEdxProton = trackNeg.tpcSignal(); + dEdxPion = trackPos.tpcSignal(); + if (!selectTPCPID(trackNeg, trackPos, trackBach)) { + return; + } + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCPID); + LOG(debug) << "Basic track selections done."; + + // Average ITS cluster size of deuteron track + double averageClusterSizeDeuteron(0); + int nCls(0); + for (int i = 0; i < 7; i++) { + int clusterSize = trackBach.itsClsSizeInLayer(i); + averageClusterSizeDeuteron += static_cast(clusterSize); + if (clusterSize > 0) + nCls++; + } + averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nCls); + + // track DCAxy and DCAz to PV associated with decay3body + o2::dataformats::VertexBase mPV; + o2::dataformats::DCA mDcaInfoCovPos; + o2::dataformats::DCA mDcaInfoCovNeg; + o2::dataformats::DCA mDcaInfoCovBach; + auto trackParCovPVPos = trackParCovPos; + auto trackParCovPVNeg = trackParCovNeg; + auto trackParCovPVBach = trackParCovBach; + mPV.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVPos, 2.f, matCorr, &mDcaInfoCovPos); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVNeg, 2.f, matCorr, &mDcaInfoCovNeg); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVBach, 2.f, matCorr, &mDcaInfoCovBach); + auto TrackPosDcaXY = mDcaInfoCovPos.getY(); + auto TrackNegDcaXY = mDcaInfoCovNeg.getY(); + auto TrackBachDcaXY = mDcaInfoCovBach.getY(); + auto TrackPosDcaZ = mDcaInfoCovPos.getZ(); + auto TrackNegDcaZ = mDcaInfoCovNeg.getZ(); + auto TrackBachDcaZ = mDcaInfoCovBach.getZ(); + // calculate 3D track DCA + auto TrackPosDca = std::sqrt(TrackPosDcaXY * TrackPosDcaXY + TrackPosDcaZ * TrackPosDcaZ); + auto TrackNegDca = std::sqrt(TrackNegDcaXY * TrackNegDcaXY + TrackNegDcaZ * TrackNegDcaZ); + auto TrackBachDca = std::sqrt(TrackBachDcaXY * TrackBachDcaXY + TrackBachDcaZ * TrackBachDcaZ); + // selection + if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { + return; + } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAxyPV); + if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { + return; + } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAzPV); + + // daughter track momentum at inner wall of TPC + float tpcInnerParamProton; + float tpcInnerParamPion; + float tpcInnerParamDeuteron = trackBach.tpcInnerParam(); + if (isMatter) { // hypertriton (proton, pi-, deuteron) + tpcInnerParamProton = trackPos.tpcInnerParam(); + tpcInnerParamPion = trackNeg.tpcInnerParam(); + } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) + tpcInnerParamProton = trackNeg.tpcInnerParam(); + tpcInnerParamPion = trackPos.tpcInnerParam(); + } + + // -------- STEP 2: fit vertex with proton and pion -------- + // Fit vertex with DCA fitter to find minimization point --> uses material corrections implicitly + if (kfparticleConfigurations.doDCAFitterPreMinimum) { + try { + fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); + } catch (std::runtime_error& e) { + LOG(error) << "Exception caught in DCA fitter process call: Not able to fit decay3body vertex!"; + return; + } + // re-acquire tracks at vertex position from DCA fitter + trackParCovPos = fitter3body.getTrack(0); + trackParCovNeg = fitter3body.getTrack(1); + trackParCovBach = fitter3body.getTrack(2); + + LOG(debug) << "Minimum found with DCA fitter for decay3body."; + } + + // create KFParticle objects from tracks + KFParticle kfpProton, kfpPion; + if (isMatter) { + kfpProton = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassPionCharged); + } else if (!isMatter) { + kfpProton = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassPionCharged); + } + LOG(debug) << "KFParticle objects created from daughter tracks."; + + // Construct V0 as intermediate step + KFParticle KFV0; + int nDaughtersV0 = 2; + const KFParticle* DaughtersV0[2] = {&kfpProton, &kfpPion}; + KFV0.SetConstructMethod(2); + try { + KFV0.Construct(DaughtersV0, nDaughtersV0); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create V0 vertex from daughter tracks." << e.what(); + return; + } + KFV0.TransportToDecayVertex(); + LOG(debug) << "V0 constructed."; + + // check V0 mass and set mass constraint + float massV0, sigmaMassV0; + KFV0.GetMass(massV0, sigmaMassV0); + KFParticle KFV0Mass = KFV0; + KFV0Mass.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); + float chi2massV0 = KFV0Mass.GetChi2() / KFV0Mass.GetNDF(); + if (kfparticleConfigurations.useLambdaMassConstraint) { + LOG(debug) << "V0 mass constraint applied."; + KFV0 = KFV0Mass; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxV0MassConst); + + // apply virtual V0 cuts used in SVertexer in case of 3body mixing with proton track + if (kfparticleConfigurations.mixingType == 1 && kfparticleConfigurations.applySVertexerV0Cuts) { + // V0 radius + if (std::sqrt(KFV0.GetX() * KFV0.GetX() + KFV0.GetY() * KFV0.GetY()) <= 0.5) { + return; + } + // pT + if (KFV0.GetPt() <= 0.01) { + return; + } + // pz/pT + if (KFV0.GetPz() / KFV0.GetPt() >= 2) { + return; + } + // cos(PA) + if (cpaXYFromKF(KFV0, kfpv) <= 0.9 || cpaFromKF(KFV0, kfpv) <= 0.8) { + return; + } + } + + // -------- STEP 3: fit three body vertex -------- + // Create KFParticle object from deuteron track + KFParticle kfpDeuteron; + kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, trackBach.sign() * bachelorcharge, constants::physics::MassDeuteron); + LOG(debug) << "KFParticle created from deuteron track."; + + // Construct vertex + KFParticle KFHt; + fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt); + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxhasSV); + + // -------- STEP 4: daughter selections after geometrical vertex fit -------- + // daughter DCAs with KF + if ((kfpProton.GetDistanceFromParticle(kfpPion) >= kfparticleConfigurations.maxDcaProPi) || (kfpProton.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaProDeu) || (kfpPion.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaPiDe)) { + return; + } + float DCAvtxDaughters3D = kfpProton.GetDistanceFromParticle(kfpPion) + kfpProton.GetDistanceFromParticle(kfpDeuteron) + kfpPion.GetDistanceFromParticle(kfpDeuteron); + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDau); + LOG(debug) << "DCA selection after vertex fit applied."; + + // daughter DCAs to vertex + if (kfpProton.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpPion.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpDeuteron.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDauVtx); + LOG(debug) << "DCA to vertex selection after vertex fit applied."; + + // daughter pT + if (kfpProton.GetPt() < kfparticleConfigurations.minPtProton || kfpProton.GetPt() > kfparticleConfigurations.maxPtProton || kfpPion.GetPt() < kfparticleConfigurations.minPtPion || kfpPion.GetPt() > kfparticleConfigurations.maxPtPion || kfpDeuteron.GetPt() < kfparticleConfigurations.minPtDeuteron || kfpDeuteron.GetPt() > kfparticleConfigurations.maxPtDeuteron) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDauPt); + LOG(debug) << "Daughter pT selection applied."; + + // -------- STEP 5: candidate selection and constraint after geometrical vertex fit -------- + // Rapidity + float rapHt = RecoDecay::y(std::array{KFHt.GetPx(), KFHt.GetPy(), KFHt.GetPz()}, o2::constants::physics::MassHyperTriton); + if (std::abs(rapHt) > kfparticleConfigurations.maxRapidityHt) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxRap); + + // Pt selection + if (KFHt.GetPt() <= kfparticleConfigurations.minPtHt || KFHt.GetPt() >= kfparticleConfigurations.maxPtHt) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxPt); + + // Mass window + float massHt, sigmaMassHt; + KFHt.GetMass(massHt, sigmaMassHt); + if (massHt <= kfparticleConfigurations.minMassHt || massHt >= kfparticleConfigurations.maxMassHt) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxMass); + + // cos(PA) to PV + if (std::abs(cpaFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPA) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPA); + + // cos(PA) xy to PV + if (std::abs(cpaXYFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPAxy) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPAXY); + + // chi2 geometrical + float chi2geoNDF = KFHt.GetChi2() / KFHt.GetNDF(); + if (kfparticleConfigurations.applyTopoSel && chi2geoNDF >= kfparticleConfigurations.maxChi2geo) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2geo); + LOG(debug) << "Basic selections after vertex fit done."; + + // ctau before topo constraint + if (KFHt.GetLifeTime() > kfparticleConfigurations.maxctauHt) { + return; + } + + // Set vertex constraint and topological selection + KFParticle KFHtPV = KFHt; + try { + KFHtPV.SetProductionVertex(kfpv); + } catch (std::runtime_error& e) { + LOG(error) << "Exception caught KFParticle process call: Topological constraint failed"; + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTopoConstr); // to check if topo constraint fails + // get topological chi2 + float chi2topoNDF = KFHtPV.GetChi2() / KFHtPV.GetNDF(); + KFHtPV.TransportToDecayVertex(); + if (kfparticleConfigurations.applyTopoSel && chi2topoNDF >= kfparticleConfigurations.maxChi2topo) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2topo); + + // -------- STEP 6: collect and fill candidate info -------- + // get cluster size of strangeness tracked 3bodies + float trackedClSize; + if (decay3bodyID == -1) { + trackedClSize = 0; + } else { + trackedClSize = !fTrackedClSizeVector.empty() ? fTrackedClSizeVector[decay3bodyID] : 0; + } + + + + //------------------------------------------------------------------ + // table filling + fillCandidateTable(candidate); + LOG(debug) << "Table filled."; + + // fill event counter hist (has selected candidate) --> only filled once per vertex + registry.fill(HIST("Counters/hEventCounterKFParticle"), 3.5); + } // end buildVtx3BodyDataTableKFParticle + + //------------------------------------------------------------------ + void processRun3(ColwithEvTimes const& collisions, aod::Decay3Bodys const& decay3bodys, TrackExtPIDIUwithEvTimes const&, aod::BCsWithTimestamps const&) + { + VtxCandidates.clear(); + + registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); + + for (const auto& d3body : decay3bodys) { + auto t0 = d3body.track0_as(); + auto t1 = d3body.track1_as(); + auto t2 = d3body.track2_as(); + auto collision = d3body.collision_as(); + auto bc = collision.bc_as(); + initCCDB(bc); + + // Recalculate the TOF PID + double tofNSigmaBach = -999; + if (t2.has_collision() && t2.hasTOF()) { + auto originalcol = t2.template collision_as(); + tofNSigmaBach = bachelorTOFPID.GetTOFNSigma(t2, originalcol, collision); + } + + fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, tofNSigmaBach); + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3, "Produce DCA fitter decay3body tables", true); + + //------------------------------------------------------------------ + void processRun3Reduced(aod::RedCollisions const& collisions, aod::RedDecay3Bodys const& decay3bodys, aod::RedIUTracks const&) + { + VtxCandidates.clear(); + + registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); + + for (const auto& d3body : decay3bodys) { + auto t0 = d3body.track0_as(); + auto t1 = d3body.track1_as(); + auto t2 = d3body.track2_as(); + auto collision = d3body.collision_as(); + + initCCDBfromRunNumber(collision.runNumber()); + fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, t2.tofNSigmaDe()); + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced, "Produce DCA fitter decay3body tables with reduced data", false); + + + void processRun3Reduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) + { + VtxCandidates.clear(); + + auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); + auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); + + for (const auto& decay3body : decay3bodys) { + int bin_Radius = xAxis->FindBin(decay3body.svRadius()); + int bin_Phi = yAxis->FindBin(decay3body.momPhi()); + registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); + registry.fill(HIST("hDecay3BodyPosZ"), decay3body.svPosZ()); + } + + Binning3BodyDCAFitter binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhiDegree}, true}; + doMixed3Body(decay3bodys, binningOnRadiusPhi); + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixing, "Produce mixing background directly from mixed decay3bodys based on DCAFitter Info", false); + + void processRun3Reduced3bodyMixingKFInfo(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) + { + VtxCandidates.clear(); + + auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); + auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); + + for (const auto& decay3body : decay3bodys) { + int bin_Radius = xAxis->FindBin(decay3body.radius()); + int bin_Phi = yAxis->FindBin(decay3body.phi()); + registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); + registry.fill(HIST("hDecay3BodyPosZ"), decay3body.posz()); + } + + Binning3BodyKFInfo binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}, true}; + doMixed3Body(decay3bodys, binningOnRadiusPhi); + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixingKFInfo, "Produce mixing background directly from mixed decay3bodys based on KF Info", false); + + //------------------------------------------------------------------ + void processRun3withKFParticle(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + + auto bc = collision.bc_as(); + initCCDB(bc); + LOG(debug) << "CCDB initialised."; + + // Zorro event counting + bool isZorroSelected = false; + if (kfparticleConfigurations.cfgSkimmedProcessing) { + isZorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); + if (isZorroSelected) { + registry.fill(HIST("Counters/hEventCounterZorro"), 0.); + } else { + if (kfparticleConfigurations.cfgOnlyKeepInterestedTrigger) { + continue; + } + } + } + + // event selection + registry.fill(HIST("Counters/hEventCounterKFParticle"), 0.5); + if (kfparticleConfigurations.doSel8selection && !collision.sel8()) { + continue; + } + registry.fill(HIST("Counters/hEventCounterKFParticle"), 1.5); + if (kfparticleConfigurations.doPosZselection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; + } + registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); + registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); + + if (isZorroSelected) { + registry.fill(HIST("Counters/hEventCounterZorro"), 1.); + } + + // slice Decay3Body table by collision + const uint64_t collIdx = collision.globalIndex(); + auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perCollision, collIdx); + for (auto& vtx3body : Decay3BodyTable_thisCollision) { + auto trackPos = vtx3body.template track0_as(); + auto trackNeg = vtx3body.template track1_as(); + auto trackBach = vtx3body.template track2_as(); + buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, getTOFnSigma(collision, trackBach, false /*isEventMixing*/)); + LOG(debug) << "End of processKFParticle."; + } + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticle, "Produce KFParticle decay3body tables", false); + + void processRun3withKFParticleStrangenessTracking(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const& tracks, aod::Decay3Bodys const& decay3bodys, aod::Tracked3Bodys const& tracked3bodys, aod::BCsWithTimestamps const& bcs) + { + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); + } + processRun3withKFParticle(collisions, tracks, decay3bodys, bcs); + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleStrangenessTracking, "Produce KFParticle strangeness tracked decay3body tables", false); + + void processRun3withKFParticleReduced(aod::RedCollisions const& collisions, aod::RedIUTracks const&, aod::RedDecay3Bodys const& decay3bodys) + { + int lastRunNumber = -1; + + for (const auto& collision : collisions) { + // set magnetic field only when run number changes + if (collision.runNumber() != lastRunNumber) { + initCCDBfromRunNumber(collision.runNumber()); + lastRunNumber = collision.runNumber(); // Update the last run number + LOG(debug) << "CCDB initialized for run " << lastRunNumber; + } + + // event selection + registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); + registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); + + // slice Decay3Body table by collision + const uint64_t collIdx = collision.globalIndex(); + auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perReducedCollision, collIdx); + for (auto& vtx3body : Decay3BodyTable_thisCollision) { + auto trackPos = vtx3body.template track0_as(); + auto trackNeg = vtx3body.template track1_as(); + auto trackBach = vtx3body.template track2_as(); + buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, trackBach.tofNSigmaDe()); + } + LOG(debug) << "End of processKFParticleDerived."; + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced, "Produce KFParticle decay3body tables from derived decay3body data", false); + + void processRun3withKFParticleReduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) + { + // Define a 2D array to count 3bodies per bin (radius, phi, posZ) + std::vector> bin3bodyCounts(16, std::vector(36, 0)); + + // Function to find bin index (returns -1 if out of range) + auto findBin = [](float value, const std::vector& binEdges) -> int { + for (size_t i = 0; i < binEdges.size() - 1; ++i) { + if (value > binEdges[i] && value <= binEdges[i + 1]) { + return i; + } + } + return -1; // Out of range + }; + + int counter = 0; + // Loop over all collisions to count them in bins + for (auto& decay3body : decay3bodys) { + counter++; + float radius = decay3body.radius(); + float phi = decay3body.phi(); + float posZ = decay3body.posz(); + + registry.fill(HIST("QA/EM/hRadius"), radius); + registry.fill(HIST("QA/EM/hPhi"), phi); + registry.fill(HIST("QA/EM/hPosZ"), posZ); + + // float degToRad = TMath::Pi()/180; + + // Determine bin indices + int radiusBin = findBin(radius, {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}); + int phiBin = findBin(phi, {-180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}); + if (radiusBin >= 0 && phiBin >= 0) { // && posZBin >= 0) { + bin3bodyCounts[radiusBin][phiBin]++; //[posZBin]++; + } + } + LOG(info) << "3body counter: " << counter; + + // Print out the number of 3-body decays per bin + LOG(info) << "3body count per bin (radius, phi, posZ):"; + for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { + for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { + LOG(info) << "Bin (" << i << ", " << j << "): " << bin3bodyCounts[i][j] << " 3bodies"; + } + } + // Fill 3D histogram with numbers per bin + for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { + for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { + registry.fill(HIST("QA/EM/h3bodyBinCounts"), i, j, bin3bodyCounts[i][j]); + } + } + LOG(info) << "Integral of h3bodyBinCounts: " << registry.get(HIST("QA/EM/h3bodyBinCounts"))->Integral(); + + Binning3Body binningOnRadPhi{{kfparticleConfigurations.bins3BodyRadius, kfparticleConfigurations.bins3BodyPhi}, true}; + + // Strictly upper index policy for decay3body objects binned by radius, phi and z position + for (auto& [decay3body1, decay3body2] : selfPairCombinations(binningOnRadPhi, kfparticleConfigurations.nEvtMixing, -1, decay3bodys)) { + auto trackPos1 = decay3body1.template track0_as(); + auto trackNeg1 = decay3body1.template track1_as(); + auto trackBach1 = decay3body1.template track2_as(); + auto trackPos2 = decay3body2.template track0_as(); + auto trackNeg2 = decay3body2.template track1_as(); + auto trackBach2 = decay3body2.template track2_as(); + + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 0.5); + + // collision vertex selections + auto collision1 = decay3body1.template collision_as(); + auto collision2 = decay3body2.template collision_as(); + initCCDBfromRunNumber(collision2.runNumber()); + initCCDBfromRunNumber(collision1.runNumber()); + + if (decay3body1.collisionId() == decay3body2.collisionId()) { // only combine if from different event + continue; + } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 1.5); + if (kfparticleConfigurations.selectVtxZ3bodyMixing && std::abs(collision1.posZ() - collision2.posZ()) > kfparticleConfigurations.VtxZBin3bodyMixing) { // only combine if collision similar in VtxZ + continue; + } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 2.5); + + // ---------- selections ---------- + if ((trackBach1.sign() > 0 && !(trackBach2.sign() > 0)) || (trackBach1.sign() < 0 && !(trackBach2.sign() < 0)) || trackBach1.globalIndex() == trackBach2.globalIndex()) { // only combine if trackBach2 has correct sign and is not same as trackBach1 + continue; + } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); + + // ---------- do candidate analysis ---------- + bool isMatter1 = false; + if (trackBach1.sign() > 0) { + isMatter1 = true; + } + if (kfparticleConfigurations.mixingType == 0) { // mix deuteron + buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); + buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); + } else if (kfparticleConfigurations.mixingType == 1) { // mix proton + if (isMatter1 == true) { + buildVtx3BodyDataTableKFParticle(collision1, trackPos2, trackNeg1, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); + buildVtx3BodyDataTableKFParticle(collision2, trackPos1, trackNeg2, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); + } else if (isMatter1 == false) { + buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); + buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); + } + } + } // end decay3body combinations loop + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced3bodyMixing, "Produce KFParticle mixed decay3body tables from derived decay3body data", false); +}; + + + + + +// build link from decay3body -> vtx3body +struct decay3bodyDataLinkBuilder { + Produces VtxDataLink; + + void init(InitContext const&) {} + + template + void buildDecay3BodyLabel(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) + { + std::vector lIndices; + lIndices.reserve(decay3bodytable.size()); + for (int ii = 0; ii < decay3bodytable.size(); ii++) + lIndices[ii] = -1; + for (const auto& vtxdata : vtxdatatable) { + if (vtxdata.decay3bodyId() != -1) { + lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); + } + } + for (int ii = 0; ii < decay3bodytable.size(); ii++) { + VtxDataLink(lIndices[ii]); + } + } + + void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) + { + buildDecay3BodyLabel(decay3bodytable, vtxdatatable); + } + PROCESS_SWITCH(decay3bodyDataLinkBuilder, processStandard, "Produce label from decay3body to vtx3body", true); + + void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) + { + buildDecay3BodyLabel(decay3bodytable, vtxdatatable); + } + PROCESS_SWITCH(decay3bodyDataLinkBuilder, processReduced, "Produce label from reducedDecay3body to vtx3body", false); +}; + +struct kfdecay3bodyDataLinkBuilder { + Produces kfvtxdataLink; + + void init(InitContext const&) {} + + template + void buildDataLink(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) + { + std::vector lIndices; + lIndices.reserve(decay3bodytable.size()); + for (int ii = 0; ii < decay3bodytable.size(); ii++) + lIndices[ii] = -1; + for (auto& vtxdata : vtxdatatable) { + if (vtxdata.decay3bodyId() != -1) { + lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); + } + } + for (int ii = 0; ii < decay3bodytable.size(); ii++) { + kfvtxdataLink(lIndices[ii]); + } + } + + void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) + { + buildDataLink(decay3bodytable, vtxdatatable); // build Decay3Body -> KFDecay3BodyData link table + } + PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processStandard, "Build data link table.", true); + + void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) + { + buildDataLink(decay3bodytable, vtxdatatable); // build ReducedDecay3Body -> KFDecay3BodyData link table + } + PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processReduced, "Build data link table for reduced data.", false); +}; + +struct decay3bodyLabelBuilder { + + Produces vtxlabels; + Produces vtxfulllabels; + + HistogramRegistry registry{"registry", {}}; + + void init(InitContext const&) + { + if (doprocessDoNotBuildLabels == false) { + auto hLabelCounter = registry.add("hLabelCounter", "hLabelCounter", HistType::kTH1D, {{3, 0.0f, 3.0f}}); + hLabelCounter->GetXaxis()->SetBinLabel(1, "Total"); + hLabelCounter->GetXaxis()->SetBinLabel(2, "Have Same MotherTrack"); + hLabelCounter->GetXaxis()->SetBinLabel(3, "True H3L"); + + registry.add("hHypertritonMCPt", "hHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); + registry.add("hAntiHypertritonMCPt", "hAntiHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); + registry.add("hHypertritonMCMass", "hHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); + registry.add("hAntiHypertritonMCMass", "hAntiHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); + registry.add("hHypertritonMCLifetime", "hHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); + registry.add("hAntiHypertritonMCLifetime", "hAntiHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); + } + } + + Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; + + void processDoNotBuildLabels(aod::Decay3BodyDataLink const&) // is it possible to have none parameter? + { + // dummy process function - should not be required in the future + }; + PROCESS_SWITCH(decay3bodyLabelBuilder, processDoNotBuildLabels, "Do not produce MC label tables", true); + + void processBuildLabels(aod::Decay3BodysLinked const& decay3bodys, aod::Vtx3BodyDatas const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const&) + { + std::vector lIndices; + lIndices.reserve(vtx3bodydatas.size()); + for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { + lIndices[ii] = -1; + } + + for (const auto& decay3body : decay3bodys) { + + int lLabel = -1; + int lPDG = -1; + float lPt = -1; + double MClifetime = -1; + bool is3bodyDecay = false; + int lGlobalIndex = -1; + + auto lTrack0 = decay3body.track0_as(); + auto lTrack1 = decay3body.track1_as(); + auto lTrack2 = decay3body.track2_as(); + registry.fill(HIST("hLabelCounter"), 0.5); + + // Association check + // There might be smarter ways of doing this in the future + if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { + vtxfulllabels(-1); + continue; + } + auto lMCTrack0 = lTrack0.mcParticle_as(); + auto lMCTrack1 = lTrack1.mcParticle_as(); + auto lMCTrack2 = lTrack2.mcParticle_as(); + if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { + vtxfulllabels(-1); + continue; + } + + for (const auto& lMother0 : lMCTrack0.mothers_as()) { + for (const auto& lMother1 : lMCTrack1.mothers_as()) { + for (const auto& lMother2 : lMCTrack2.mothers_as()) { + if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { + lGlobalIndex = lMother1.globalIndex(); + lPt = lMother1.pt(); + lPDG = lMother1.pdgCode(); + MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); // only for hypertriton + is3bodyDecay = true; // vtxs with the same mother + } + } + } + } // end association check + if (!is3bodyDecay) { + vtxfulllabels(-1); + continue; + } + registry.fill(HIST("hLabelCounter"), 1.5); + + // Intended for hypertriton cross-checks only + if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { + lLabel = lGlobalIndex; + double hypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + registry.fill(HIST("hLabelCounter"), 2.5); + registry.fill(HIST("hHypertritonMCPt"), lPt); + registry.fill(HIST("hHypertritonMCLifetime"), MClifetime); + registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); + } + if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { + lLabel = lGlobalIndex; + double antiHypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); + registry.fill(HIST("hLabelCounter"), 2.5); + registry.fill(HIST("hAntiHypertritonMCPt"), lPt); + registry.fill(HIST("hAntiHypertritonMCLifetime"), MClifetime); + registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); + } + + // Construct label table, only vtx which corresponds to true mother and true daughters with a specified order is labeled + // for matter: track0->p, track1->pi, track2->bachelor + // for antimatter: track0->pi, track1->p, track2->bachelor + vtxfulllabels(lLabel); + if (decay3body.vtx3BodyDataId() != -1) { + lIndices[decay3body.vtx3BodyDataId()] = lLabel; + } + } + for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { + vtxlabels(lIndices[ii]); + } + } + PROCESS_SWITCH(decay3bodyLabelBuilder, processBuildLabels, "Produce MC label tables", false); +}; + +struct decay3bodyInitializer { + Spawns vtx3bodydatas; + void init(InitContext const&) {} +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/Utils/decay3bodyBuilderHelper.h b/PWGLF/Utils/decay3bodyBuilderHelper.h index 7c409f96f67..225b01b1088 100644 --- a/PWGLF/Utils/decay3bodyBuilderHelper.h +++ b/PWGLF/Utils/decay3bodyBuilderHelper.h @@ -88,19 +88,23 @@ struct decay3bodyCandidate { class Decay3BodyBuilderHelper { public: - strangenessBuilderHelper() + decay3bodyBuilderHelper() { - // standards hardcoded in builder ... - // ...but can be changed easily since fitter is public fitter3body.setPropagateToPCA(true); - fitter3body.setMaxR(200.); + fitter3body.setMaxR(200.); //->maxRIni3body fitter3body.setMinParamChange(1e-3); fitter3body.setMinRelChi2Change(0.9); fitter3body.setMaxDZIni(1e9); fitter3body.setMaxDXYIni(4.0f); fitter3body.setMaxChi2(1e9); - fitter3body.setUseAbsDCA(true); - fitter3body.setWeightedFinalPCA(false); + + fitterV0.setPropagateToPCA(true); + fitterV0.setMaxR(200.); + fitterV0.setMinParamChange(1e-3); + fitterV0.setMinRelChi2Change(0.9); + fitterV0.setMaxDZIni(1e9); + fitterV0.setMaxChi2(1e9); + fitterV0.setUseAbsDCA(d_UseAbsDCA); // LUT has to be loaded later lut = nullptr; @@ -110,12 +114,15 @@ class Decay3BodyBuilderHelper fitter3body.setBz(-999.9f); // will NOT make sense if not changed }; - o2::base::MatLayerCylSet* lut; // material LUT for DCA fitter + o2::base::MatLayerCylSet* lut = nullptr; // material LUT for DCA fitter o2::vertexing::DCAFitterN<2> fitterV0; // 2-prong o2 dca fitter o2::vertexing::DCAFitterN<3> fitter3body; // 3-prong o2 dca fitter decay3bodyCandidate decay3body; // storage for Decay3body candidate properties + o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; + std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda + // decay3body candidate criteria struct { // daughter tracks @@ -149,6 +156,20 @@ class Decay3BodyBuilderHelper float maxChi2; } decay3bodyselections; + // SVertexer selection criteria + struct { + float minPt2V0; + float maxTgl2V0; + float maxDCAXY2ToMeanVertex3bodyV0; + float minCosPAXYMeanVertex3bodyV0; + float minCosPA3bodyV0; + float maxRDiffV03body; + float minPt3Body; + float maxTgl3Body; + float maxDCAXY3Body; + float maxDCAZ3Body; + } svertexerselections; + //_______________________________________________________________________ // build Decay3body from three tracks, including V0 building. template @@ -157,7 +178,7 @@ class Decay3BodyBuilderHelper TTrack const& trackNeg, TTrack const& trackBach, int decay3bodyIndex, - float todNsigmaDeuteron, + float tofNsigmaDeuteron, float trackedClSize, int bachelorcharge = 1, bool useKFParticle = false, @@ -165,7 +186,8 @@ class Decay3BodyBuilderHelper bool useSelections = true, bool useTPCforPion = false, bool acceptTPCOnly = false, - bool calculateCovariance = true) + bool calculateCovariance = true, + bool isEventMixing = false) { int collisionIndex = collision.globalIndex(); float pvX = collision.posX(); @@ -285,7 +307,7 @@ class Decay3BodyBuilderHelper mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); // positive track - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPosCopy, 2.f, matCorr, &mDcaInfoCov); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPosCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); decay3body.trackDCAxyToPV[0] = mDcaInfoCov.getY(); decay3body.trackDCAzToPV[0] = mDcaInfoCov.getZ(); auto trackPosDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[0] * decay3body.trackDCAxyToPV[0] + decay3body.trackDCAzToPV[0] * decay3body.trackDCAzToPV[0]); @@ -299,7 +321,7 @@ class Decay3BodyBuilderHelper } } // negative track - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParNegPosCopy, 2.f, matCorr, &mDcaInfoCov); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParNegPosCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); decay3body.trackDCAxyToPV[1] = mDcaInfoCov.getY(); decay3body.trackDCAzToPV[1] = mDcaInfoCov.getZ(); auto trackNegDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[1] * decay3body.trackDCAxyToPV[1] + decay3body.trackDCAzToPV[1] * decay3body.trackDCAzToPV[1]); @@ -313,7 +335,7 @@ class Decay3BodyBuilderHelper } } // bachelor track - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovBachCopy, 2.f, matCorr, &mDcaInfoCov); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovBachCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); decay3body.trackDCAxyToPV[2] = mDcaInfoCov.getY(); decay3body.trackDCAzToPV[2] = mDcaInfoCov.getZ(); auto trackBachDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[2] * decay3body.trackDCAxyToPV[2] + decay3body.trackDCAzToPV[2] * decay3body.trackDCAzToPV[2]); @@ -442,6 +464,12 @@ class Decay3BodyBuilderHelper } } + //_______________________________________________________________________ + // SVertexer selections in case of event mixing + if (isEventMixing) { + applySVertexerCuts(collision, trackParCovPos, trackParCovNeg, trackParCovBach, /*applyV0Cut = */true); + } + //_______________________________________________________________________ // fill remaining candidate information // daughter PID @@ -455,7 +483,7 @@ class Decay3BodyBuilderHelper decay3body.tpcNsigma[2] = trackBach.tpcNsigmaDeuteron(); decay3body.tpcNsigma[3] = trackBach.tpcNsigmaPi(); // recalculated bachelor TOF PID - decay3body.tofNsigmaDeuteron = todNsigmaDeuteron; + decay3body.tofNsigmaDeuteron = tofNsigmaDeuteron; // average ITS cluster size of deuteron track double averageClusterSizeDeuteron(0); @@ -704,6 +732,135 @@ class Decay3BodyBuilderHelper return; } + //_______________________________________________________________________ + // functionality to apply SVertexer cuts in case of event mixing + template + void applySVertexerCuts(TCollisions const& collision, + TTrackParCov const& trackParCovPos, + TTrackParCov const& trackParCovNeg, + TTrackParCov const& trackParCovBach, + bool applyV0Cut = true) + { + const float pidCutsLambda[o2::vertexing::SVertexHypothesis::NPIDParams] = {0., 20, 0., 5.0, 0.0, 1.09004e-03, 2.62291e-04, 8.93179e-03, 2.83121}; // Lambda + mV0Hyps[0].set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, fitter3body.getBz()); + mV0Hyps[1].set(o2::track::PID::Lambda, o2::track::PID::Pion, o2::track::PID::Proton, pidCutsLambda, fitter3body.getBz()); + + int nV0 = fitterV0.process(trackParCovPos, trackParCovNeg); + if (nV0 == 0) { + return; + } + + std::array v0pos = {0.}; + const auto& v0vtxXYZ = fitterV0.getPCACandidate(); + for (int i = 0; i < 3; i++) { + v0pos[i] = v0vtxXYZ[i]; + } + const int cand = 0; + if (!fitterV0.isPropagateTracksToVertexDone(cand) && !fitterV0.propagateTracksToVertex(cand)) { + return; + } + + const auto& trPProp = fitterV0.getTrack(0, cand); + const auto& trNProp = fitterV0.getTrack(1, cand); + std::array pP{}, pN{}; + trPProp.getPxPyPzGlo(pP); + trNProp.getPxPyPzGlo(pN); + std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; + // Cut for Virtual V0 + float dxv0 = v0pos[0] - mMeanVertex.getX(), dyv0 = v0pos[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; + float rv0 = std::sqrt(r2v0); + float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; + if (applyV0Cut && pt2V0 <= svertexerselections.mMinPt2V0) { + return; + } + if (applyV0Cut && pV0[2] * pV0[2] / pt2V0 > svertexerselections.maxTgl2V0) { // tgLambda cut + return; + } + + float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); + // apply mass selections + 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]; + bool good3bodyV0Hyp = false; + for (int ipid = 0; ipid < 2; ipid++) { + float massForLambdaHyp = mV0Hyps[ipid].calcMass(p2Pos, p2Neg, p2V0); + if (massForLambdaHyp - mV0Hyps[ipid].getMassV0Hyp() < mV0Hyps[ipid].getMargin(ptV0)) { + good3bodyV0Hyp = true; + break; + } + } + if (applyV0Cut && !good3bodyV0Hyp) { + return; + } + + float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; + float cosPAXY = prodXYv0 / rv0 * ptV0; + if (applyV0Cut && dca2 > svertexerselections.maxDCAXY2ToMeanVertex3bodyV0) { + return; + } + // FIXME: V0 cosPA cut to be investigated + if (applyV0Cut && cosPAXY < svertexerselections.minCosPAXYMeanVertex3bodyV0) { + return; + } + // Check: CosPA Cut of Virtual V0 may not be used since the V0 may be based on another PV + float dx = v0pos[0] - collision.posX(), dy = v0pos[1] - collision.posY(), dz = v0pos[2] - collision.posZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; + float v0CosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); + if (applyV0Cut && v0CosPA < svertexerselections.minCosPA3bodyV0) { + return; + } + + // 3body vertex + int n3bodyVtx = fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); + if (n3bodyVtx == 0) { // discard this pair + return; + } + const auto& vertexXYZ = fitter3body.getPCACandidatePos(); + std::array pos = {0.}; + for (int i = 0; i < 3; i++) { + pos[i] = vertexXYZ[i]; + } + + std::array p0 = {0.}, p1 = {0.}, p2{0.}; + const auto& propagatedTrackPos = fitter3body.getTrack(0); + const auto& propagatedTrackNeg = fitter3body.getTrack(1); + const auto& propagatedTrackBach = fitter3body.getTrack(2); + propagatedTrackPos.getPxPyPzGlo(p0); + propagatedTrackNeg.getPxPyPzGlo(p1); + propagatedTrackBach.getPxPyPzGlo(p2); + for (int i = 0; i < 3; i++) { + p2[i] *= bachelorcharge; + } + std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; + + float r3body = std::hypot(pos[0], pos[1]); + if (r3body < 0.5) { + return; + } + + // Cut for the compatibility of V0 and 3body vertex + float deltaR = std::abs(rv0 - r3body); + if (deltaR > svertexerselections.maxRDiffV03body) { + return; + } + + float pt3B = std::hypot(p3B[0], p3B[1]); + if (pt3B < svertexerselections.minPt3Body) { // pt cut + return; + } + if (p3B[2] / pt3B > svertexerselections.maxTgl3Body) { // tgLambda cut + return; + } + + // H3L DCA Check + const auto& vertexXYZ = fitter3body.getPCACandidatePos(); + auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, t2.sign()); + o2::dataformats::DCA dca; + if (!track3B.propagateToDCA({{collision.posX(), collision.posY(), collision.posZ()}, {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}}, fitter3body.getBz(), &dca, 5.) || + std::abs(dca.getY()) > svertexerselections.maxDCAXY3Body || std::abs(dca.getZ()) > svertexerselections.maxDCAZ3Body) { + return; + } + + return; + } private: // internal helper to calculate DCA (3D) of a straight line to a given PV analytically float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) From 628308d2fd436fad39931fd9cf1768d9ea71813c Mon Sep 17 00:00:00 2001 From: creetz16 Date: Wed, 21 May 2025 17:26:09 +0200 Subject: [PATCH 3/7] Update decay3bodybuilder and data model --- PWGLF/DataModel/Reduced3BodyTables.h | 28 +- PWGLF/DataModel/Vtx3BodyTables.h | 770 ++-- PWGLF/TableProducer/Nuspex/CMakeLists.txt | 12 +- .../Nuspex/decay3bodybuilder.cxx | 3303 ++++++----------- .../Nuspex/decay3bodybuilder_new.cxx | 2000 ---------- .../Nuspex/reduced3bodyCreator.cxx | 41 +- .../TableProducer/Nuspex/threebodyKFTask.cxx | 488 --- .../Nuspex/threebodyRecoTask.cxx | 909 ----- PWGLF/Utils/decay3bodyBuilderHelper.h | 611 ++- 9 files changed, 1636 insertions(+), 6526 deletions(-) delete mode 100644 PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx delete mode 100644 PWGLF/TableProducer/Nuspex/threebodyKFTask.cxx delete mode 100644 PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx diff --git a/PWGLF/DataModel/Reduced3BodyTables.h b/PWGLF/DataModel/Reduced3BodyTables.h index 51fff63c81d..aeabfb92c0b 100644 --- a/PWGLF/DataModel/Reduced3BodyTables.h +++ b/PWGLF/DataModel/Reduced3BodyTables.h @@ -83,6 +83,7 @@ DECLARE_SOA_TABLE_FULL(StoredRedIUTracks, "RedIUTracks", "AOD", "REDIUTRACK", // // tracks extra track::PIDForTracking, track::IsPVContributor, + track::HasITS, track::HasTPC, track::HasTOF, track::TPCNClsFound, @@ -120,29 +121,22 @@ DECLARE_SOA_INDEX_COLUMN_FULL(Track0, track0, int, RedIUTracks, "_0"); //! DECLARE_SOA_INDEX_COLUMN_FULL(Track1, track1, int, RedIUTracks, "_1"); //! Track 1 index DECLARE_SOA_INDEX_COLUMN_FULL(Track2, track2, int, RedIUTracks, "_2"); //! Track 2 index DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, RedCollisions, ""); //! Collision index -DECLARE_SOA_COLUMN(Phi, phi, float); //! decay3body radius -DECLARE_SOA_COLUMN(Radius, radius, float); //! decay3body phi -DECLARE_SOA_COLUMN(PosZ, posz, float); //! decay3body z position +DECLARE_SOA_COLUMN(RadiusKF, radiusKF, float); //! phi of momentum of mother particle calculated by KF +DECLARE_SOA_COLUMN(PhiKF, phiKF, float); //! SV radius in x-y plane calculated by KF +DECLARE_SOA_COLUMN(PosZKF, poszKF, float); //! z position of SV calculated by KF +DECLARE_SOA_COLUMN(RadiusDCA, radiusDCA, float); //! phi of momentum of mother particle calculated by dcaFitter +DECLARE_SOA_COLUMN(PhiDCA, phiDCA, float); //! SV radius in x-y plane calculated by dcaFitter +DECLARE_SOA_COLUMN(PosZDCA, poszDCA, float); //! z position of SV calculated by dcaFitter +DECLARE_SOA_COLUMN(TrackedClSize, trackedClSize, float); //! average ITS cluster size (if tracked) } // namespace reduceddecay3body DECLARE_SOA_TABLE(RedDecay3Bodys, "AOD", "REDDECAY3BODY", //! reduced 3-body decay table o2::soa::Index<>, reduceddecay3body::CollisionId, reduceddecay3body::Track0Id, reduceddecay3body::Track1Id, reduceddecay3body::Track2Id); -using ReducedDecay3BodysLinked = soa::Join; -using ReducedDecay3BodyLinked = ReducedDecay3BodysLinked::iterator; - DECLARE_SOA_TABLE(Red3BodyInfo, "AOD", "RED3BODYINFO", //! joinable with RedDecay3Bodys - reduceddecay3body::Radius, reduceddecay3body::Phi, reduceddecay3body::PosZ); - -namespace dcafittersvinfo -{ -DECLARE_SOA_COLUMN(SVRadius, svRadius, float); //! SV radius in x-y plane calculated by dcaFitter -DECLARE_SOA_COLUMN(MomPhi, momPhi, float); //! phi of momentum of mother particle calculated from dcaFitter -DECLARE_SOA_COLUMN(SVPosZ, svPosZ, float); //! z position of SV calculated by dcaFitter -} // namespace dcafittersvinfo - -DECLARE_SOA_TABLE_FULL(DCAFitterSVInfo, "FitSVInfo", "AOD", "FITSVINFO", //! joinable with RedDecay3Bodys - dcafittersvinfo::SVRadius, dcafittersvinfo::MomPhi, dcafittersvinfo::SVPosZ); + reduceddecay3body::RadiusKF, reduceddecay3body::PhiKF, reduceddecay3body::PosZKF, + reduceddecay3body::RadiusDCA, reduceddecay3body::PhiDCA, reduceddecay3body::PosZDCA, + reduceddecay3body::TrackedClSize); } // namespace o2::aod diff --git a/PWGLF/DataModel/Vtx3BodyTables.h b/PWGLF/DataModel/Vtx3BodyTables.h index 9ae43bb0255..fbccd926806 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. /// \file Vtx3BodyTables.h -/// \brief Definitions of reduced tables for 3body decayed hypertriton +/// \brief Definitions of analysis tables for 3body decayed hypertriton /// \author Yuanzhe Wang /// \author Carolina Reetz @@ -26,48 +26,110 @@ namespace o2::aod { namespace vtx3body { -DECLARE_SOA_INDEX_COLUMN_FULL(Track0, track0, int, Tracks, "_0"); //! -DECLARE_SOA_INDEX_COLUMN_FULL(Track1, track1, int, Tracks, "_1"); //! -DECLARE_SOA_INDEX_COLUMN_FULL(Track2, track2, int, Tracks, "_2"); //! -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! -DECLARE_SOA_INDEX_COLUMN(Decay3Body, decay3body); //! +// General 3 body Vtx properties +DECLARE_SOA_COLUMN(Mass, mass, float); //! candidate mass (with H3L or Anti-H3L mass hypothesis depending on deuteron charge) +DECLARE_SOA_COLUMN(Sign, sign, float); //! candidate sign +DECLARE_SOA_COLUMN(X, x, float); //! decay position X +DECLARE_SOA_COLUMN(Y, y, float); //! decay position Y +DECLARE_SOA_COLUMN(Z, z, float); //! decay position Z +DECLARE_SOA_COLUMN(Px, px, float); //! momentum X +DECLARE_SOA_COLUMN(Py, py, float); //! momentum Y +DECLARE_SOA_COLUMN(Pz, pz, float); //! momentum Z +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! KFParticle: chi2geo/ndf or chi2topo/ndf of vertex fit, DCA fitter: Chi2AtPCACandidate value + +// daughter properties +DECLARE_SOA_COLUMN(MassV0, massV0, float); //! V0 mass (with H3L or Anti-H3L mass hypothesis depending on deuteron charge) +DECLARE_SOA_COLUMN(PxTrackPr, pxTrackPr, float); //! track0 px at min +DECLARE_SOA_COLUMN(PyTrackPr, pyTrackPr, float); //! track0 py at min +DECLARE_SOA_COLUMN(PzTrackPr, pzTrackPr, float); //! track0 pz at min +DECLARE_SOA_COLUMN(PxTrackPi, pxTrackPi, float); //! track1 px at min +DECLARE_SOA_COLUMN(PyTrackPi, pyTrackPi, float); //! track1 py at min +DECLARE_SOA_COLUMN(PzTrackPi, pzTrackPi, float); //! track1 pz at min +DECLARE_SOA_COLUMN(PxTrackDe, pxTrackDe, float); //! track2 px at min +DECLARE_SOA_COLUMN(PyTrackDe, pyTrackDe, float); //! track2 py at min +DECLARE_SOA_COLUMN(PzTrackDe, pzTrackDe, float); //! track2 pz at min + +// DCAs to PV +DECLARE_SOA_COLUMN(DCAXYTrackPrToPV, dcaXYtrackPrToPv, float); //! DCAXY of proton to PV +DECLARE_SOA_COLUMN(DCAXYTrackPiToPV, dcaXYtrackPiToPv, float); //! DCAXY of pion to PV +DECLARE_SOA_COLUMN(DCAXYTrackDeToPV, dcaXYtrackDeToPv, float); //! DCAXY of deuteron to PV +DECLARE_SOA_COLUMN(DCAZTrackPrToPV, dcaZtrackPrToPv, float); //! DCAZ of proton to PV +DECLARE_SOA_COLUMN(DCAZTrackPiToPV, dcaZtrackPiToPv, float); //! DCAZ of pion to PV +DECLARE_SOA_COLUMN(DCAZTrackDeToPV, dcaZtrackDeToPv, float); //! DCAZ of deuteron to PV + +// DCAs to SV +DECLARE_SOA_COLUMN(DCATrackPrToSV, dcaTrackPrToSv, float); //! DCA of proton to SV +DECLARE_SOA_COLUMN(DCATrackPiToSV, dcaTrackPiToSv, float); //! DCA of pion to SV +DECLARE_SOA_COLUMN(DCATrackDeToSV, dcaTrackDeToSv, float); //! DCA of deuteron to SV +DECLARE_SOA_COLUMN(DCAVtxDaughters, dcaVtxdaughters, float); //! Quadratic sum of DCA between daughters at SV -// General 3 body Vtx properties: position, momentum -DECLARE_SOA_COLUMN(PxTrack0, pxtrack0, float); //! track0 px at min -DECLARE_SOA_COLUMN(PyTrack0, pytrack0, float); //! track0 py at min -DECLARE_SOA_COLUMN(PzTrack0, pztrack0, float); //! track0 pz at min -DECLARE_SOA_COLUMN(PxTrack1, pxtrack1, float); //! track1 px at min -DECLARE_SOA_COLUMN(PyTrack1, pytrack1, float); //! track1 py at min -DECLARE_SOA_COLUMN(PzTrack1, pztrack1, float); //! track1 pz at min -DECLARE_SOA_COLUMN(PxTrack2, pxtrack2, float); //! track2 px at min -DECLARE_SOA_COLUMN(PyTrack2, pytrack2, float); //! track2 py at min -DECLARE_SOA_COLUMN(PzTrack2, pztrack2, float); //! track2 pz at min -DECLARE_SOA_COLUMN(X, x, float); //! decay position X -DECLARE_SOA_COLUMN(Y, y, float); //! decay position Y -DECLARE_SOA_COLUMN(Z, z, float); //! decay position Z - -// Saved from finding: DCAs -DECLARE_SOA_COLUMN(DCAVtxDaughters, dcaVtxdaughters, float); //! DCA among daughters -DECLARE_SOA_COLUMN(DCAXYTrack0ToPV, dcaXYtrack0topv, float); //! DCAXY of prong0 to PV -DECLARE_SOA_COLUMN(DCAXYTrack1ToPV, dcaXYtrack1topv, float); //! DCAXY of prong1 to PV -DECLARE_SOA_COLUMN(DCAXYTrack2ToPV, dcaXYtrack2topv, float); //! DCAXY of prong2 to PV -DECLARE_SOA_COLUMN(DCATrack0ToPV, dcatrack0topv, float); //! DCA of prong0 to PV -DECLARE_SOA_COLUMN(DCATrack1ToPV, dcatrack1topv, float); //! DCA of prong1 to PV -DECLARE_SOA_COLUMN(DCATrack2ToPV, dcatrack2topv, float); //! DCA of prong2 to PV +// Strangeness tracking +DECLARE_SOA_COLUMN(TrackedClSize, trackedClSize, float); //! Average ITS cluster size of strangeness tracked 3body -// Recalculated TOF PID information of bachelor -DECLARE_SOA_COLUMN(TOFNSigmaBachDe, tofNSigmaBachDe, float); //! Recalculated Nsigma seperation with TOF for deuteron +// PID +DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, float); //! nsigma proton of TPC PID of the proton daughter +DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); //! nsigma pion of TPC PID of the pion daughter +DECLARE_SOA_COLUMN(TPCNSigmaDe, tpcNSigmaDe, float); //! nsigma deuteron of TPC PID of the bachelor daughter +DECLARE_SOA_COLUMN(TPCNSigmaPiBach, tpcNSigmaPiBach, float); //! nsigma pion of TPC PID of the bachelor daughter +DECLARE_SOA_COLUMN(TOFNSigmaDe, tofNSigmaDe, float); //! nsigma deuteron of TOF PID of the bachelor daughter +DECLARE_SOA_COLUMN(PIDTrackingDe, pidTrackingDe, uint32_t); //! PID during tracking of bachelor daughter + +// Daughter track quality +DECLARE_SOA_COLUMN(TPCNClTrackPr, tpcNClTrackPr, int); //! Number of TPC clusters of proton daughter +DECLARE_SOA_COLUMN(TPCNClTrackPi, tpcNClTrackPi, int); //! Number of TPC clusters of pion daughter +DECLARE_SOA_COLUMN(TPCNClTrackDe, tpcNClTrackDe, int); //! Number of TPC clusters of deuteron daughter +DECLARE_SOA_COLUMN(ITSClSizePr, itsClsizePr, double); //! average ITS cluster size of proton daughter +DECLARE_SOA_COLUMN(ITSClSizePi, itsClsizePi, double); //! average ITS cluster size of pion daughter +DECLARE_SOA_COLUMN(ITSClSizeDe, itsClsizeDe, double); //! average ITS cluster size of deuteron daughter + +// Covariance matrices +DECLARE_SOA_COLUMN(CovProton, covProton, float[21]); //! covariance matrix elements of proton daughter track +DECLARE_SOA_COLUMN(CovPion, covPion, float[21]); //! covariance matrix elements of pion daughter track +DECLARE_SOA_COLUMN(CovDeuteron, covDeuteron, float[21]); //! covariance matrix elements of deuteron daughter track +DECLARE_SOA_COLUMN(VtxCovMat, vtxCovMat, float[21]); //! covariance matrix elements of candidate + +// Monte Carlo info +DECLARE_SOA_COLUMN(GenPx, genPx, float); // generated Px of the hypertriton in GeV/c +DECLARE_SOA_COLUMN(GenPy, genPy, float); // generated Py of the hypertriton in GeV/c +DECLARE_SOA_COLUMN(GenPz, genPz, float); // generated Pz of the hypertriton in GeV/c +DECLARE_SOA_COLUMN(GenX, genX, float); // generated decay vtx position X of the hypertriton +DECLARE_SOA_COLUMN(GenY, genY, float); // generated decay vtx position Y of the hypertriton +DECLARE_SOA_COLUMN(GenZ, genZ, float); // generated decay vtx position Z of the hypertriton +DECLARE_SOA_COLUMN(GenCt, genCt, float); // generated Ct of the hypertriton +DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // generated Phi of the hypertriton +DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton +DECLARE_SOA_COLUMN(GenRap, genRap, float); // generated rapidity of the hypertriton +DECLARE_SOA_COLUMN(GenPPr, genPPr, float); //! generated momentum proton daughter particle +DECLARE_SOA_COLUMN(GenPPi, genPPi, float); //! generated momentum pion daughter particle +DECLARE_SOA_COLUMN(GenPDe, genPDe, float); //! generated momentum deuteron daughter particle +DECLARE_SOA_COLUMN(GenPtPr, genPtPr, float); //! generated transverse momentum proton daughter particle +DECLARE_SOA_COLUMN(GenPtPi, genPtPi, float); //! generated transverse momentum pion daughter particle +DECLARE_SOA_COLUMN(GenPtDe, genPtDe, float); //! generated transverse momentum deuteron daughter particle +DECLARE_SOA_COLUMN(IsTrueH3L, isTrueH3l, bool); //! flag for true hypertriton candidate +DECLARE_SOA_COLUMN(IsTrueAntiH3L, isTrueAntiH3l, bool); //! flag for true anti-hypertriton candidate +DECLARE_SOA_COLUMN(PrPdgCode, prPdgCode, int); //! MC particle proton PDG code +DECLARE_SOA_COLUMN(PiPdgCode, piPdgCode, int); //! MC particle pion PDG code +DECLARE_SOA_COLUMN(DePdgCode, dePdgCode, int); //! MC particle deuteron PDG code +DECLARE_SOA_COLUMN(IsDePrimary, isDePrimary, bool); //! flag for deuteron daughter primary +DECLARE_SOA_COLUMN(IsSurvEvSel, isSurvEvSel, int); //! flag if reco collision survived event selection +DECLARE_SOA_COLUMN(IsReco, isreco, int); //! flag if candidate was reconstructed // Derived expressions // Momenta -DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! 3 body p - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack0 + pxtrack1 + pxtrack2, pytrack0 + pytrack1 + pytrack2, pztrack0 + pztrack1 + pztrack2); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! 3 body pT - [](float pxtrack0, float pytrack0, float pxtrack1, float pytrack1, float pxtrack2, float pytrack2) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack0 + pxtrack1 + pxtrack2, pytrack0 + pytrack1 + pytrack2); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! 3 body pT in GeV/c + [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! 3 body total momentum in GeV/c + [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(GenPt, genPt, //! 3 body pT in GeV/c + [](float genPx, float genPy) -> float { return RecoDecay::sqrtSumOfSquares(genPx, genPy); }); +DECLARE_SOA_DYNAMIC_COLUMN(GenP, genP, //! 3 body total momentum in GeV/c + [](float genPx, float genPy, float genPz) -> float { return RecoDecay::sqrtSumOfSquares(genPx, genPy, genPz); }); // Length quantities DECLARE_SOA_DYNAMIC_COLUMN(VtxRadius, vtxradius, //! 3 body decay radius (2D, centered at zero) [](float x, float y) -> float { return RecoDecay::sqrtSumOfSquares(x, y); }); +DECLARE_SOA_DYNAMIC_COLUMN(GenRadius, genRadius, //! 3 body decay radius (2D, centered at zero) + [](float genX, float genY) -> float { return RecoDecay::sqrtSumOfSquares(genX, genY); }); // Distance Over To Mom DECLARE_SOA_DYNAMIC_COLUMN(DistOverTotMom, distovertotmom, //! PV to 3 body decay distance over total momentum @@ -79,6 +141,7 @@ DECLARE_SOA_DYNAMIC_COLUMN(DistOverTotMom, distovertotmom, //! PV to 3 body deca // CosPA DECLARE_SOA_DYNAMIC_COLUMN(VtxCosPA, vtxcosPA, //! 3 body vtx CosPA [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) -> float { return RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{X, Y, Z}, std::array{Px, Py, Pz}); }); + // Dca to PV DECLARE_SOA_DYNAMIC_COLUMN(DCAVtxToPV, dcavtxtopv, //! DCA of 3 body vtx to PV [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) -> float { return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); }); @@ -89,532 +152,139 @@ DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! 3 body vtx eta DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! 3 body vtx phi [](float Px, float Py) -> float { return RecoDecay::phi(Px, Py); }); -// Calculated on the fly with mother particle hypothesis -DECLARE_SOA_DYNAMIC_COLUMN(MHypertriton, mHypertriton, //! mass under Hypertriton hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); }); -DECLARE_SOA_DYNAMIC_COLUMN(MAntiHypertriton, mAntiHypertriton, //! mass under antiHypertriton hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); }); - -DECLARE_SOA_DYNAMIC_COLUMN(MHyperHelium4, mHyperHelium4, //! mass under HyperHelium4 hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassHelium3}); }); -DECLARE_SOA_DYNAMIC_COLUMN(MAntiHyperHelium4, mAntiHyperHelium4, //! mass under antiHyperHelium4 hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassHelium3}); }); - -DECLARE_SOA_DYNAMIC_COLUMN(YHypertriton, yHypertriton, //! 3 body vtx y with hypertriton or antihypertriton hypothesis +// Rapidity +DECLARE_SOA_DYNAMIC_COLUMN(Rap, rap, //! 3 body vtx y with hypertriton or antihypertriton hypothesis [](float Px, float Py, float Pz) -> float { return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassHyperTriton); }); -DECLARE_SOA_DYNAMIC_COLUMN(YHyperHelium4, yHyperHelium4, //! 3 body vtx y with hyperhelium4 or antihyperhelium4 hypothesis - [](float Px, float Py, float Pz) -> float { return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassHyperHelium4); }); - -// kinematic information of daughter tracks -DECLARE_SOA_DYNAMIC_COLUMN(Track0Pt, track0pt, //! daughter0 pT - [](float pxtrack0, float pytrack0) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack0, pytrack0); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track1Pt, track1pt, //! daughter1 pT - [](float pxtrack1, float pytrack1) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack1, pytrack1); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track2Pt, track2pt, //! daughter2 pT - [](float pxtrack2, float pytrack2) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack2, pytrack2); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track0Eta, track0eta, //! daughter0 eta - [](float pxtrack0, float pytrack0, float pztrack0) -> float { return RecoDecay::eta(std::array{pxtrack0, pytrack0, pztrack0}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track0Phi, track0phi, //! daughter0 phi - [](float pxtrack0, float pytrack0) -> float { return RecoDecay::phi(pxtrack0, pytrack0); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track1Eta, track1eta, //! daughter1 eta - [](float pxtrack1, float pytrack1, float pztrack1) -> float { return RecoDecay::eta(std::array{pxtrack1, pytrack1, pztrack1}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track1Phi, track1phi, //! daughter1 phi - [](float pxtrack1, float pytrack1) -> float { return RecoDecay::phi(pxtrack1, pytrack1); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track2Eta, track2eta, //! daughter2 eta - [](float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::eta(std::array{pxtrack2, pytrack2, pztrack2}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track2Phi, track2phi, //! daughter2 phi - [](float pxtrack2, float pytrack2) -> float { return RecoDecay::phi(pxtrack2, pytrack2); }); -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, //! 3 body vtx px - float, 1.f * aod::vtx3body::pxtrack0 + 1.f * aod::vtx3body::pxtrack1 + 1.f * aod::vtx3body::pxtrack2); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, //! 3 body vtx py - float, 1.f * aod::vtx3body::pytrack0 + 1.f * aod::vtx3body::pytrack1 + 1.f * aod::vtx3body::pytrack2); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! 3 body vtx pz - float, 1.f * aod::vtx3body::pztrack0 + 1.f * aod::vtx3body::pztrack1 + 1.f * aod::vtx3body::pztrack2); +// Kinematic information of daughter tracks +DECLARE_SOA_DYNAMIC_COLUMN(TrackPrPt, trackPrPt, //! daughter0 pT + [](float pxTrackPr, float pyTrackPr) -> float { return RecoDecay::sqrtSumOfSquares(pxTrackPr, pyTrackPr); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPiPt, trackPiPt, //! daughter1 pT + [](float pxTrackPi, float pyTrackPi) -> float { return RecoDecay::sqrtSumOfSquares(pxTrackPi, pyTrackPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackDePt, trackDePt, //! daughter2 pT + [](float pxTrackDe, float pyTrackDe) -> float { return RecoDecay::sqrtSumOfSquares(pxTrackDe, pyTrackDe); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPrEta, trackPrEta, //! daughter0 eta + [](float pxTrackPr, float pyTrackPr, float pzTrackPr) -> float { return RecoDecay::eta(std::array{pxTrackPr, pyTrackPr, pzTrackPr}); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPrPhi, trackPrPhi, //! daughter0 phi + [](float pxTrackPr, float pyTrackPr) -> float { return RecoDecay::phi(pxTrackPr, pyTrackPr); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPiEta, trackPiEta, //! daughter1 eta + [](float pxTrackPi, float pyTrackPi, float pzTrackPi) -> float { return RecoDecay::eta(std::array{pxTrackPi, pyTrackPi, pzTrackPi}); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPiPhi, trackPiPhi, //! daughter1 phi + [](float pxTrackPi, float pyTrackPi) -> float { return RecoDecay::phi(pxTrackPi, pyTrackPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackDeEta, trackDeEta, //! daughter2 eta + [](float pxTrackDe, float pyTrackDe, float pzTrackDe) -> float { return RecoDecay::eta(std::array{pxTrackDe, pyTrackDe, pzTrackDe}); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackDePhi, trackDePhi, //! daughter2 phi + [](float pxTrackDe, float pyTrackDe) -> float { return RecoDecay::phi(pxTrackDe, pyTrackDe); }); } // namespace vtx3body -DECLARE_SOA_TABLE_FULL(StoredVtx3BodyDatas, "Vtx3BodyDatas", "AOD", "Vtx3BodyDATA", //! - o2::soa::Index<>, vtx3body::Track0Id, vtx3body::Track1Id, vtx3body::Track2Id, vtx3body::CollisionId, vtx3body::Decay3BodyId, - vtx3body::X, vtx3body::Y, vtx3body::Z, - vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, - vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, - vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, - vtx3body::DCAVtxDaughters, - vtx3body::DCAXYTrack0ToPV, vtx3body::DCAXYTrack1ToPV, vtx3body::DCAXYTrack2ToPV, - vtx3body::DCATrack0ToPV, vtx3body::DCATrack1ToPV, vtx3body::DCATrack2ToPV, - vtx3body::TOFNSigmaBachDe, - - // Dynamic columns - vtx3body::P, - vtx3body::Pt, - vtx3body::VtxRadius, - vtx3body::DistOverTotMom, - vtx3body::VtxCosPA, - vtx3body::DCAVtxToPV, - - // Invariant masses - vtx3body::MHypertriton, - vtx3body::MAntiHypertriton, - vtx3body::MHyperHelium4, - vtx3body::MAntiHyperHelium4, - - // Longitudinal - vtx3body::YHypertriton, - vtx3body::YHyperHelium4, - vtx3body::Eta, - vtx3body::Phi, - vtx3body::Track0Pt, - vtx3body::Track0Eta, - vtx3body::Track0Phi, - vtx3body::Track1Pt, - vtx3body::Track1Eta, - vtx3body::Track1Phi, - vtx3body::Track2Pt, - vtx3body::Track2Eta, - vtx3body::Track2Phi); - -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(Vtx3BodyDatas, StoredVtx3BodyDatas, "Vtx3BodyDATAEXT", //! - vtx3body::Px, vtx3body::Py, vtx3body::Pz); - -using Vtx3BodyData = Vtx3BodyDatas::iterator; -namespace vtx3body -{ -DECLARE_SOA_INDEX_COLUMN(Vtx3BodyData, vtx3BodyData); //! Index to Vtx3BodyData entry -} - -DECLARE_SOA_TABLE(Decay3BodyDataLink, "AOD", "DECAY3BODYLINK", //! Joinable table with Decay3bodys which links to Vtx3BodyData which is not produced for all entries - vtx3body::Vtx3BodyDataId); - -using Decay3BodysLinked = soa::Join; -using Decay3BodyLinked = Decay3BodysLinked::iterator; - -// Definition of labels for Vtx3BodyDatas -namespace mcvtx3bodylabel -{ -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for Vtx3BodyDatas -} // namespace mcvtx3bodylabel - -DECLARE_SOA_TABLE(McVtx3BodyLabels, "AOD", "MCVTXLABEL", //! Table joinable with Vtx3BodyData containing the MC labels - mcvtx3bodylabel::McParticleId); -using McVtx3BodyLabel = McVtx3BodyLabels::iterator; - -// Definition of labels for Decay3Bodys // Full table, joinable with Decay3Bodys (CAUTION: NOT WITH Vtx3BodyDATA) -namespace mcfullvtx3bodylabel -{ -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for Decay3Bodys -} // namespace mcfullvtx3bodylabel - -DECLARE_SOA_TABLE(McFullVtx3BodyLabels, "AOD", "MCFULLVTXLABEL", //! Table joinable with Decay3Bodys - mcfullvtx3bodylabel::McParticleId); -using McFullVtx3BodyLabel = McFullVtx3BodyLabels::iterator; - -// output table for ML studies -namespace hyp3body -{ -// collision -DECLARE_SOA_COLUMN(Centrality, centrality, float); //! centrality -// reconstruced candidate -DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); //! bool: true for matter -DECLARE_SOA_COLUMN(M, m, float); //! invariant mass -DECLARE_SOA_COLUMN(P, p, float); //! p -DECLARE_SOA_COLUMN(Pt, pt, float); //! pT -DECLARE_SOA_COLUMN(Ct, ct, float); //! ct -DECLARE_SOA_COLUMN(CosPA, cospa, float); -DECLARE_SOA_COLUMN(DCADaughters, dcaDaughters, float); //! DCA among daughters -DECLARE_SOA_COLUMN(DCACandToPV, dcaCandtopv, float); //! DCA of the reconstructed track to pv -DECLARE_SOA_COLUMN(VtxRadius, vtxRadius, float); //! Radius of SV -// kinematic infomation of daughter tracks -DECLARE_SOA_COLUMN(PtProton, ptProton, float); //! pT of the proton daughter -DECLARE_SOA_COLUMN(EtaProton, etaProton, float); //! eta of the proton daughter -DECLARE_SOA_COLUMN(PhiProton, phiProton, float); //! phi of the proton daughter -DECLARE_SOA_COLUMN(RadiusProton, radiusProton, float); //! radius of innermost hit of the proton daughter -DECLARE_SOA_COLUMN(PtPion, ptPion, float); //! pT of the pion daughter -DECLARE_SOA_COLUMN(EtaPion, etaPion, float); //! eta of the pion daughter -DECLARE_SOA_COLUMN(PhiPion, phiPion, float); //! phi of the pion daughter -DECLARE_SOA_COLUMN(RadiusPion, radiusPion, float); //! radius of innermost hit of the pion daughter -DECLARE_SOA_COLUMN(PtBachelor, ptBachelor, float); //! pT of the bachelor daughter -DECLARE_SOA_COLUMN(EtaBachelor, etaBachelor, float); //! eta of the bachelor daughter -DECLARE_SOA_COLUMN(PhiBachelor, phiBachelor, float); //! phi of the bachelor daughter -DECLARE_SOA_COLUMN(RadiusBachelor, radiusBachelor, float); //! radius of innermost hit of the bachelor daughter -// track quality -DECLARE_SOA_COLUMN(TPCNclusProton, tpcNclusProton, uint8_t); //! number of TPC clusters of the proton daughter -DECLARE_SOA_COLUMN(TPCNclusPion, tpcNclusPion, uint8_t); //! number of TPC clusters of the pion daughter -DECLARE_SOA_COLUMN(TPCNclusBachelor, tpcNclusBachelor, uint8_t); //! number of TPC clusters of the bachelor daughter -DECLARE_SOA_COLUMN(ITSNclusSizeProton, itsNclusSizeProton, uint8_t); //! average ITS cluster size of the proton daughter -DECLARE_SOA_COLUMN(ITSNclusSizePion, itsNclusSizePion, uint8_t); //! average ITS cluster size of the pion daughter -DECLARE_SOA_COLUMN(ITSNclusSizeBachelor, itsNclusSizeBachelor, uint8_t); //! average ITS cluster size of the bachelor daughter -// PID -DECLARE_SOA_COLUMN(TPCNSigmaProton, tpcNSigmaProton, float); //! nsigma of TPC PID of the proton daughter -DECLARE_SOA_COLUMN(TPCNSigmaPion, tpcNSigmaPion, float); //! nsigma of TPC PID of the pion daughter -DECLARE_SOA_COLUMN(TPCNSigmaBachelor, tpcNSigmaBachelor, float); //! nsigma of TPC PID of the bachelor daughter -DECLARE_SOA_COLUMN(TOFNSigmaBachelor, tofNSigmaBachelor, float); //! nsigma of TOF PID of the bachelor daughter -// DCA to PV -DECLARE_SOA_COLUMN(DCAXYProtonToPV, dcaxyProtontoPV, float); //! DCAXY of the proton daughter to pv -DECLARE_SOA_COLUMN(DCAXYPionToPV, dcaxyPiontoPV, float); //! DCAXY of the pion daughter to pv -DECLARE_SOA_COLUMN(DCAXYBachelorToPV, dcaxyBachelortoPV, float); //! DCAXY of the bachelor daughter to pv -DECLARE_SOA_COLUMN(DCAProtonToPV, dcaProtontoPV, float); //! DCA of the proton daughter to pv -DECLARE_SOA_COLUMN(DCAPionToPV, dcaPiontoPV, float); //! DCA of the pion daughter to pv -DECLARE_SOA_COLUMN(DCABachelorToPV, dcaBachelortoPV, float); //! DCA of the bachelor daughter to pv -DECLARE_SOA_COLUMN(IsBachPrimary, isbachprimary, bool); //! flag for bachelor daughter primary -// for MC -DECLARE_SOA_COLUMN(GenP, genP, float); // P of the hypertriton -DECLARE_SOA_COLUMN(GenPt, genPt, float); // pT of the hypertriton -DECLARE_SOA_COLUMN(GenCt, genCt, float); // ct of the hypertriton -DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // Phi of the hypertriton -DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton -DECLARE_SOA_COLUMN(GenRapidity, genRapidity, float); // Rapidity of the hypertriton -DECLARE_SOA_COLUMN(IsReco, isReco, bool); // bool: true for reco -DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); // bool: true for signal -DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); // pdgCode of the mcparticle, -1 for fake pair -DECLARE_SOA_COLUMN(SurvivedEventSelection, survivedEventSelection, bool); // bool: true for survived event selection -} // namespace hyp3body - -// output table for data -DECLARE_SOA_TABLE(Hyp3BodyCands, "AOD", "HYP3BODYCANDS", - o2::soa::Index<>, - hyp3body::Centrality, - // secondary vertex and reconstruced candidate - hyp3body::IsMatter, - hyp3body::M, - hyp3body::P, - hyp3body::Pt, - hyp3body::Ct, - hyp3body::CosPA, - hyp3body::DCADaughters, - hyp3body::DCACandToPV, - hyp3body::VtxRadius, - // daughter tracks - hyp3body::PtProton, hyp3body::EtaProton, hyp3body::PhiProton, hyp3body::RadiusProton, - hyp3body::PtPion, hyp3body::EtaPion, hyp3body::PhiPion, hyp3body::RadiusPion, - hyp3body::PtBachelor, hyp3body::EtaBachelor, hyp3body::PhiBachelor, hyp3body::RadiusBachelor, - hyp3body::TPCNclusProton, hyp3body::TPCNclusPion, hyp3body::TPCNclusBachelor, - hyp3body::ITSNclusSizeProton, hyp3body::ITSNclusSizePion, hyp3body::ITSNclusSizeBachelor, - hyp3body::TPCNSigmaProton, hyp3body::TPCNSigmaPion, hyp3body::TPCNSigmaBachelor, - hyp3body::TOFNSigmaBachelor, - hyp3body::DCAXYProtonToPV, hyp3body::DCAXYPionToPV, hyp3body::DCAXYBachelorToPV, - hyp3body::DCAProtonToPV, hyp3body::DCAPionToPV, hyp3body::DCABachelorToPV); - -// output table for MC -DECLARE_SOA_TABLE(MCHyp3BodyCands, "AOD", "MCHYP3BODYCANDS", - o2::soa::Index<>, - hyp3body::Centrality, - // secondary vertex and reconstruced candidate - hyp3body::IsMatter, - hyp3body::M, - hyp3body::P, - hyp3body::Pt, - hyp3body::Ct, - hyp3body::CosPA, - hyp3body::DCADaughters, - hyp3body::DCACandToPV, - hyp3body::VtxRadius, - // daughter tracks - hyp3body::PtProton, hyp3body::EtaProton, hyp3body::PhiProton, hyp3body::RadiusProton, - hyp3body::PtPion, hyp3body::EtaPion, hyp3body::PhiPion, hyp3body::RadiusPion, - hyp3body::PtBachelor, hyp3body::EtaBachelor, hyp3body::PhiBachelor, hyp3body::RadiusBachelor, - hyp3body::TPCNclusProton, hyp3body::TPCNclusPion, hyp3body::TPCNclusBachelor, - hyp3body::ITSNclusSizeProton, hyp3body::ITSNclusSizePion, hyp3body::ITSNclusSizeBachelor, - hyp3body::TPCNSigmaProton, hyp3body::TPCNSigmaPion, hyp3body::TPCNSigmaBachelor, - hyp3body::TOFNSigmaBachelor, - hyp3body::DCAXYProtonToPV, hyp3body::DCAXYPionToPV, hyp3body::DCAXYBachelorToPV, - hyp3body::DCAProtonToPV, hyp3body::DCAPionToPV, hyp3body::DCABachelorToPV, - hyp3body::IsBachPrimary, - // MC information - hyp3body::GenP, - hyp3body::GenPt, - hyp3body::GenCt, - hyp3body::GenPhi, - hyp3body::GenEta, - hyp3body::GenRapidity, - hyp3body::IsSignal, - hyp3body::IsReco, - hyp3body::PdgCode, - hyp3body::SurvivedEventSelection); - -//______________________________________________________ -// DATAMODEL FOR KFPARTICLE DECAY3BODYS - -namespace kfvtx3body -{ -// General 3 body Vtx properties: mass, momentum, charge -DECLARE_SOA_COLUMN(Mass, mass, float); //! candidate mass (PID hypothesis depending on bachelor charge) -DECLARE_SOA_COLUMN(XErr, xerr, float); //! candidate position x error at decay position -DECLARE_SOA_COLUMN(YErr, yerr, float); //! candidate position y error at decay position -DECLARE_SOA_COLUMN(ZErr, zerr, float); //! candidate position z error at decay position -DECLARE_SOA_COLUMN(Px, px, float); //! candidate px at decay position -DECLARE_SOA_COLUMN(Py, py, float); //! candidate py at decay position -DECLARE_SOA_COLUMN(Pz, pz, float); //! candidate pz at decay position -DECLARE_SOA_COLUMN(Pt, pt, float); //! candidate pt at decay position -DECLARE_SOA_COLUMN(PxErr, pxerr, float); //! candidate px error at decay position -DECLARE_SOA_COLUMN(PyErr, pyerr, float); //! candidate py error at decay position -DECLARE_SOA_COLUMN(PzErr, pzerr, float); //! candidate pz error at decay position -DECLARE_SOA_COLUMN(PtErr, pterr, float); //! candidate pt error at decay position -DECLARE_SOA_COLUMN(Sign, sign, float); //! candidate sign - -// topological properties -DECLARE_SOA_COLUMN(VtxCosPAKF, vtxcospakf, float); //! 3 body vtx CosPA from KFParticle (using kfpPV) -DECLARE_SOA_COLUMN(VtxCosXYPAKF, vtxcosxypakf, float); //! 3 body vtx CosPA from KFParticle (using kfpPV) -DECLARE_SOA_COLUMN(VtxCosPAKFtopo, vtxcospakftopo, float); //! 3 body vtx CosPA from KFParticle after topological constraint (using kfpPV) -DECLARE_SOA_COLUMN(VtxCosXYPAKFtopo, vtxcosxypakftopo, float); //! 3 body vtx CosPA from KFParticle after topological constraint (using kfpPV) -DECLARE_SOA_COLUMN(DCAVtxToPVKF, dcavtxtopvkf, float); //! 3 body vtx DCA to PV from KFParticle (using kfpPV) -DECLARE_SOA_COLUMN(DCAXYVtxToPVKF, dcaxyvtxtopvkf, float); //! 3 body vtx DCAxy to PV from KFParticle (using kfpPV) -DECLARE_SOA_COLUMN(DecayLKF, decaylkf, float); //! 3 body vtx decay length from KFParticle (using kfpPV after topological constraint) -DECLARE_SOA_COLUMN(DecayLXYKF, decaylxykf, float); //! 3 body vtx decay length XY from KFParticle (using kfpPV after topological constraint) -DECLARE_SOA_COLUMN(DecayLDeltaL, decayldeltal, float); //! 3 body vtx l/dl from KFParticle (using kfpPV after topological constraint) -DECLARE_SOA_COLUMN(Chi2geoNDF, chi2geondf, float); //! 3 body vtx chi2geo from geometrical KFParticle fit -DECLARE_SOA_COLUMN(Chi2topoNDF, chi2topondf, float); //! 3 body vtx chi2topo from KFParticle topological constraint to the PV (using kfpPV) -DECLARE_SOA_COLUMN(CTauKFtopo, ctaukftopo, float); //! 3 body vtx ctau from KFParticle after topological constraint - -// Strangeness tracking -DECLARE_SOA_COLUMN(TrackedClSize, trackedclsize, int); //! Cluster size of strangeness tracked 3body - -// daughters -DECLARE_SOA_COLUMN(DCATrack0ToPVKF, dcatrack0topvkf, float); //! DCA of proton prong to PV from KFParticle -DECLARE_SOA_COLUMN(DCATrack1ToPVKF, dcatrack1topvkf, float); //! DCA of pion prong to PV from KFParticle -DECLARE_SOA_COLUMN(DCATrack2ToPVKF, dcatrack2topvkf, float); //! DCA of deuteron prong to PV from KFParticle -DECLARE_SOA_COLUMN(DCAxyTrack0ToPVKF, dcaxytrack0topvkf, float); //! DCAxy of proton prong to PV from KFParticle -DECLARE_SOA_COLUMN(DCAxyTrack1ToPVKF, dcaxytrack1topvkf, float); //! DCAxy of pion prong to PV from KFParticle -DECLARE_SOA_COLUMN(DCAxyTrack2ToPVKF, dcaxytrack2topvkf, float); //! DCAxy of deuteron prong to PV from KFParticle -DECLARE_SOA_COLUMN(DCATrackPosToPV, dcatrackpostopv, float); //! DCA of positive track to PV (propagated before vtx fit) -DECLARE_SOA_COLUMN(DCATrackNegToPV, dcatracknegtopv, float); //! DCA of negative track to PV (propagated before vtx fit) -DECLARE_SOA_COLUMN(DCATrackBachToPV, dcatrackbachtopv, float); //! DCA of bachelor track to PV (propagated before vtx fit) -DECLARE_SOA_COLUMN(DCAxyTrackPosToPV, dcaxytrackpostopv, float); //! DCAxy of positive track to PV (propagated before vtx fit) -DECLARE_SOA_COLUMN(DCAxyTrackNegToPV, dcaxytracknegtopv, float); //! DCAxy of negative track to PV (propagated before vtx fit) -DECLARE_SOA_COLUMN(DCAxyTrackBachToPV, dcaxytrackbachtopv, float); //! DCAxy of bachelor track to PV (propagated before vtx fit) -DECLARE_SOA_COLUMN(DCAxyTrack0ToSVKF, dcaxytrack0tosvkf, float); //! DCAxy of proton prong to SV from KFParticle -DECLARE_SOA_COLUMN(DCAxyTrack1ToSVKF, dcaxytrack1tosvkf, float); //! DCAxy of pion prong to SV from KFParticle -DECLARE_SOA_COLUMN(DCAxyTrack2ToSVKF, dcaxytrack2tosvkf, float); //! DCAxy of deuteron prong to SV from KFParticle -DECLARE_SOA_COLUMN(DCATrack0ToTrack1KF, dcatrack0totrack1kf, float); //! DCAxy of proton prong to pion from KFParticle -DECLARE_SOA_COLUMN(DCATrack0ToTrack2KF, dcatrack0totrack2kf, float); //! DCAxy of proton prong to deuteron from KFParticle -DECLARE_SOA_COLUMN(DCATrack1ToTrack2KF, dcatrack1totrack2kf, float); //! DCAxy of pion prong to deuteron from KFParticle -DECLARE_SOA_COLUMN(DCAVtxDaughtersKF, dcavtxdaughterskf, float); //! sum of DCAs between daughters in 3D from KFParticle -DECLARE_SOA_COLUMN(Track0Sign, track0sign, float); //! sign of proton daughter track -DECLARE_SOA_COLUMN(Track1Sign, track1sign, float); //! sign of pion daughter track -DECLARE_SOA_COLUMN(Track2Sign, track2sign, float); //! sign of deuteron daughter track -DECLARE_SOA_COLUMN(TPCInnerParamTrack0, tpcinnerparamtrack0, float); //! momentum at inner wall of TPC of proton daughter -DECLARE_SOA_COLUMN(TPCInnerParamTrack1, tpcinnerparamtrack1, float); //! momentum at inner wall of TPC of pion daughter -DECLARE_SOA_COLUMN(TPCInnerParamTrack2, tpcinnerparamtrack2, float); //! momentum at inner wall of TPC of deuteron daughter -DECLARE_SOA_COLUMN(TPCNClTrack0, tpcncltrack0, int); //! Number of TPC clusters of proton daughter -DECLARE_SOA_COLUMN(TPCNClTrack1, tpcncltrack1, int); //! Number of TPC clusters of pion daughter -DECLARE_SOA_COLUMN(TPCNClTrack2, tpcncltrack2, int); //! Number of TPC clusters of deuteron daughter -DECLARE_SOA_COLUMN(TPCChi2NClDeuteron, tpcchi2ncldeuteron, float); //! TPC Chi2 / cluster of deuteron daughter -DECLARE_SOA_COLUMN(DeltaPhiDeuteron, deltaphideuteron, float); //! phi before track rotation - phi after track rotation for deuteron track -DECLARE_SOA_COLUMN(DeltaPhiProton, deltaphiproton, float); //! phi before track rotation - phi after track rotation for proton track -// PID -DECLARE_SOA_COLUMN(TPCNSigmaProton, tpcnsigmaproton, float); //! nsigma proton of TPC PID of the proton daughter -DECLARE_SOA_COLUMN(TPCNSigmaPion, tpcnsigmapion, float); //! nsigma pion of TPC PID of the pion daughter -DECLARE_SOA_COLUMN(TPCNSigmaDeuteron, tpcnsigmadeuteron, float); //! nsigma deuteron of TPC PID of the bachelor daughter -DECLARE_SOA_COLUMN(TPCNSigmaPionBach, tpcnsigmapionbach, float); //! nsigma pion of TPC PID of the bachelor daughter -DECLARE_SOA_COLUMN(TPCdEdxProton, tpcdedxproton, float); //! TPC dEdx of the proton daughter -DECLARE_SOA_COLUMN(TPCdEdxPion, tpcdedxpion, float); //! TPC dEdx of the pion daughter -DECLARE_SOA_COLUMN(TPCdEdxDeuteron, tpcdedxdeuteron, float); //! TPC dEdx of the bachelor daughter -DECLARE_SOA_COLUMN(TOFNSigmaDeuteron, tofnsigmadeuteron, float); //! nsigma of TOF PID of the bachelor daughter -DECLARE_SOA_COLUMN(ITSClusSizeDeuteron, itsclussizedeuteron, double); //! average ITS cluster size of bachelor daughter -DECLARE_SOA_COLUMN(PIDTrackingDeuteron, pidtrackingdeuteron, uint32_t); //! PID during tracking of bachelor daughter - -// Monte Carlo -DECLARE_SOA_COLUMN(GenP, genp, float); //! generated momentum -DECLARE_SOA_COLUMN(GenPt, genpt, float); //! generated transverse momentum -DECLARE_SOA_COLUMN(GenDecVtxX, gendecvtxx, double); //! generated decay vertex position x -DECLARE_SOA_COLUMN(GenDecVtxY, gendecvtxy, double); //! generated decay vertex position y -DECLARE_SOA_COLUMN(GenDecVtxZ, gendecvtxz, double); //! generated decay vertex position z -DECLARE_SOA_COLUMN(GenCtau, genctau, double); //! generated ctau -DECLARE_SOA_COLUMN(GenPhi, genphi, float); //! generated phi -DECLARE_SOA_COLUMN(GenEta, geneta, float); //! generated eta -DECLARE_SOA_COLUMN(GenRapidity, genrapidity, float); //! generated rapidity -DECLARE_SOA_COLUMN(GenPosP, genposp, float); //! generated momentum pos daughter particle -DECLARE_SOA_COLUMN(GenPosPt, genpospt, float); //! generated transverse momentum pos daughter particle -DECLARE_SOA_COLUMN(GenNegP, gennegp, float); //! generated momentum neg daughter particle -DECLARE_SOA_COLUMN(GenNegPt, gennegpt, float); //! generated transverse momentum neg daughter particle -DECLARE_SOA_COLUMN(GenBachP, genbachp, float); //! generated momentum bachelor daughter particle -DECLARE_SOA_COLUMN(GenBachPt, genbachpt, float); //! generated transverse momentum bachelor daughter particle -DECLARE_SOA_COLUMN(IsTrueH3L, istrueh3l, bool); //! flag for true hypertriton candidate -DECLARE_SOA_COLUMN(IsTrueAntiH3L, istrueantih3l, bool); //! flag for true anti-hypertriton candidate -DECLARE_SOA_COLUMN(PdgCodeDau0, pdgcodedau0, int); //! MC particle daughter 0 PDG code -DECLARE_SOA_COLUMN(PdgCodeDau1, pdgcodedau1, int); //! MC particle daughter 1 PDG code -DECLARE_SOA_COLUMN(PdgCodeDau2, pdgcodedau2, int); //! MC particle daughter 2 PDG code -DECLARE_SOA_COLUMN(IsBachPrimary, isbachprimary, bool); //! flag for bachelor daughter primary -DECLARE_SOA_COLUMN(SurvEvSel, survevsel, int); //! flag if reco collision survived event selection -DECLARE_SOA_COLUMN(IsReco, isreco, int); //! flag if candidate was reconstructed - -// V0 -DECLARE_SOA_COLUMN(MassV0, massv0, float); //! proton, pion vertex mass -DECLARE_SOA_COLUMN(Chi2MassV0, chi2massv0, float); //! chi2 of proton, pion mass constraint to Lambda mass -DECLARE_SOA_COLUMN(CosPAV0, cospav0, float); //! proton, pion vertex mass - -} // namespace kfvtx3body - -DECLARE_SOA_TABLE(KFVtx3BodyDatas, "AOD", "KFVTX3BODYDATA", - o2::soa::Index<>, vtx3body::CollisionId, vtx3body::Track0Id, vtx3body::Track1Id, vtx3body::Track2Id, vtx3body::Decay3BodyId, - - // hypertriton candidate - kfvtx3body::Mass, - vtx3body::X, vtx3body::Y, vtx3body::Z, - kfvtx3body::XErr, kfvtx3body::YErr, kfvtx3body::ZErr, - kfvtx3body::Px, kfvtx3body::Py, kfvtx3body::Pz, kfvtx3body::Pt, - kfvtx3body::PxErr, kfvtx3body::PyErr, kfvtx3body::PzErr, kfvtx3body::PtErr, - kfvtx3body::Sign, - kfvtx3body::DCAVtxToPVKF, kfvtx3body::DCAXYVtxToPVKF, - kfvtx3body::VtxCosPAKF, kfvtx3body::VtxCosXYPAKF, - kfvtx3body::VtxCosPAKFtopo, kfvtx3body::VtxCosXYPAKFtopo, - kfvtx3body::DecayLKF, kfvtx3body::DecayLXYKF, kfvtx3body::DecayLDeltaL, - kfvtx3body::Chi2geoNDF, kfvtx3body::Chi2topoNDF, - kfvtx3body::CTauKFtopo, kfvtx3body::TrackedClSize, - - // V0 - kfvtx3body::MassV0, kfvtx3body::Chi2MassV0, - kfvtx3body::CosPAV0, - - // daughters - vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, // proton - vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, // pion - vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, // deuteron - kfvtx3body::TPCInnerParamTrack0, kfvtx3body::TPCInnerParamTrack1, kfvtx3body::TPCInnerParamTrack2, // proton, pion, deuteron - kfvtx3body::TPCNClTrack0, kfvtx3body::TPCNClTrack1, kfvtx3body::TPCNClTrack2, // proton, pion, deuteron - kfvtx3body::TPCChi2NClDeuteron, - kfvtx3body::DeltaPhiDeuteron, kfvtx3body::DeltaPhiProton, - kfvtx3body::DCATrack0ToPVKF, kfvtx3body::DCATrack1ToPVKF, kfvtx3body::DCATrack2ToPVKF, kfvtx3body::DCAxyTrack0ToPVKF, kfvtx3body::DCAxyTrack1ToPVKF, kfvtx3body::DCAxyTrack2ToPVKF, - kfvtx3body::DCAxyTrack0ToSVKF, kfvtx3body::DCAxyTrack1ToSVKF, kfvtx3body::DCAxyTrack2ToSVKF, - kfvtx3body::DCATrack0ToTrack1KF, kfvtx3body::DCATrack0ToTrack2KF, kfvtx3body::DCATrack1ToTrack2KF, - kfvtx3body::DCAVtxDaughtersKF, - kfvtx3body::DCAxyTrackPosToPV, kfvtx3body::DCAxyTrackNegToPV, kfvtx3body::DCAxyTrackBachToPV, - kfvtx3body::DCATrackPosToPV, kfvtx3body::DCATrackNegToPV, kfvtx3body::DCATrackBachToPV, - kfvtx3body::Track0Sign, kfvtx3body::Track1Sign, kfvtx3body::Track2Sign, // track sing: proton, pion, deuteron - kfvtx3body::TPCNSigmaProton, kfvtx3body::TPCNSigmaPion, kfvtx3body::TPCNSigmaDeuteron, kfvtx3body::TPCNSigmaPionBach, - kfvtx3body::TPCdEdxProton, kfvtx3body::TPCdEdxPion, kfvtx3body::TPCdEdxDeuteron, - kfvtx3body::TOFNSigmaDeuteron, - kfvtx3body::ITSClusSizeDeuteron, - kfvtx3body::PIDTrackingDeuteron); - -using KFVtx3BodyData = KFVtx3BodyDatas::iterator; -namespace kfvtx3body -{ -DECLARE_SOA_INDEX_COLUMN(KFVtx3BodyData, kfvtx3BodyData); //! Index to KFVtx3BodyData entry -} - -DECLARE_SOA_TABLE(KFDecay3BodyDataLink, "AOD", "KF3BODYLINK", //! Joinable table with Decay3bodys which links to KFVtx3BodyData which is not produced for all entries - kfvtx3body::KFVtx3BodyDataId); - -using KFDecay3BodysLinked = soa::Join; -using KFDecay3BodyLinked = KFDecay3BodysLinked::iterator; - -// Lite data candidate table for analysis -DECLARE_SOA_TABLE(KFVtx3BodyDatasLite, "AOD", "KF3BODYLITE", +// reconstructed candidate table for analysis +DECLARE_SOA_TABLE(Vtx3BodyDatas, "AOD", "VTX3BODYDATA", //! o2::soa::Index<>, - // hypertriton candidate - kfvtx3body::Mass, + vtx3body::Sign, + vtx3body::Mass, vtx3body::MassV0, vtx3body::X, vtx3body::Y, vtx3body::Z, - kfvtx3body::Px, kfvtx3body::Py, kfvtx3body::Pz, kfvtx3body::Pt, - kfvtx3body::Sign, - kfvtx3body::DCAVtxToPVKF, kfvtx3body::DCAXYVtxToPVKF, - kfvtx3body::VtxCosPAKF, kfvtx3body::VtxCosXYPAKF, - kfvtx3body::DecayLKF, kfvtx3body::DecayLXYKF, kfvtx3body::DecayLDeltaL, - kfvtx3body::Chi2geoNDF, kfvtx3body::Chi2topoNDF, - kfvtx3body::CTauKFtopo, kfvtx3body::TrackedClSize, - - // V0 - kfvtx3body::MassV0, - kfvtx3body::CosPAV0, - - // daughters - vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, // proton - vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, // pion - vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, // deuteron - kfvtx3body::TPCInnerParamTrack0, kfvtx3body::TPCInnerParamTrack1, kfvtx3body::TPCInnerParamTrack2, // proton, pion, deuteron - kfvtx3body::TPCNClTrack0, kfvtx3body::TPCNClTrack1, kfvtx3body::TPCNClTrack2, // proton, pion, deuteron - kfvtx3body::TPCChi2NClDeuteron, - kfvtx3body::DeltaPhiDeuteron, kfvtx3body::DeltaPhiProton, - kfvtx3body::DCATrack0ToPVKF, kfvtx3body::DCATrack1ToPVKF, kfvtx3body::DCATrack2ToPVKF, kfvtx3body::DCAxyTrack0ToPVKF, kfvtx3body::DCAxyTrack1ToPVKF, kfvtx3body::DCAxyTrack2ToPVKF, - kfvtx3body::DCAxyTrack0ToSVKF, kfvtx3body::DCAxyTrack1ToSVKF, kfvtx3body::DCAxyTrack2ToSVKF, - kfvtx3body::DCATrack0ToTrack1KF, kfvtx3body::DCATrack0ToTrack2KF, kfvtx3body::DCATrack1ToTrack2KF, - kfvtx3body::DCAVtxDaughtersKF, - kfvtx3body::Track0Sign, kfvtx3body::Track1Sign, kfvtx3body::Track2Sign, // track sing: proton, pion, deuteron - kfvtx3body::TPCNSigmaProton, kfvtx3body::TPCNSigmaPion, kfvtx3body::TPCNSigmaDeuteron, kfvtx3body::TPCNSigmaPionBach, - kfvtx3body::TOFNSigmaDeuteron, - kfvtx3body::ITSClusSizeDeuteron, - kfvtx3body::PIDTrackingDeuteron); - -using KFVtx3BodyDataLite = KFVtx3BodyDatasLite::iterator; + vtx3body::Px, vtx3body::Py, vtx3body::Pz, + vtx3body::Chi2, + vtx3body::TrackedClSize, + vtx3body::PxTrackPr, vtx3body::PyTrackPr, vtx3body::PzTrackPr, + vtx3body::PxTrackPi, vtx3body::PyTrackPi, vtx3body::PzTrackPi, + vtx3body::PxTrackDe, vtx3body::PyTrackDe, vtx3body::PzTrackDe, + vtx3body::DCAXYTrackPrToPV, vtx3body::DCAXYTrackPiToPV, vtx3body::DCAXYTrackDeToPV, + vtx3body::DCAZTrackPrToPV, vtx3body::DCAZTrackPiToPV, vtx3body::DCAZTrackDeToPV, + vtx3body::DCATrackPrToSV, vtx3body::DCATrackPiToSV, vtx3body::DCATrackDeToSV, + vtx3body::DCAVtxDaughters, + vtx3body::TPCNSigmaPr, vtx3body::TPCNSigmaPi, vtx3body::TPCNSigmaDe, vtx3body::TPCNSigmaPiBach, + vtx3body::TOFNSigmaDe, + vtx3body::ITSClSizePr, vtx3body::ITSClSizePi, vtx3body::ITSClSizeDe, + vtx3body::TPCNClTrackPr, vtx3body::TPCNClTrackPi, vtx3body::TPCNClTrackDe, + vtx3body::PIDTrackingDe, + + // Dynamic columns + vtx3body::P, + vtx3body::Pt, + vtx3body::VtxRadius, + vtx3body::DistOverTotMom, + vtx3body::VtxCosPA, + vtx3body::DCAVtxToPV, + + // Longitudinal + vtx3body::Rap, + vtx3body::Eta, + vtx3body::Phi, + vtx3body::TrackPrPt, + vtx3body::TrackPrEta, + vtx3body::TrackPrPhi, + vtx3body::TrackPiPt, + vtx3body::TrackPiEta, + vtx3body::TrackPiPhi, + vtx3body::TrackDePt, + vtx3body::TrackDeEta, + vtx3body::TrackDePhi); + +// covariance matrix table +DECLARE_SOA_TABLE(Vtx3BodyCovs, "AOD", "VTX3BODYCOV", //! + vtx3body::CovProton, vtx3body::CovPion, vtx3body::CovDeuteron, + vtx3body::VtxCovMat); // MC candidate table for analysis -DECLARE_SOA_TABLE(McKFVtx3BodyDatas, "AOD", "MCKF3BODYDATAS", +DECLARE_SOA_TABLE(McVtx3BodyDatas, "AOD", "MC3BODYDATA", //! o2::soa::Index<>, - // hypertriton candidate - kfvtx3body::Mass, + vtx3body::Sign, + vtx3body::Mass, vtx3body::MassV0, vtx3body::X, vtx3body::Y, vtx3body::Z, - kfvtx3body::XErr, kfvtx3body::YErr, kfvtx3body::ZErr, - kfvtx3body::Px, kfvtx3body::Py, kfvtx3body::Pz, kfvtx3body::Pt, - kfvtx3body::PxErr, kfvtx3body::PyErr, kfvtx3body::PzErr, kfvtx3body::PtErr, - kfvtx3body::Sign, - kfvtx3body::DCAVtxToPVKF, kfvtx3body::DCAXYVtxToPVKF, - kfvtx3body::VtxCosPAKF, kfvtx3body::VtxCosXYPAKF, - kfvtx3body::VtxCosPAKFtopo, kfvtx3body::VtxCosXYPAKFtopo, - kfvtx3body::DecayLKF, kfvtx3body::DecayLXYKF, kfvtx3body::DecayLDeltaL, - kfvtx3body::Chi2geoNDF, kfvtx3body::Chi2topoNDF, - kfvtx3body::CTauKFtopo, kfvtx3body::TrackedClSize, - - // V0 - kfvtx3body::MassV0, kfvtx3body::Chi2MassV0, - kfvtx3body::CosPAV0, - - // daughters - vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, // proton - vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, // pion - vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, // deuteron - kfvtx3body::TPCInnerParamTrack0, kfvtx3body::TPCInnerParamTrack1, kfvtx3body::TPCInnerParamTrack2, // proton, pion, deuteron - kfvtx3body::TPCNClTrack0, kfvtx3body::TPCNClTrack1, kfvtx3body::TPCNClTrack2, // proton, pion, deuteron - kfvtx3body::TPCChi2NClDeuteron, - kfvtx3body::DeltaPhiDeuteron, kfvtx3body::DeltaPhiProton, - kfvtx3body::DCATrack0ToPVKF, kfvtx3body::DCATrack1ToPVKF, kfvtx3body::DCATrack2ToPVKF, kfvtx3body::DCAxyTrack0ToPVKF, kfvtx3body::DCAxyTrack1ToPVKF, kfvtx3body::DCAxyTrack2ToPVKF, - kfvtx3body::DCAxyTrack0ToSVKF, kfvtx3body::DCAxyTrack1ToSVKF, kfvtx3body::DCAxyTrack2ToSVKF, - kfvtx3body::DCATrack0ToTrack1KF, kfvtx3body::DCATrack0ToTrack2KF, kfvtx3body::DCATrack1ToTrack2KF, - kfvtx3body::DCAVtxDaughtersKF, - kfvtx3body::DCAxyTrackPosToPV, kfvtx3body::DCAxyTrackNegToPV, kfvtx3body::DCAxyTrackBachToPV, - kfvtx3body::DCATrackPosToPV, kfvtx3body::DCATrackNegToPV, kfvtx3body::DCATrackBachToPV, - kfvtx3body::Track0Sign, kfvtx3body::Track1Sign, kfvtx3body::Track2Sign, // track sing: proton, pion, deuteron - kfvtx3body::TPCNSigmaProton, kfvtx3body::TPCNSigmaPion, kfvtx3body::TPCNSigmaDeuteron, kfvtx3body::TPCNSigmaPionBach, - kfvtx3body::TPCdEdxProton, kfvtx3body::TPCdEdxPion, kfvtx3body::TPCdEdxDeuteron, - kfvtx3body::TOFNSigmaDeuteron, - kfvtx3body::ITSClusSizeDeuteron, - kfvtx3body::PIDTrackingDeuteron, - - // MC information - kfvtx3body::GenP, - kfvtx3body::GenPt, - kfvtx3body::GenDecVtxX, kfvtx3body::GenDecVtxY, kfvtx3body::GenDecVtxZ, - kfvtx3body::GenCtau, - kfvtx3body::GenPhi, - kfvtx3body::GenEta, - kfvtx3body::GenRapidity, - kfvtx3body::GenPosP, kfvtx3body::GenPosPt, - kfvtx3body::GenNegP, kfvtx3body::GenNegPt, - kfvtx3body::GenBachP, kfvtx3body::GenBachPt, - kfvtx3body::IsTrueH3L, kfvtx3body::IsTrueAntiH3L, - kfvtx3body::PdgCodeDau0, kfvtx3body::PdgCodeDau1, kfvtx3body::PdgCodeDau2, - kfvtx3body::IsBachPrimary, - kfvtx3body::IsReco, - kfvtx3body::SurvEvSel); - -// Definition of labels for KFVtx3BodyDatas -namespace mckfvtx3bodylabel -{ -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for KF Vtx3BodyDatas -} // namespace mckfvtx3bodylabel - -DECLARE_SOA_TABLE(McKFVtx3BodyLabels, "AOD", "MCKFVTXLABEL", //! Table joinable with KFVtx3BodyData containing the MC labels - mckfvtx3bodylabel::McParticleId); -using McKFVtx3BodyLabel = McKFVtx3BodyLabels::iterator; - -// Definition of labels for KFDecay3Bodys // Full table, joinable with KFDecay3Bodys (CAUTION: NOT WITH Vtx3BodyDATA) -namespace mcfullkfvtx3bodylabel -{ -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for Decay3Bodys -} // namespace mcfullkfvtx3bodylabel - -DECLARE_SOA_TABLE(McFullKFVtx3BodyLabels, "AOD", "MCFULLKFLABEL", //! Table joinable with Decay3Bodys (CAUTION: NOT WITH Vtx3BodyDATA) - mcfullkfvtx3bodylabel::McParticleId); -using McFullKFVtx3BodyLabel = McFullKFVtx3BodyLabels::iterator; + vtx3body::Px, vtx3body::Py, vtx3body::Pz, + vtx3body::Chi2, + vtx3body::TrackedClSize, + vtx3body::PxTrackPr, vtx3body::PyTrackPr, vtx3body::PzTrackPr, + vtx3body::PxTrackPi, vtx3body::PyTrackPi, vtx3body::PzTrackPi, + vtx3body::PxTrackDe, vtx3body::PyTrackDe, vtx3body::PzTrackDe, + vtx3body::DCAXYTrackPrToPV, vtx3body::DCAXYTrackPiToPV, vtx3body::DCAXYTrackDeToPV, + vtx3body::DCAZTrackPrToPV, vtx3body::DCAZTrackPiToPV, vtx3body::DCAZTrackDeToPV, + vtx3body::DCATrackPrToSV, vtx3body::DCATrackPiToSV, vtx3body::DCATrackDeToSV, + vtx3body::DCAVtxDaughters, + vtx3body::TPCNSigmaPr, vtx3body::TPCNSigmaPi, vtx3body::TPCNSigmaDe, vtx3body::TPCNSigmaPiBach, + vtx3body::TOFNSigmaDe, + vtx3body::ITSClSizePr, vtx3body::ITSClSizePi, vtx3body::ITSClSizeDe, + vtx3body::TPCNClTrackPr, vtx3body::TPCNClTrackPi, vtx3body::TPCNClTrackDe, + vtx3body::PIDTrackingDe, + + // Monte Carlo information + vtx3body::GenPx, vtx3body::GenPy, vtx3body::GenPz, + vtx3body::GenX, vtx3body::GenY, vtx3body::GenZ, + vtx3body::GenCt, + vtx3body::GenPhi, vtx3body::GenEta, vtx3body::GenRap, + vtx3body::GenPPr, vtx3body::GenPPi, vtx3body::GenPDe, + vtx3body::GenPtPr, vtx3body::GenPtPi, vtx3body::GenPtDe, + vtx3body::IsTrueH3L, vtx3body::IsTrueAntiH3L, + vtx3body::IsReco, + vtx3body::PrPdgCode, vtx3body::PiPdgCode, vtx3body::DePdgCode, + vtx3body::IsDePrimary, + vtx3body::IsSurvEvSel, + + // Dynamic columns + vtx3body::P, + vtx3body::Pt, + vtx3body::GenP, + vtx3body::GenPt, + vtx3body::VtxRadius, + vtx3body::GenRadius, + vtx3body::DistOverTotMom, + vtx3body::VtxCosPA, + vtx3body::DCAVtxToPV, + + // Longitudinal + vtx3body::Rap, + vtx3body::Eta, + vtx3body::Phi, + vtx3body::TrackPrPt, + vtx3body::TrackPrEta, + vtx3body::TrackPrPhi, + vtx3body::TrackPiPt, + vtx3body::TrackPiEta, + vtx3body::TrackPiPhi, + vtx3body::TrackDePt, + vtx3body::TrackDeEta, + vtx3body::TrackDePhi); } // namespace o2::aod #endif // PWGLF_DATAMODEL_VTX3BODYTABLES_H_ diff --git a/PWGLF/TableProducer/Nuspex/CMakeLists.txt b/PWGLF/TableProducer/Nuspex/CMakeLists.txt index e8ec0868378..efe21601521 100644 --- a/PWGLF/TableProducer/Nuspex/CMakeLists.txt +++ b/PWGLF/TableProducer/Nuspex/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(decay3bodybuilder SOURCES decay3bodybuilder.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter KFParticle::KFParticle O2Physics::AnalysisCore O2::TOFBase O2Physics::EventFilteringUtils O2::DetectorsVertexing + PUBLIC_LINK_LIBRARIES KFParticle::KFParticle O2Physics::AnalysisCore O2::TOFBase O2Physics::EventFilteringUtils O2::DetectorsVertexing COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hyhefour-builder @@ -59,11 +59,6 @@ o2physics_add_dpl_workflow(threebodymcfinder PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(threebody-reco-task - SOURCES threebodyRecoTask.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore O2Physics::EventFilteringUtils - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(ebye-maker SOURCES ebyeMaker.cxx PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore @@ -79,11 +74,6 @@ o2physics_add_dpl_workflow(pidtof-generic PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(threebody-kf-task - SOURCES threebodyKFTask.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(hypernuclei-kf-reco-task SOURCES hypKfRecoTask.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index e4d05bbacd5..b81ce4eaa30 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -9,10 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// ======================== /// \file decay3bodybuilder.cxx -/// \brief Builder task for 3-body decay reconstruction (p + pion + bachelor) +/// \brief Builder task for 3-body hypertriton decay reconstruction (proton + pion + deuteron) /// \author Yuanzhe Wang -/// \author Carolina Reetz (KFParticle specific part) +/// \author Carolina Reetz +// ======================== + +/// TODO: include likesign analysis here +/// TODO: include possibility to mix 3bodys with opposite B fields #include #include @@ -20,25 +25,19 @@ #include #include #include -#include #include -#include -#include - #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include "DCAFitter/DCAFitterN.h" #include "ReconstructionDataFormats/Track.h" -#include "DetectorsVertexing/SVertexHypothesis.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/Reduced3BodyTables.h" #include "PWGLF/DataModel/Vtx3BodyTables.h" #include "PWGLF/DataModel/pidTOFGeneric.h" +#include "PWGLF/Utils/decay3bodyBuilderHelper.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" #include "Common/Core/PID/PIDTOF.h" @@ -53,8 +52,6 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "DataFormatsCalibration/MeanVertexObject.h" #ifndef HomogeneousField #define HomogeneousField @@ -70,308 +67,205 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using std::array; - -using FullTracksExtIU = soa::Join; -using FullTracksExtPIDIU = soa::Join; - -using ColwithEvTimes = o2::soa::Join; -using ColwithEvTimesMults = o2::soa::Join; -using TrackExtIUwithEvTimes = soa::Join; -using TrackExtPIDIUwithEvTimes = soa::Join; -using MCLabeledTracksIU = soa::Join; +static constexpr int nParameters = 1; +static const std::vector tableNames{ + "Vtx3BodyDatas", + "Vtx3BodyCovs", + "McVtx3BodyDatas"}; -using ReducedCollisionsMults = soa::Join; -using ReducedCollisionsMultsCents = soa::Join; +static constexpr int nTablesConst = 5; -namespace -{ -const float pidCutsLambda[o2::vertexing::SVertexHypothesis::NPIDParams] = {0., 20, 0., 5.0, 0.0, 1.09004e-03, 2.62291e-04, 8.93179e-03, 2.83121}; // Lambda -} // namespace - -struct VtxCandidate { - int track0Id; - int track1Id; - int track2Id; - int collisionId; - int decay3bodyId; - float vtxPos[3]; - float track0P[3]; - float track1P[3]; - float track2P[3]; - float dcadaughters; - float daudcaxytopv[3]; // 0 - proton, 1 - pion, 2 - bachelor - float daudcatopv[3]; // 0 - proton, 1 - pion, 2 - bachelor - float bachelortofNsigma; +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[nTablesConst][nParameters]{ + {0}, // Vtx3BodyDatas + {0}, // Vtx3BodyCovs + {0} // McVtx3BodyDatas }; -struct kfCandidate { - // hypertriton - int collisionID; - int trackPosID; - int trackNegID; - int trackBachID; - int decay3bodyID; - float mass; - float pos[3]; - float posErr[3]; - float mom[4]; - float momErr[4]; - float charge; - float dcaToPV[2]; // 3D, xy - float cpaToPV[2]; // 3D, xy - float cpaToPVtopo[2]; // 3D, xy - float decLen[2]; // 3D, xy - float ldl; - float chi2geoNDF; - float chi2topoNDF; - float ctau; - float trackedClSize; - float DeltaPhiRotDeuteron; - float DeltaPhiRotProton; - // V0 - float massV0; - float chi2massV0; - float cpaV0ToPV; - // daughter momenta - float protonMom[3]; - float pionMom[3]; - float deuteronMom[3]; - float tpcInnerParam[3]; // proton, pion, deuteron - // daughter track quality - int tpcNClDaughters[3]; // proton, pion, deuteron - float tpcChi2NClDeuteron; - // daughter DCAs KF - float DCAdaughterToPV[3]; // proton, pion, deuteron - float DCAdaughterToPVxy[3]; // proton, pion, deuteron - float DCAdaughterToSVxy[3]; // proton, pion, deuteron - float DCAprotonToPion; - float DCAprotonToDeuteron; - float DCApionToDeuteron; - float DCAvtxDaughters3D; - // daughter DCAs to PV propagated with material - float trackDCAxy[3]; // pos, neg, bach - float trackDCA[3]; // pos, neg, bach - // daughter signs - float daughterCharge[3]; // proton, pion, deuteron - // daughter PID - float tpcNsigma[4]; // proton, pion, deuteron, bach with pion hyp - float tpcdEdx[3]; // proton, pion, deuteron - float tofNsigmaDeuteron; - float averageClusterSizeDeuteron; - float pidForTrackingDeuteron; -}; +using TracksExtPIDIUwithEvTimes = soa::Join; +using TracksExtPIDIUwithEvTimesLabeled = soa::Join; -struct decay3bodyBuilder { +using ColswithEvTimes = o2::soa::Join; +using ColswithEvTimesLabeled = o2::soa::Join; - Produces vtx3bodydata; - Produces kfvtx3bodydata; - Produces kfvtx3bodydatalite; - Service ccdb; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - std::vector VtxCandidates; +struct decay3bodyBuilder { - std::unordered_map ccdbCache; // Maps runNumber -> d_bz - std::unordered_map> grpMagCache; // Maps runNumber -> grpmap + // helper object + o2::pwglf::decay3bodyBuilderHelper helper; - Zorro zorro; - OutputObj zorroSummary{"zorroSummary"}; + // table index : match order above + enum tableIndex { kVtx3BodyDatas = 0, + kVtx3BodyCovs, + kMcVtx3BodyDatas, + nTables }; - std::vector fTrackedClSizeVector; + struct : ProducesGroup { + Produces vtx3bodydatas; + Produces vtx3bodycovs; + Produces mcvtx3bodydatas; + } products; - // Configurables - Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; - - enum Hyp3Body { kH3L = 0, - kH4L, - kHe4L, - kHe5L, - kNHyp3body }; - - enum VtxStep { kVtxAll = 0, - kVtxTPCNcls, - kVtxPIDCut, - kVtxhasSV, - kVtxDcaDau, - kVtxCosPA, - kNVtxSteps }; - - enum kfvtxstep { kKfVtxAll = 0, - kKfVtxCharge, - kKfVtxEta, - kKfVtxTPCNcls, - kKfVtxTPCRows, - kKfVtxTPCPID, - kKfVtxDCAxyPV, - kKfVtxDCAzPV, - kKfVtxV0MassConst, - kKfVtxhasSV, - kKfVtxDcaDau, - kKfVtxDcaDauVtx, - kKfVtxDauPt, - kKfVtxRap, - kKfVtxPt, - kKfVtxMass, - kKfVtxCosPA, - kKfVtxCosPAXY, - kKfVtxChi2geo, - kKfVtxTopoConstr, - kKfVtxChi2topo, - kKfNVtxSteps }; - - HistogramRegistry registry{"registry", {}}; - - // hypothesis - Configurable motherhyp{"motherhyp", 0, "hypothesis of the 3body decayed particle"}; // corresponds to Hyp3Body - int bachelorcharge = 1; // to be updated in Init base on the hypothesis - o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init base on the hypothesis - - // Selection criteria - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable mintpcNCls{"mintpcNCls", 70, "min tpc Nclusters"}; - Configurable minCosPA3body{"minCosPA3body", 0.9, "minCosPA3body"}; - Configurable dcavtxdau{"dcavtxdau", 1.0, "DCA Vtx Daughters"}; - Configurable enablePidCut{"enablePidCut", 0, "enable function checkPIDH3L"}; - Configurable TofPidNsigmaMin{"TofPidNsigmaMin", -5, "TofPidNsigmaMin"}; - Configurable TofPidNsigmaMax{"TofPidNsigmaMax", 5, "TofPidNsigmaMax"}; - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - Configurable minBachPUseTOF{"minBachPUseTOF", 1, "minBachP Enable TOF PID"}; + // enablde tables + Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + "Produce this table: 0 - false, 1 - true"}; + std::vector mEnabledTables; // Vector of enabled tables + // general options Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; + Configurable doTrackQA{"doTrackQA", false, "Flag to fill QA histograms for daughter tracks of (selected) decay3body candidates."}; + Configurable doVertexQA{"doVertexQA", false, "Flag to fill QA histograms for PV of (selected) events."}; + Configurable doSel8selection{"doSel8selection", true, "flag for sel8 event selection"}; + Configurable doPosZselection{"doPosZselection", true, "flag for posZ event selection"}; + + // data processing options + Configurable doSkimmedProcessing{"doSkimmedProcessing", false, "Apply Zoroo counting in case of skimmed data input"}; + Configurable triggerList{"triggerList", "fTriggerEventF1Proton, fTrackedOmega, fTrackedXi, fOmegaLargeRadius, fDoubleOmega, fOmegaHighMult, fSingleXiYN, fQuadrupleXi, fDoubleXi, fhadronOmega, fOmegaXi, fTripleXi, fOmega, fGammaVeryLowPtEMCAL, fGammaVeryLowPtDCAL, fGammaHighPtEMCAL, fGammaLowPtEMCAL, fGammaVeryHighPtDCAL, fGammaVeryHighPtEMCAL, fGammaLowPtDCAL, fJetNeutralLowPt, fJetNeutralHighPt, fGammaHighPtDCAL, fJetFullLowPt, fJetFullHighPt, fEMCALReadout, fPCMandEE, fPHOSnbar, fPCMHighPtPhoton, fPHOSPhoton, fLD, fPPPHI, fPD, fLLL, fPLL, fPPL, fPPP, fLeadingPtTrack, fHighFt0cFv0Flat, fHighFt0cFv0Mult, fHighFt0Flat, fHighFt0Mult, fHighMultFv0, fHighTrackMult, fHfSingleNonPromptCharm3P, fHfSingleNonPromptCharm2P, fHfSingleCharm3P, fHfPhotonCharm3P, fHfHighPt2P, fHfSigmaC0K0, fHfDoubleCharm2P, fHfBeauty3P, fHfFemto3P, fHfFemto2P, fHfHighPt3P, fHfSigmaCPPK, fHfDoubleCharm3P, fHfDoubleCharmMix, fHfPhotonCharm2P, fHfV0Charm2P, fHfBeauty4P, fHfV0Charm3P, fHfSingleCharm2P, fHfCharmBarToXiBach, fSingleMuHigh, fSingleMuLow, fLMeeHMR, fDiMuon, fDiElectron, fLMeeIMR, fSingleE, fTrackHighPt, fTrackLowPt, fJetChHighPt, fJetChLowPt, fUDdiffLarge, fUDdiffSmall, fITSextremeIonisation, fITSmildIonisation, fH3L3Body, fHe, fH2", "List of triggers used to select events"}; + Configurable onlyKeepInterestedTrigger{"onlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; + // CCDB options - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - // CCDB TOF PID paras - Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; - Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; - Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; - Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; - Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; - Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; - Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; - // for KFParticle reconstruction struct : ConfigurableGroup { - Configurable cfgSkimmedProcessing{"kfparticleConfigurations.cfgSkimmedProcessing", false, "Flag for skimmed dataset processing"}; - Configurable triggerList{"kfparticleConfigurations.triggerList", "fH3L3Body", "List of triggers used to select events"}; - Configurable cfgOnlyKeepInterestedTrigger{"kfparticleConfigurations.cfgOnlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; - Configurable fillCandidateFullTable{"kfparticleConfigurations.fillCandidateFullTable", false, "Switch to fill full table with candidate properties"}; - Configurable doSel8selection{"kfparticleConfigurations.doSel8selection", true, "flag for sel8 event selection"}; - Configurable doPosZselection{"kfparticleConfigurations.doPosZselection", true, "flag for posZ event selection"}; - Configurable doDCAFitterPreMinimum{"kfparticleConfigurations.doDCAFitterPreMinimum", false, "do DCAFitter pre-optimization before KF fit to include material corrections for decay3body vertex"}; - Configurable doTrackQA{"kfparticleConfigurations.doTrackQA", false, "Flag to fill QA histograms for daughter tracks."}; - Configurable doVertexQA{"kfparticleConfigurations.doVertexQA", false, "Flag to fill QA histograms for KFParticle PV."}; - Configurable useLambdaMassConstraint{"kfparticleConfigurations.useLambdaMassConstraint", false, "Apply Lambda mass constraint on proton-pion vertex"}; - Configurable doDCAPreSel{"kfparticleConfigurations.doDCAPreSel", false, "Apply selection on DCA of daughter tracks to PV"}; - Configurable maxEta{"kfparticleConfigurations.maxEta", 1.0, "Maximum eta for proton and pion daughter tracks"}; - Configurable maxEtaDeuteron{"kfparticleConfigurations.maxEtaDeuteron", 0.9, "Maximum eta for deuteron daughter track"}; - Configurable useTPCforPion{"kfparticleConfigurations.useTPCforPion", true, "Flag to ask for TPC info for pion track (PID, nClusters), false: pion track can be ITS only"}; - Configurable mintpcNClsProton{"kfparticleConfigurations.mintpcNClsProton", 70, "Minimum number of TPC clusters for proton track"}; - Configurable mintpcNClsPion{"kfparticleConfigurations.mintpcNClsPion", 70, "Minimum number of TPC clusters for pion track"}; - Configurable mintpcNClsBach{"kfparticleConfigurations.mintpcNClsBach", 70, "Minimum number of TPC clusters for bachelor track"}; - Configurable mintpcCrossedRows{"kfparticleConfigurations.mintpcCrossedRows", 70, "Minimum number of TPC crossed rows for proton and deuteron track"}; - Configurable mintpcCrossedRowsPion{"kfparticleConfigurations.mintpcCrossedRowsPion", 70, "Minimum number of TPC crossed rows for pion track"}; - Configurable minPtProton{"kfparticleConfigurations.minPtProton", 0.1, "Minimum pT of proton track"}; - Configurable maxPtProton{"kfparticleConfigurations.maxPtProton", 10, "Maximum pT of proton track"}; - Configurable minPtPion{"kfparticleConfigurations.minPtPion", 0.1, "Minimum pT of pion track"}; - Configurable maxPtPion{"kfparticleConfigurations.maxPtPion", 10, "Maximum pT of pion track"}; - Configurable minPtDeuteron{"kfparticleConfigurations.minPtDeuteron", 0.1, "Minimum pT of deuteron track"}; - Configurable maxPtDeuteron{"kfparticleConfigurations.maxPtDeuteron", 10, "Maximum pT of deuteron track"}; - Configurable mindcaXYPionPV{"kfparticleConfigurations.mindcaXYPionPV", 0.1, "Minimum DCA XY of the pion daughter track to the PV"}; - Configurable mindcaXYProtonPV{"kfparticleConfigurations.mindcaXYProtonPV", 0.1, "Minimum DCA XY of the proton daughter track to the PV"}; - Configurable mindcaZPionPV{"kfparticleConfigurations.mindcaZPionPV", 0.1, "Minimum DCA Z of the pion daughter track to the PV"}; - Configurable mindcaZProtonPV{"kfparticleConfigurations.mindcaZProtonPV", 0.1, "Minimum DCA Z of the proton daughter track to the PV"}; - Configurable maxtpcnSigma{"kfparticleConfigurations.maxtpcnSigma", 5., "Maximum nSigma TPC for daughter tracks"}; - Configurable maxDcaProDeu{"kfparticleConfigurations.maxDcaProDeu", 1000., "Maximum geometrical distance between proton and deuteron at the SV in 3D with KFParticle"}; - Configurable maxDcaProPi{"kfparticleConfigurations.maxDcaProPi", 1000., "Maximum geometrical distance between proton and pion at the SV in 3D with KFParticle"}; - Configurable maxDcaPiDe{"kfparticleConfigurations.maxDcaPiDe", 1000., "Maximum geometrical distance between pion and deuteron at the SV in 3D with KFParticle"}; - Configurable maxDcaXYSVDau{"kfparticleConfigurations.maxDcaXYSVDau", 1.0, "Maximum geometrical distance of daughter tracks from the SV in XY with KFParticle"}; - Configurable maxRapidityHt{"kfparticleConfigurations.maxRapidityHt", 1., "Maximum rapidity for Hypertriton candidates with KFParticle"}; - Configurable minPtHt{"kfparticleConfigurations.minPtHt", 0.01, "Minimum momentum for Hypertriton candidates with KFParticle (0.01 applied in SVertexer)"}; - Configurable maxPtHt{"kfparticleConfigurations.maxPtHt", 36., "Maximum momentum for Hypertriton candidates with KFParticle"}; - Configurable minMassHt{"kfparticleConfigurations.minMassHt", 2.96, "Minimum candidate mass with KFParticle"}; - Configurable maxMassHt{"kfparticleConfigurations.maxMassHt", 3.05, "Maximum candidate mass with KFParticle"}; - Configurable maxctauHt{"kfparticleConfigurations.maxctauHt", 40., "Maximum candidate ctau with KFParticle before topological constraint"}; - Configurable maxChi2geo{"kfparticleConfigurations.maxChi2geo", 1000., "Maximum chi2 geometrical with KFParticle"}; - Configurable minCosPA{"kfparticleConfigurations.minCosPA", 0.8, "Minimum cosine pointing angle with KFParticle (0.8 applied in SVertexer)"}; - Configurable minCosPAxy{"kfparticleConfigurations.minCosPAxy", 0.8, "Minimum cosine pointing angle in xy with KFParticle"}; - Configurable applyTopoSel{"kfparticleConfigurations.applyTopoSel", false, "Apply selection constraining the mother to the PV with KFParticle"}; - Configurable maxChi2topo{"kfparticleConfigurations.maxChi2topo", 1000., "Maximum chi2 topological with KFParticle"}; - Configurable nEvtMixing{"kfparticleConfigurations.nEvtMixing", 5, "Number of events to mix"}; - ConfigurableAxis binsVtxZ{"kfparticleConfigurations.binsVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis binsMultiplicity{"kfparticleConfigurations.binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - multiplicity"}; - // 3body mixing - Configurable mixingType{"kfparticleConfigurations.mixingType", 0, "0: mix V0 from one event with bachelor from another, 1: mix pion and bachelor from one event with proton from another "}; - Configurable applySVertexerV0Cuts{"kfparticleConfigurations.applySVertexerV0Cuts", false, "Apply virtual V0 cuts applied in SVertexer in case of proton mixing"}; - ConfigurableAxis bins3BodyRadius{"kfparticleConfigurations.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}, "Mixing bins - 3body radius"}; - // ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f*TMath::Pi()/180, -170.0f*TMath::Pi()/180, -160.0f*TMath::Pi()/180, -150.0f*TMath::Pi()/180, -140.0f*TMath::Pi()/180, -130.0f*TMath::Pi()/180, -120.0f*TMath::Pi()/180, -110.0f*TMath::Pi()/180, -100.0f*TMath::Pi()/180, -90.0f*TMath::Pi()/180, -80.0f*TMath::Pi()/180, -70.0f*TMath::Pi()/180, -60.0f*TMath::Pi()/180, -50.0f*TMath::Pi()/180, -40.0f*TMath::Pi()/180, -30.0f*TMath::Pi()/180, -20.0f*TMath::Pi()/180, -10.0f*TMath::Pi()/180, 0.0f, 10.0f*TMath::Pi()/180, 20.0f*TMath::Pi()/180, 30.0f*TMath::Pi()/180, 40.0f*TMath::Pi()/180, 50.0f*TMath::Pi()/180, 60.0f*TMath::Pi()/180, 70.0f*TMath::Pi()/180, 80.0f*TMath::Pi()/180, 90.0f*TMath::Pi()/180, 100.0f*TMath::Pi()/180, 110.0f*TMath::Pi()/180, 120.0f*TMath::Pi()/180, 130.0f*TMath::Pi()/180, 140.0f*TMath::Pi()/180, 150.0f*TMath::Pi()/180, 160.0f*TMath::Pi()/180, 170.0f*TMath::Pi()/180, 180.0f*TMath::Pi()/180}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPosZ{"kfparticleConfigurations.bins3BodyPosZ", {VARIABLE_WIDTH, -300.0f, -42.0f, -13.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 13.0f, 42.0f, 300.0f}, "Mixing bins - 3body z position"}; - Configurable selectVtxZ3bodyMixing{"kfparticleConfigurations.selectVtxZ3bodyMixing", true, "Select same VtxZ events in case of 3body mixing"}; - Configurable VtxZBin3bodyMixing{"kfparticleConfigurations.VtxZBin3bodyMixing", 1., "Bin width for event vtx z position in case of 3body mixing"}; - } kfparticleConfigurations; - - //------------------------------------------------------------------ - // Sets for DCAFitter event mixing + std::string prefix = "ccdb"; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } ccdbConfigurations; + + // Decay3body building options struct : ConfigurableGroup { - Configurable nUseMixed{"dcaFitterEMSel.nUseMixed", 5, "nUseMixed"}; - Configurable mMinPt2V0{"dcaFitterEMSel.mMinPt2V0", 0.5, "mMinPt2V0"}; // minimum pT^2 of V0 - Configurable mMaxTgl2V0{"dcaFitterEMSel.mMaxTgl2V0", 4, "mMaxTgl2V0"}; // maximum tgLambda^2 of V0 - Configurable mMaxDCAXY2ToMeanVertex3bodyV0{"dcaFitterEMSel.mMaxDCAXY2ToMeanVertex3bodyV0", 4, "mMaxDCAXY2ToMeanVertex3bodyV0"}; // max DCA^2 of 2 body decay to mean vertex of 3 body decay in XY - Configurable minCosPAXYMeanVertex3bodyV0{"dcaFitterEMSel.minCosPAXYMeanVertex3bodyV0", 0.9, "minCosPAXYMeanVertex3bodyV0"}; // min CosPA of 2 body decay to mean vertex of 3 body decay in XY - Configurable minCosPA3bodyV0{"dcaFitterEMSel.minCosPA3bodyV0", 0.8, "minCosPA3bodyV0"}; // min CosPA of 3 body decay to PV - Configurable maxRDiffV03body{"dcaFitterEMSel.maxRDiffV03body", 3, "maxRDiffV03body"}; // Maximum difference between virtual V0 and 3body radius - Configurable minPt3Body = {"dcaFitterEMSel.minPt3Body", 0.01, ""}; // minimum pT of 3body Vertex - Configurable maxTgl3Body = {"dcaFitterEMSel.maxTgl3Body", 2, ""}; // maximum tgLambda of 3body Vertex - Configurable maxDCAXY3Body{"dcaFitterEMSel.maxDCAXY3Body", 0.5, "DCAXY H3L to PV"}; // max DCA of 3 body decay to PV in XY - Configurable maxDCAZ3Body{"dcaFitterEMSel.maxDCAZ3Body", 1.0, "DCAZ H3L to PV"}; // max DCA of 3 body decay to PV in Z - // Binning for mixing events - ConfigurableAxis binsVtxZ{"dcaFitterEMSel.binsVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis binsMultiplicity{"dcaFitterEMSel.binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - multiplicity"}; - Configurable maxDeltaRadiusColMixing{"dcaFitterEMSel.maxDeltaRadiusColMixing", 2., "max difference between pv z position in case of collision mixing"}; - Configurable maxDeltaPhiColMixing{"dcaFitterEMSel.maxDeltaPhiColMixing", 30., "max difference between Phi of monther particle in case of collision mixing (degree)"}; - // Configurations for mixing decay3bodys - // Configurable cfgUseDCAFitterInfo{"dcaFitterEMSel.cfgUseDCAFitterInfo", true, ""}; // if use information from dcatFitter while mixing reduced 3bodys - Configurable cfgMix3BodyMethod{"dcaFitterEMSel.cfgMix3BodyMethod", 0, ""}; // 0: bachelor, 1: pion, 2: proton - Configurable cfgApplyV0Cut{"dcaFitterEMSel.cfgApplyV0Cut", true, "if apply V0 cut while performing event-mixing"}; - ConfigurableAxis bins3BodyRadius{"dcaFitterEMSel.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 2.0f, 4.0f, 7.0f, 10.0f, 14.0f, 18.0f, 22.0f, 30.0f, 40.0f}, "Mixing bins - 3body radius"}; - ConfigurableAxis bins3BodyPhi{"dcaFitterEMSel.bins3BodyPhi", {VARIABLE_WIDTH, -3.15, -2.15, -1, 0, 1, 2.15, 3.15}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPhiDegree{"dcaFitterEMSel.bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPosZ{"dcaFitterEMSel.bins3BodyPosZ", {VARIABLE_WIDTH, -500.0f, -200.0f, -100.0f, -70.0f, -60.0f, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -20.0f, -15.0f, -13.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f, 13.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f, 60.0f, 70.0f, 100.0f, 200.0f, 500.0f}, "3body SV z position"}; - Configurable selectPVPosZ3bodyMixing{"dcaFitterEMSel.selectPVPosZ3bodyMixing", true, "Select same pvPosZ events in case of 3body mixing"}; - Configurable maxDeltaPVPosZ3bodyMixing{"dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing", 1., "max difference between pv z position in case of 3body mixing"}; - } dcaFitterEMSel; - - SliceCache cache; - using BinningTypeColEM = ColumnBinningPolicy; - using Binning3BodyDCAFitter = ColumnBinningPolicy; - using Binning3BodyKFInfo = ColumnBinningPolicy; - - // KF event mixing - using BinningTypeKF = ColumnBinningPolicy; + std::string prefix = "decay3bodyBuilderOpts"; + // building options + Configurable isEventMixing{"isEventMixing", false, "Use event mixing"}; + Configurable useKFParticle{"useKFParticle", false, "Use KFParticle for decay3body building"}; + Configurable kfSetTopologicalConstraint{"kfSetTopologicalConstraint", false, "Set topological vertex constraint in case of KFParticle reconstruction"}; + Configurable useSelections{"useSelections", true, "Apply selections during decay3body building"}; + Configurable useTPCforPion{"useTPCforPion", false, "Flag to ask for TPC info for pion track (PID, nClusters), false: pion track can be ITS only"}; + Configurable acceptTPCOnly{"acceptTPCOnly", false, "Accept TPC only tracks as daughters"}; + Configurable calculateCovariance{"calculateCovariance", true, "Calculate candidate and daughter covariance matrices"}; + // daughter track selections + Configurable maxEtaDaughters{"maxEtaDaughters", 0.9, "Max eta of daughters"}; + Configurable minTPCNClProton{"minTPCNClProton", 90, "Min TPC NClusters of proton daughter"}; + Configurable minTPCNClPion{"minTPCNClPion", 70, "Min TPC NClusters of pion daughter"}; + Configurable minTPCNClDeuteron{"minTPCNClDeuteron", 100, "Min TPC NClusters of deuteron daughter"}; + Configurable minDCAProtonToPV{"minDCAProtonToPV", 0.1, "Min DCA of proton to PV"}; + Configurable minDCAPionToPV{"minDCAPionToPV", 0.1, "Min DCA of pion to PV"}; + Configurable minDCADeuteronToPV{"minDCADeuteronToPV", 0.1, "Min DCA of deuteron to PV"}; + Configurable minPtProton{"minPtProton", 0.3, "Min Pt of proton daughter"}; + Configurable minPtPion{"minPtPion", 0.1, "Min Pt of pion daughter"}; + Configurable minPtDeuteron{"minPtDeuteron", 0.6, "Min Pt of deuteron daughter"}; + Configurable maxPtProton{"maxPtProton", 5.0, "Max Pt of proton daughter"}; + Configurable maxPtPion{"maxPtPion", 1.2, "Max Pt of pion daughter"}; + Configurable maxPtDeuteron{"maxPtDeuteron", 10.0, "Max Pt of deuteron daughter"}; + Configurable maxTPCnSigma{"maxTPCnSigma", 5.0, "Min/max TPC nSigma of daughter tracks"}; + Configurable minTOFnSigmaDeuteron{"minTOFnSigmaDeuteron", -5.0, "Min TOF nSigma of deuteron daughter"}; + Configurable maxTOFnSigmaDeuteron{"maxTOFnSigmaDeuteron", 5.0, "Max TOF nSigma of deuteron daughter"}; + Configurable minPDeuteronUseTOF{"minPDeuteronUseTOF", 1.0, "Min P of deuteron to use TOF PID"}; + Configurable maxDCADauAtSV{"maxDCADauAtSV", 0.5, "Max DCA of daughters at SV (quadratic sum of daughter DCAs between each other)"}; + // candidate selections + Configurable maxRapidity{"maxRapidity", 1.0, "Max rapidity of decay3body vertex"}; + Configurable minPt{"minPt", 2.0, "Min Pt of decay3body candidate"}; + Configurable maxPt{"maxPt", 5.0, "Max Pt of decay3body candidate"}; + Configurable minMass{"minMass", 2.96, "Min mass of decay3body candidate"}; + Configurable maxMass{"maxMass", 3.04, "Max mass of decay3body candidate"}; + Configurable minCtau{"minCtau", 0.0, "Min ctau of decay3body candidate"}; + Configurable maxCtau{"maxCtau", 100.0, "Max ctau of decay3body candidate"}; + Configurable minCosPA{"minCosPA", 0.9, "Min cosPA of decay3body candidate"}; + Configurable maxChi2{"maxChi2", 100.0, "Max chi2 of decay3body candidate"}; + } decay3bodyBuilderOpts; - // 3body mixing - // using Binning3Body = ColumnBinningPolicy; - using Binning3Body = ColumnBinningPolicy; + struct : ConfigurableGroup { + std::string prefix = "mixingOpts"; + Configurable n3bodyMixing{"n3bodyMixing", 0, "Number of decay3bodys to mix: 0 - value set to maximum bin entry in hDecay3BodyRadiusPhi, > 0 - manual setting"}; + Configurable mixingType{"mixingType", 0, "0: mix V0 from one event with bachelor from another, 1: mix pion and bachelor from one event with proton from another, 1: mix proton and bachelor from one event with pion from another "}; + ConfigurableAxis bins3BodyRadius{"bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 2.0f, 4.0f, 7.0f, 10.0f, 14.0f, 18.0f, 22.0f, 30.0f, 40.0f}, "Mixing bins - 3body radius"}; + ConfigurableAxis bins3BodyPhi{"bins3BodyPhi", {VARIABLE_WIDTH, -180 * TMath::Pi() / 180, -120 * TMath::Pi() / 180, -60 * TMath::Pi() / 180, 0, 60 * TMath::Pi() / 180, 120 * TMath::Pi() / 180, 180 * TMath::Pi() / 180}, "Mixing bins - 3body phi (rad)"}; + ConfigurableAxis bins3BodyPhiDegree{"bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi (degree)"}; + ConfigurableAxis bins3BodyPosZ{"bins3BodyPosZ", {VARIABLE_WIDTH, -500.0f, -200.0f, -100.0f, -70.0f, -60.0f, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -20.0f, -15.0f, -13.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f, 13.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f, 60.0f, 70.0f, 100.0f, 200.0f, 500.0f}, "3body SV z position"}; + Configurable selectPVPosZ3bodyMixing{"selectPVPosZ3bodyMixing", true, "Select same pvPosZ events in case of 3body mixing"}; + Configurable maxDeltaPVPosZ3bodyMixing{"maxDeltaPVPosZ3bodyMixing", 1., "max difference between PV z position in case of 3body mixing"}; + // SVertexer selections + Configurable minPt2V0{"minPt2V0", 0.5, "Min Pt squared of V0"}; + Configurable maxTgl2V0{"maxTgl2V0", 4, "Max tgl squared of V0"}; + Configurable maxDCAXY2ToMeanVertex3bodyV0{"maxDCAXY2ToMeanVertex3bodyV0", 4, "Max DCA XY squared of V0 to mean vertex"}; + Configurable minCosPAXYMeanVertex3bodyV0{"minCosPAXYMeanVertex3bodyV0", 0.9, "Min cosPA XY of V0 to mean vertex"}; + Configurable minCosPA3bodyV0{"minCosPA3bodyV0", 0.8, "Min cosPA of V0"}; + Configurable maxRDiffV03body{"maxRDiffV03body", 3, "Max RDiff of V0 to 3body"}; + Configurable minPt3Body{"minPt3Body", 0.5, "Min Pt of 3body"}; + Configurable maxTgl3Body{"maxTgl3Body", 0.01, "Max tgl of 3body"}; + Configurable maxDCAXY3Body{"maxDCAXY3Body", 0.5, "Max DCA XY of 3body"}; + Configurable maxDCAZ3Body{"maxDCAZ3Body", 1.0, "Max DCA Z of 3body"}; + } mixingOpts; - // Filters and slices - Preslice perCollision = o2::aod::decay3body::collisionId; - Preslice perReducedCollision = o2::aod::reduceddecay3body::collisionId; + struct : ConfigurableGroup { + std::string prefix = "tofPIDOpts"; + Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; + Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; + Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; + Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + } tofPIDOpts; + + // Helper struct to contain MC information prior to filling + struct mc3Bodyinfo { + int label; + std::array genDecVtx{0.f}; + std::array genMomentum{0.f}; + float genCt; + float genPhi; + float genEta; + float genRapidity; + float genMomProton; + float genMomPion; + float genMomDeuteron; + float genPtProton; + float genPtPion; + float genPtDeuteron; + bool isTrueH3L; + bool isTrueAntiH3L; + bool isReco; + int daughterPrPdgCode; + int daughterPiPdgCode; + int daughterDePdgCode; + bool isDeuteronPrimary; + bool survivedEventSel; + }; + mc3Bodyinfo this3BodyMCInfo; + // CCDB and magnetic field int mRunNumber; float d_bz; - float maxSnp; // max sine phi for propagation - float maxStep; // max step size (cm) for propagation + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + std::unordered_map ccdbCache; // Maps runNumber -> d_bz + std::unordered_map> grpMagCache; // Maps runNumber -> grpmap o2::base::MatLayerCylSet* lut = nullptr; - o2::vertexing::DCAFitterN<2> fitterV0; - o2::vertexing::DCAFitterN<3> fitter3body; + + // histogram registry + HistogramRegistry registry{"Registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // bachelor TOF PID + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init based on the hypothesis o2::pid::tof::TOFResoParamsV2 mRespParamsV2; - std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda - bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc - o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; + + // 3body mixing + bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc + using Binning3BodyKF = ColumnBinningPolicy; + using Binning3BodyDCAfitter = ColumnBinningPolicy; + + // skimmed processing + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // tracked cluster size + std::vector fTrackedClSizeVector; + + // MC info + std::vector isGoodCollision; void init(InitContext&) { @@ -379,276 +273,240 @@ struct decay3bodyBuilder { mRunNumber = 0; d_bz = 0; - maxSnp = 0.85f; // could be changed later - maxStep = 2.00f; // could be changed later - - // set hypothesis corresponds to Hyp3Body, tpcpid to be implemented - switch (motherhyp) { - case Hyp3Body::kH3L: - bachelorcharge = 1; - bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); - break; - case Hyp3Body::kH4L: - bachelorcharge = 1; - bachelorTOFPID.SetPidType(o2::track::PID::Triton); - break; - case Hyp3Body::kHe4L: - bachelorcharge = 2; - bachelorTOFPID.SetPidType(o2::track::PID::Helium3); - break; - case Hyp3Body::kHe5L: - bachelorcharge = 2; - bachelorTOFPID.SetPidType(o2::track::PID::Alpha); - break; - default: - LOG(fatal) << "Wrong hypothesis for decay3body"; - return; - } - fitterV0.setPropagateToPCA(true); - fitterV0.setMaxR(200.); - fitterV0.setMinParamChange(1e-3); - fitterV0.setMinRelChi2Change(0.9); - fitterV0.setMaxDZIni(1e9); - fitterV0.setMaxChi2(1e9); - fitterV0.setUseAbsDCA(d_UseAbsDCA); - - fitter3body.setPropagateToPCA(true); - fitter3body.setMaxR(200.); //->maxRIni3body - fitter3body.setMinParamChange(1e-3); - fitter3body.setMinRelChi2Change(0.9); - fitter3body.setMaxDZIni(1e9); - fitter3body.setMaxChi2(1e9); - fitter3body.setUseAbsDCA(d_UseAbsDCA); - - // Material correction in the DCA fitter - ccdb->setURL(ccdburl); + mEnabledTables.resize(nTables, 0); + + // CCDB options + ccdb->setURL(ccdbConfigurations.ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + // Set material correction if (useMatCorrType == 1) { LOGF(info, "TGeo correction requested, loading geometry"); if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); + ccdb->get(ccdbConfigurations.geoPath); } + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; } if (useMatCorrType == 2) { LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - } - - // Material correction in the DCA fitter - if (useMatCorrType == 1) - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - if (useMatCorrType == 2) + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbConfigurations.lutPath)); matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - - fitterV0.setMatCorrType(matCorr); - fitter3body.setMatCorrType(matCorr); - - // Add histograms separately for different process functions - if (doprocessRun3 == true || doprocessRun3Reduced) { - registry.add("hEventCounter", "hEventCounter", HistType::kTH1F, {{1, 0.0f, 1.0f}}); - } - - if (doprocessRun3 == true || doprocessRun3Reduced || doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { - auto hVtx3BodyCounter = registry.add("hVtx3BodyCounter", "hVtx3BodyCounter", HistType::kTH1D, {{6, 0.0f, 6.0f}}); - hVtx3BodyCounter->GetXaxis()->SetBinLabel(1, "Total"); - hVtx3BodyCounter->GetXaxis()->SetBinLabel(2, "TPCNcls"); - hVtx3BodyCounter->GetXaxis()->SetBinLabel(3, "PIDCut"); - hVtx3BodyCounter->GetXaxis()->SetBinLabel(4, "HasSV"); - hVtx3BodyCounter->GetXaxis()->SetBinLabel(5, "DcaDau"); - hVtx3BodyCounter->GetXaxis()->SetBinLabel(6, "CosPA"); - registry.add("hBachelorTOFNSigmaDe", "", HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}); - } - - if (doprocessRun3ReducedEM == true) { - registry.add("hEventCount", "hEventCount", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - registry.add("hEventPairs", "hEventPairs", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - registry.add("hDecay3BodyPairsBeforeCut", "hDecay3BodyPairsBeforeCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - registry.add("hDecay3BodyPairsAfterCut", "hDecay3BodyPairsAfterCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - registry.add("hRadius0", "hRadius0", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - registry.add("hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - registry.add("hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{400, -20.0f, 20.0f, "#Delta Radius (cm)"}}); - registry.add("hPhi0", "hPhi0", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); - registry.add("hPhi1", "hPhi1", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); - registry.add("hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, -180.0f, 180.0f, "#Delta #phi (degree)"}}); - } - - if (doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { - registry.add("hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}); - registry.add("hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {dcaFitterEMSel.bins3BodyPosZ}); - auto h3bodyCombinationCounter = registry.add("h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); - h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); - h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "bach sign/ID"); - h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "not same collision"); - h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "collision VtxZ"); - } - - if (doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { - doUpdateGRPMagField = true; - registry.add("h3bodyEMCutCounter", "h3bodyEMCutCounter", HistType::kTH1D, {{14, 0.0f, 14.0f}}); - } - - if (doprocessRun3withKFParticle == true || doprocessRun3withKFParticleStrangenessTracking == true || doprocessRun3withKFParticleReduced == true || doprocessRun3withKFParticleReducedEM == true || doprocessRun3withKFParticleReduced3bodyMixing == true) { - auto hEventCounterZorro = registry.add("Counters/hEventCounterZorro", "hEventCounterZorro", HistType::kTH1D, {{2, -0.5, 1.5}}); - hEventCounterZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); - hEventCounterZorro->GetXaxis()->SetBinLabel(2, "Zorro after evsel"); - auto hEventCounterKFParticle = registry.add("Counters/hEventCounterKFParticle", "hEventCounterKFParticle", HistType::kTH1D, {{4, 0.0f, 4.0f}}); - hEventCounterKFParticle->GetXaxis()->SetBinLabel(1, "total"); - hEventCounterKFParticle->GetXaxis()->SetBinLabel(2, "sel8"); - hEventCounterKFParticle->GetXaxis()->SetBinLabel(3, "vertexZ"); - hEventCounterKFParticle->GetXaxis()->SetBinLabel(4, "has candidate"); - hEventCounterKFParticle->LabelsOption("v"); - auto hVtx3BodyCounterKFParticle = registry.add("Counters/hVtx3BodyCounterKFParticle", "hVtx3BodyCounterKFParticle", HistType::kTH1D, {{21, 0.0f, 21.0f}}); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(1, "Total"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(2, "Charge"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(3, "Eta"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(4, "TPCNcls"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(5, "TPCRows"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(6, "TPCpid"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(7, "DCAxyPV"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(8, "DCAzPV"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(9, "V0MassConst"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(10, "HasSV"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(11, "DcaDau"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(12, "DCADauVtx"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(13, "DauPt"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(14, "Rapidity"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(15, "Pt"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(16, "Mass"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(17, "CosPA"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(18, "CosPAXY"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(19, "Chi2geo"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(20, "TopoConstr"); - hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(21, "Chi2topo"); - hVtx3BodyCounterKFParticle->LabelsOption("v"); - - registry.add("QA/Tracks/hTrackPosTPCNcls", "hTrackPosTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); - registry.add("QA/Tracks/hTrackNegTPCNcls", "hTrackNegTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); - registry.add("QA/Tracks/hTrackBachTPCNcls", "hTrackBachTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); - registry.add("QA/Tracks/hTrackPosHasTPC", "hTrackPosHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); - registry.add("QA/Tracks/hTrackNegHasTPC", "hTrackNegHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); - registry.add("QA/Tracks/hTrackBachHasTPC", "hTrackBachHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); - registry.add("QA/Tracks/hTrackBachITSClusSizes", "hTrackBachITSClusSizes", HistType::kTH1F, {{10, 0., 10., "ITS cluster sizes"}}); - registry.add("QA/Tracks/hTrackProtonTPCPID", "hTrackProtonTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); - registry.add("QA/Tracks/hTrackPionTPCPID", "hTrackPionTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); - registry.add("QA/Tracks/hTrackBachTPCPID", "hTrackBachTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); - registry.add("QA/Tracks/hTrackProtonPt", "hTrackProtonPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); - registry.add("QA/Tracks/hTrackPionPt", "hTrackPionPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); - registry.add("QA/Tracks/hTrackBachPt", "hTrackBachPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); - registry.add("QA/Event/hAllSelEventsVtxZ", "hAllSelEventsVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); - registry.add("QA/Event/hVtxXKF", "hVtxXKF", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV X (cm)"}}); - registry.add("QA/Event/hVtxYKF", "hVtxYKF", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV Y (cm)"}}); - registry.add("QA/Event/hVtxZKF", "hVtxZKF", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); - registry.add("QA/Event/hVtxCovXXKF", "hVtxCovXXKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XX) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovYYKF", "hVtxCovYYKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YY) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovZZKF", "hVtxCovZZKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(ZZ) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovXYKF", "hVtxCovXYKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XY) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovXZKF", "hVtxCovXZKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XZ) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovYZKF", "hVtxCovYZKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); - registry.add("QA/Event/hVtxX", "hVtxX", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV X (cm)"}}); - registry.add("QA/Event/hVtxY", "hVtxY", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV Y (cm)"}}); - registry.add("QA/Event/hVtxZ", "hVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); - registry.add("QA/Event/hVtxCovXX", "hVtxCovXX", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XX) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovYY", "hVtxCovYY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YY) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovZZ", "hVtxCovZZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(ZZ) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovXY", "hVtxCovXY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XY) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovXZ", "hVtxCovXZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XZ) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovYZ", "hVtxCovYZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); } - if (doprocessRun3withKFParticleReducedEM == true) { - registry.add("QA/EM/hPairCounterMixing", "hPairCounterMixing", HistType::kTH1D, {{1, 0.0f, 1.0f}}); - auto hCombinationCounterMixing = registry.add("QA/EM/hCombinationCounterMixing", "hCombinationCounterMixing", HistType::kTH1D, {{3, 0.0f, 3.0f}}); - hCombinationCounterMixing->GetXaxis()->SetBinLabel(1, "total"); - hCombinationCounterMixing->GetXaxis()->SetBinLabel(2, "bach sign/ID"); - hCombinationCounterMixing->GetXaxis()->SetBinLabel(3, "radius, phi"); - hCombinationCounterMixing->LabelsOption("v"); - - registry.add("QA/EM/hEventBinCounts", "hEventBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); - registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); - registry.add("QA/EM/hPairBinCounts", "hPairBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); - - registry.add("QA/EM/hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - registry.add("QA/EM/hRadius2", "hRadius2", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - registry.add("QA/EM/hPhi1", "hPhi1", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); - registry.add("QA/EM/hPhi2", "hPhi2", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); - registry.add("QA/EM/hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{200, 0.0f, 10.0f, "#Delta Radius (cm)"}}); - registry.add("QA/EM/hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, 0.0f, 360.0f, "#Delta #phi (degree)"}}); + helper.fitterV0.setMatCorrType(matCorr); + helper.fitter3body.setMatCorrType(matCorr); + + // set bachelor PID + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + + // set decay3body parameters in the helper + helper.decay3bodyselections.maxEtaDaughters = decay3bodyBuilderOpts.maxEtaDaughters; + helper.decay3bodyselections.minTPCNClProton = decay3bodyBuilderOpts.minTPCNClProton; + helper.decay3bodyselections.minTPCNClPion = decay3bodyBuilderOpts.minTPCNClPion; + helper.decay3bodyselections.minTPCNClDeuteron = decay3bodyBuilderOpts.minTPCNClDeuteron; + helper.decay3bodyselections.minDCAProtonToPV = decay3bodyBuilderOpts.minDCAProtonToPV; + helper.decay3bodyselections.minDCAPionToPV = decay3bodyBuilderOpts.minDCAPionToPV; + helper.decay3bodyselections.minDCADeuteronToPV = decay3bodyBuilderOpts.minDCADeuteronToPV; + helper.decay3bodyselections.minPtProton = decay3bodyBuilderOpts.minPtProton; + helper.decay3bodyselections.minPtPion = decay3bodyBuilderOpts.minPtPion; + helper.decay3bodyselections.minPtDeuteron = decay3bodyBuilderOpts.minPtDeuteron; + helper.decay3bodyselections.maxPtProton = decay3bodyBuilderOpts.maxPtProton; + helper.decay3bodyselections.maxPtPion = decay3bodyBuilderOpts.maxPtPion; + helper.decay3bodyselections.maxPtDeuteron = decay3bodyBuilderOpts.maxPtDeuteron; + helper.decay3bodyselections.maxTPCnSigma = decay3bodyBuilderOpts.maxTPCnSigma; + helper.decay3bodyselections.minTOFnSigmaDeuteron = decay3bodyBuilderOpts.minTOFnSigmaDeuteron; + helper.decay3bodyselections.maxTOFnSigmaDeuteron = decay3bodyBuilderOpts.maxTOFnSigmaDeuteron; + helper.decay3bodyselections.minPDeuteronUseTOF = decay3bodyBuilderOpts.minPDeuteronUseTOF; + helper.decay3bodyselections.maxDCADauAtSV = decay3bodyBuilderOpts.maxDCADauAtSV; + helper.decay3bodyselections.maxRapidity = decay3bodyBuilderOpts.maxRapidity; + helper.decay3bodyselections.minPt = decay3bodyBuilderOpts.minPt; + helper.decay3bodyselections.maxPt = decay3bodyBuilderOpts.maxPt; + helper.decay3bodyselections.minMass = decay3bodyBuilderOpts.minMass; + helper.decay3bodyselections.maxMass = decay3bodyBuilderOpts.maxMass; + helper.decay3bodyselections.minCtau = decay3bodyBuilderOpts.minCtau; + helper.decay3bodyselections.maxCtau = decay3bodyBuilderOpts.maxCtau; + helper.decay3bodyselections.minCosPA = decay3bodyBuilderOpts.minCosPA; + helper.decay3bodyselections.maxChi2 = decay3bodyBuilderOpts.maxChi2; + + // set SVertexer selection parameters in the helper + helper.svertexerselections.minPt2V0 = mixingOpts.minPt2V0; + helper.svertexerselections.maxTgl2V0 = mixingOpts.maxTgl2V0; + helper.svertexerselections.maxDCAXY2ToMeanVertex3bodyV0 = mixingOpts.maxDCAXY2ToMeanVertex3bodyV0; + helper.svertexerselections.minCosPAXYMeanVertex3bodyV0 = mixingOpts.minCosPAXYMeanVertex3bodyV0; + helper.svertexerselections.minCosPA3bodyV0 = mixingOpts.minCosPA3bodyV0; + helper.svertexerselections.maxRDiffV03body = mixingOpts.maxRDiffV03body; + helper.svertexerselections.minPt3Body = mixingOpts.minPt3Body; + helper.svertexerselections.maxTgl3Body = mixingOpts.maxTgl3Body; + helper.svertexerselections.maxDCAXY3Body = mixingOpts.maxDCAXY3Body; + helper.svertexerselections.maxDCAZ3Body = mixingOpts.maxDCAZ3Body; + + // list enabled process functions + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, " Decay3body builder: basic configuration listing"); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + if (doprocessRealData) { + LOGF(info, " ===> process function enabled: processRealData"); + } + if (doprocessRealDataReduced) { + LOGF(info, " ===> process function enabled: processRealDataReduced"); + } + if (doprocessRealDataReduced3bodyMixing) { + LOGF(info, " ===> process function enabled: processRealDataReduced3bodyMixing"); + } + if (doprocessMonteCarlo) { + LOGF(info, " ===> process function enabled: processMonteCarlo"); + } + + // list enabled tables + for (int i = 0; i < nTables; i++) { + if (mEnabledTables[i]) { + LOGF(info, " -~> Table enabled: %s", tableNames[i]); + } + } + + // print base cuts + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, "-~> max daughter eta ..............: %i", decay3bodyBuilderOpts.maxEtaDaughters.value); + LOGF(info, "-~> min TPC ncls proton ...........: %i", decay3bodyBuilderOpts.minTPCNClProton.value); + LOGF(info, "-~> min TPC ncls pion .............: %i", decay3bodyBuilderOpts.minTPCNClPion.value); + LOGF(info, "-~> min TPC ncls bach .............: %i", decay3bodyBuilderOpts.minTPCNClDeuteron.value); + LOGF(info, "-~> min DCA proton to PV ..........: %f", decay3bodyBuilderOpts.minDCAProtonToPV.value); + LOGF(info, "-~> min DCA pion to PV ............: %f", decay3bodyBuilderOpts.minDCAPionToPV.value); + LOGF(info, "-~> min DCA bach to PV ............: %f", decay3bodyBuilderOpts.minDCADeuteronToPV.value); + LOGF(info, "-~> min pT proton .................: %f", decay3bodyBuilderOpts.minPtProton.value); + LOGF(info, "-~> min pT pion ...................: %f", decay3bodyBuilderOpts.minPtPion.value); + LOGF(info, "-~> min pT bach ...................: %f", decay3bodyBuilderOpts.minPtDeuteron.value); + LOGF(info, "-~> max pT proton .................: %f", decay3bodyBuilderOpts.maxPtProton.value); + LOGF(info, "-~> max pT pion ...................: %f", decay3bodyBuilderOpts.maxPtPion.value); + LOGF(info, "-~> max pT bach ...................: %f", decay3bodyBuilderOpts.maxPtDeuteron.value); + LOGF(info, "-~> max TPC nSigma ...............: %f", decay3bodyBuilderOpts.maxTPCnSigma.value); + LOGF(info, "-~> min TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.minTOFnSigmaDeuteron.value); + LOGF(info, "-~> max TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.maxTOFnSigmaDeuteron.value); + LOGF(info, "-~> min p bach use TOF ...........: %f", decay3bodyBuilderOpts.minPDeuteronUseTOF.value); + LOGF(info, "-~> max DCA dau at SV ............: %f", decay3bodyBuilderOpts.maxDCADauAtSV.value); + LOGF(info, "-~> max rapidity .................: %f", decay3bodyBuilderOpts.maxRapidity.value); + LOGF(info, "-~> min pT .......................: %f", decay3bodyBuilderOpts.minPt.value); + LOGF(info, "-~> max pT .......................: %f", decay3bodyBuilderOpts.maxPt.value); + LOGF(info, "-~> min mass .....................: %f", decay3bodyBuilderOpts.minMass.value); + LOGF(info, "-~> max mass .....................: %f", decay3bodyBuilderOpts.maxMass.value); + LOGF(info, "-~> min ctau .....................: %f", decay3bodyBuilderOpts.minCtau.value); + LOGF(info, "-~> max ctau .....................: %f", decay3bodyBuilderOpts.maxCtau.value); + LOGF(info, "-~> min cosPA ....................: %f", decay3bodyBuilderOpts.minCosPA.value); + LOGF(info, "-~> max chi2 .....................: %f", decay3bodyBuilderOpts.maxChi2.value); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + // bookkeeping histograms + auto h = registry.add("hTableBuildingStatistics", "hTableBuildingStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + auto h2 = registry.add("hInputStatistics", "hInputStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + h2->SetTitle("Input table sizes"); + + // configure tables to generate + for (int i = 0; i < nTables; i++) { + h->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); + h2->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); + h->SetBinContent(i + 1, -1); // mark all as disabled to start + + int f = enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + mEnabledTables[i] = 1; + h->SetBinContent(i + 1, 0); // mark enabled + } + } + + if (mEnabledTables[kVtx3BodyDatas] && mEnabledTables[kMcVtx3BodyDatas]) { + LOG(fatal) << "Tables Vtx3BodyDatas and McVtx3BodyDatas cannot both be enabled at the same time. Choose one!"; } - if (doprocessRun3withKFParticleReduced3bodyMixing == true) { - auto h3bodyCombinationCounter = registry.add("QA/EM/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + // Add histograms separately for different process functions + if (doprocessRealData == true || doprocessMonteCarlo == true) { + auto hEventCounter = registry.add("Counters/hEventCounter", "hEventCounter", HistType::kTH1D, {{3, 0.0f, 3.0f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "total"); + hEventCounter->GetXaxis()->SetBinLabel(2, "sel8"); + hEventCounter->GetXaxis()->SetBinLabel(3, "vertexZ"); + hEventCounter->LabelsOption("v"); + } + + if (doprocessRealData == true || doprocessRealDataReduced == true || doprocessMonteCarlo == true) { + if (doTrackQA) { // histograms for all daughter tracks of (selected) 3body candidates + registry.add("QA/Tracks/hTrackProtonTPCNcls", "hTrackProtonTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackPionTPCNcls", "hTrackPionTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackDeuteronTPCNcls", "hTrackDeuteronTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackProtonHasTPC", "hTrackProtonHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackPionHasTPC", "hTrackPionHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackDeuteronHasTPC", "hTrackDeuteronHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackProtonTPCPID", "hTrackProtonTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackPionTPCPID", "hTrackPionTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackDeuteronTPCPID", "hTrackDeuteronTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackProtonPt", "hTrackProtonPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + registry.add("QA/Tracks/hTrackPionPt", "hTrackPionPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + registry.add("QA/Tracks/hTrackDeuteronPt", "hTrackDeuteronPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + } + if (doVertexQA) { + registry.add("QA/Event/hAllSelEventsVtxZ", "hAllSelEventsVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + registry.add("QA/Event/hVtxX", "hVtxX", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV X (cm)"}}); + registry.add("QA/Event/hVtxY", "hVtxY", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV Y (cm)"}}); + registry.add("QA/Event/hVtxZ", "hVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + registry.add("QA/Event/hVtxCovXX", "hVtxCovXX", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XX) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYY", "hVtxCovYY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovZZ", "hVtxCovZZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(ZZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXY", "hVtxCovXY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXZ", "hVtxCovXZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYZ", "hVtxCovYZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); + } + } + + if (doprocessRealDataReduced3bodyMixing == true) { + auto h3bodyCombinationCounter = registry.add("EM/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "not same collision"); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "collision VtxZ"); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "bach sign/ID"); h3bodyCombinationCounter->LabelsOption("v"); - // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH3D, {{16, 0, 16, "bins radius"}, {36, 0, 36, "bins phi"}, {12, 0, 12, "bins pos Z"}}); - registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{16, 0, 16, "bins radius"}, {18, 0, 18, "bins phi"}}); - - AxisSpec radiusAxis = {kfparticleConfigurations.bins3BodyRadius, "Radius (cm)"}; - AxisSpec phiAxis = {kfparticleConfigurations.bins3BodyPhi, "#phi (degree)"}; - AxisSpec posZAxis = {kfparticleConfigurations.bins3BodyPosZ, "position in z (cm)"}; + registry.add("EM/hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}); + registry.add("EM/hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {mixingOpts.bins3BodyPosZ}); + } - registry.add("QA/EM/hRadius", "hRadius", HistType::kTH1F, {radiusAxis}); - registry.add("QA/EM/hPhi", "hPhi", HistType::kTH1F, {phiAxis}); - registry.add("QA/EM/hPosZ", "hPosZ", HistType::kTH1F, {posZAxis}); + if (doprocessRealDataReduced == true || doprocessRealDataReduced3bodyMixing == true) { + doUpdateGRPMagField = true; } } - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + template + bool initCCDB(aod::BCsWithTimestamps const& bcs, TCollisions const& collisions) { - if (mRunNumber == bc.runNumber()) { - return; + auto bc = collisions.size() ? collisions.begin().template bc_as() : bcs.begin(); + if (!bcs.size()) { + LOGF(warn, "No BC found, skipping this DF."); + return false; // signal to skip this DF } - if (kfparticleConfigurations.cfgSkimmedProcessing) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), kfparticleConfigurations.triggerList); - zorro.populateHistRegistry(registry, bc.runNumber()); + + if (mRunNumber == bc.runNumber()) { + return true; } - // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { - d_bz = d_bz_input; - fitterV0.setBz(d_bz); - fitter3body.setBz(d_bz); -#ifdef HomogeneousField - KFParticle::SetField(d_bz); -#endif - o2::parameters::GRPMagField grpmag; - if (std::fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = bc.runNumber(); - return; + if (doSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + zorro.populateHistRegistry(registry, bc.runNumber()); } - auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + auto timestamp = bc.timestamp(); o2::parameters::GRPMagField* grpmag = 0x0; - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - // Fetch magnetic field from ccdb for current collision - // d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - d_bz = o2::base::Propagator::Instance()->getNominalBz(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } - mRunNumber = bc.runNumber(); - // Set magnetic field value once known - fitterV0.setBz(d_bz); - fitter3body.setBz(d_bz); + grpmag = ccdb->getForTimeStamp(ccdbConfigurations.grpmagPath, timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + auto d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << d_bz << " kG"; + + // set magnetic field value for DCA fitter + helper.fitterV0.setBz(d_bz); + helper.fitter3body.setBz(d_bz); // Set magnetic field for KF vertexing #ifdef HomogeneousField KFParticle::SetField(d_bz); @@ -657,68 +515,76 @@ struct decay3bodyBuilder { if (useMatCorrType == 2) { // setMatLUT only after magfield has been initalized // (setMatLUT has implicit and problematic init field call if not) + LOG(info) << "Loading material look-up table for timestamp: " << timestamp; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); o2::base::Propagator::Instance()->setMatLUT(lut); + helper.lut = lut; } + // mark run as configured + mRunNumber = bc.runNumber(); + // Initial TOF PID Paras, copied from PIDTOF.h - timestamp.value = bc.timestamp(); - ccdb->setTimestamp(timestamp.value); + tofPIDOpts.timestamp.value = bc.timestamp(); + ccdb->setTimestamp(tofPIDOpts.timestamp.value); // Not later than now objects ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); // TODO: implement the automatic pass name detection from metadata - if (passName.value == "") { - passName.value = "unanchored"; // temporary default - LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << passName.value << "'"; + if (tofPIDOpts.passName.value == "") { + tofPIDOpts.passName.value = "unanchored"; // temporary default + LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << tofPIDOpts.passName.value << "'"; } - LOG(info) << "Using parameter collection, starting from pass '" << passName.value << "'"; + LOG(info) << "Using parameter collection, starting from pass '" << tofPIDOpts.passName.value << "'"; - const std::string fname = paramFileName.value; + const std::string fname = tofPIDOpts.paramFileName.value; if (!fname.empty()) { // Loading the parametrization from file - LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << parametrizationPath.value; + LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << tofPIDOpts.parametrizationPath.value; if (1) { o2::tof::ParameterCollection paramCollection; - paramCollection.loadParamFromFile(fname, parametrizationPath.value); + paramCollection.loadParamFromFile(fname, tofPIDOpts.parametrizationPath.value); LOG(info) << "+++ Loaded parameter collection from file +++"; - if (!paramCollection.retrieveParameters(mRespParamsV2, passName.value)) { - if (fatalOnPassNotAvailable) { - LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + if (!paramCollection.retrieveParameters(mRespParamsV2, tofPIDOpts.passName.value)) { + if (tofPIDOpts.fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); } else { - LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); } } else { - mRespParamsV2.setShiftParameters(paramCollection.getPars(passName.value)); + mRespParamsV2.setShiftParameters(paramCollection.getPars(tofPIDOpts.passName.value)); mRespParamsV2.printShiftParameters(); } } else { - mRespParamsV2.loadParamFromFile(fname.data(), parametrizationPath.value); + mRespParamsV2.loadParamFromFile(fname.data(), tofPIDOpts.parametrizationPath.value); } - } else if (loadResponseFromCCDB) { // Loading it from CCDB - LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << parametrizationPath.value << " for timestamp " << timestamp.value; - o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(parametrizationPath.value, timestamp.value); + } else if (tofPIDOpts.loadResponseFromCCDB) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << tofPIDOpts.parametrizationPath.value << " for timestamp " << tofPIDOpts.timestamp.value; + o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(tofPIDOpts.parametrizationPath.value, tofPIDOpts.timestamp.value); paramCollection->print(); - if (!paramCollection->retrieveParameters(mRespParamsV2, passName.value)) { // Attempt at loading the parameters with the pass defined - if (fatalOnPassNotAvailable) { - LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + if (!paramCollection->retrieveParameters(mRespParamsV2, tofPIDOpts.passName.value)) { // Attempt at loading the parameters with the pass defined + if (tofPIDOpts.fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); } else { - LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); } } else { // Pass is available, load non standard parameters - mRespParamsV2.setShiftParameters(paramCollection->getPars(passName.value)); + mRespParamsV2.setShiftParameters(paramCollection->getPars(tofPIDOpts.passName.value)); mRespParamsV2.printShiftParameters(); } } mRespParamsV2.print(); - if (timeShiftCCDBPath.value != "") { - if (timeShiftCCDBPath.value.find(".root") != std::string::npos) { - mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Pos", true); - mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Neg", false); + if (tofPIDOpts.timeShiftCCDBPath.value != "") { + if (tofPIDOpts.timeShiftCCDBPath.value.find(".root") != std::string::npos) { + mRespParamsV2.setTimeShiftParameters(tofPIDOpts.timeShiftCCDBPath.value, "gmean_Pos", true); + mRespParamsV2.setTimeShiftParameters(tofPIDOpts.timeShiftCCDBPath.value, "gmean_Neg", false); } else { - mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", timeShiftCCDBPath.value.c_str()), timestamp.value), true); - mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", timeShiftCCDBPath.value.c_str()), timestamp.value), false); + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", tofPIDOpts.timeShiftCCDBPath.value.c_str()), tofPIDOpts.timestamp.value), true); + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", tofPIDOpts.timeShiftCCDBPath.value.c_str()), tofPIDOpts.timestamp.value), false); } } bachelorTOFPID.SetParams(mRespParamsV2); + + return true; } void initCCDBfromRunNumber(int runNumber) @@ -738,9 +604,9 @@ struct decay3bodyBuilder { o2::base::Propagator::initFieldFromGRP(grpMagCache[runNumber].get()); } } else { - std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(grpmagPath, runNumber)); + std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(ccdbConfigurations.grpmagPath, runNumber)); if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for run number " << runNumber; + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.grpPath << " of object GRPObject for run number " << runNumber; } o2::base::Propagator::initFieldFromGRP(grpmag.get()); // Fetch magnetic field from ccdb for current collision @@ -752,15 +618,13 @@ struct decay3bodyBuilder { } // Set magnetic field for KF vertexing + /// TODO: KF field has to be set in the helper class where KF is used!! --> really? #ifdef HomogeneousField KFParticle::SetField(d_bz); #endif // Set field for DCAfitter - fitterV0.setBz(d_bz); - fitter3body.setBz(d_bz); - - mV0Hyps[0].set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, d_bz); - mV0Hyps[1].set(o2::track::PID::Lambda, o2::track::PID::Pion, o2::track::PID::Proton, pidCutsLambda, d_bz); + helper.fitterV0.setBz(d_bz); + helper.fitter3body.setBz(d_bz); if (useMatCorrType == 2) { // setMatLUT only after magfield has been initalized @@ -771,1739 +635,748 @@ struct decay3bodyBuilder { ccdbCache[runNumber] = d_bz; } - //------------------------------------------------------------------ - //-------------------- DCA fitter reconstruction ------------------- - //------------------------------------------------------------------ - // Select decay3body candidate based on daughter track PID - template - bool checkPID(TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackBachelor, const double& tofNSigmaBach) - { - if ((tofNSigmaBach < TofPidNsigmaMin || tofNSigmaBach > TofPidNsigmaMax) && trackBachelor.p() > minBachPUseTOF) { - return false; - } - if (std::abs(trackProton.tpcNSigmaPr()) > TpcPidNsigmaCut) { - return false; - } - if (std::abs(trackPion.tpcNSigmaPi()) > TpcPidNsigmaCut) { - return false; - } - return true; - } - // PID check for H3L - template - bool checkPIDH3L(TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackBachelor, const double& tofNSigmaBach) + // ______________________________________________________________ + // function to calculate correct TOF nSigma for deuteron track + template + double getTOFnSigma(TCollision const& collision, TTrack const& track) { - if ((std::abs(trackBachelor.tpcNSigmaDe()) > TpcPidNsigmaCut) || !checkPID(trackProton, trackPion, trackBachelor, tofNSigmaBach)) { - return false; + // TOF PID of deuteron + double tofNsigmaDeuteron = -999; + if (track.has_collision() && track.hasTOF()) { + auto originalcol = track.template collision_as(); + tofNsigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); } - return true; + return tofNsigmaDeuteron; } - //------------------------------------------------------------------ - // 3body candidate builder - template - void fillVtxCand(TCollisionTable const& collision, TTrackTable const& t0, TTrackTable const& t1, TTrackTable const& t2, int64_t decay3bodyId, int bachelorcharge = 1, double tofNSigmaBach = -999, bool saveInTable = true) + // ______________________________________________________________ + // function to build decay3body candidates + template + void buildCandidates(TBCs const&, + TCollisions const& collisions, + T3Bodys const& decay3bodys, + TMCParticles const& mcParticles, + TMCCollisions const& mcCollisions) { - registry.fill(HIST("hVtx3BodyCounter"), kVtxAll); - - if (t0.tpcNClsFound() < mintpcNCls || t1.tpcNClsFound() < mintpcNCls || t2.tpcNClsFound() < mintpcNCls) { - return; - } - registry.fill(HIST("hVtx3BodyCounter"), kVtxTPCNcls); - - if (enablePidCut) { - if (t2.sign() > 0) { - if (!checkPIDH3L(t0, t1, t2, tofNSigmaBach)) - return; - } else { - if (!checkPIDH3L(t1, t0, t2, tofNSigmaBach)) - return; - } + if (!(mEnabledTables[kVtx3BodyDatas] || mEnabledTables[kMcVtx3BodyDatas])) { + return; // don't do if no request for decay3bodys in place } - registry.fill(HIST("hVtx3BodyCounter"), kVtxPIDCut); - - // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; + // prepare MC containers (not necessarily used) + std::vector mc3BodyInfos; // Decay3bodyMCCore information + std::vector mcParticleIsReco; - auto Track0Par = getTrackPar(t0); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track0Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track0dcaXY = dcaInfo[0]; - auto Track0dca = std::sqrt(Track0dcaXY * Track0dcaXY + dcaInfo[1] * dcaInfo[1]); - - auto Track1Par = getTrackPar(t1); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track1Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track1dcaXY = dcaInfo[0]; - auto Track1dca = std::sqrt(Track1dcaXY * Track1dcaXY + dcaInfo[1] * dcaInfo[1]); - - auto Track2Par = getTrackPar(t2); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track2Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track2dcaXY = dcaInfo[0]; - auto Track2dca = std::sqrt(Track2dcaXY * Track2dcaXY + dcaInfo[1] * dcaInfo[1]); - - auto Track0 = getTrackParCov(t0); - auto Track1 = getTrackParCov(t1); - auto Track2 = getTrackParCov(t2); - int n3bodyVtx = fitter3body.process(Track0, Track1, Track2); - if (n3bodyVtx == 0) { // discard this pair - return; + // clear and reserve size for MC info vectors + if constexpr (soa::is_table) { + isGoodCollision.resize(mcCollisions.size(), false); + mcParticleIsReco.resize(mcParticles.size(), false); } - registry.fill(HIST("hVtx3BodyCounter"), kVtxhasSV); - std::array pos = {0.}; - const auto& vtxXYZ = fitter3body.getPCACandidate(); - for (int i = 0; i < 3; i++) { - pos[i] = vtxXYZ[i]; - } + // Loop over collisions for vertex QA + for (const auto& collision : collisions) { + if constexpr (soa::is_table) { // only do if NOT running over reduced data (already done in reducedCreator) + // Zorro event counting + bool isZorroSelected = false; + if (doSkimmedProcessing) { + isZorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); + if (!isZorroSelected && onlyKeepInterestedTrigger) { + continue; + } + } - std::array p0 = {0.}, p1 = {0.}, p2{0.}; - const auto& propagatedTrack0 = fitter3body.getTrack(0); - const auto& propagatedTrack1 = fitter3body.getTrack(1); - const auto& propagatedTrack2 = fitter3body.getTrack(2); - propagatedTrack0.getPxPyPzGlo(p0); - propagatedTrack1.getPxPyPzGlo(p1); - propagatedTrack2.getPxPyPzGlo(p2); - for (int i = 0; i < 3; i++) { - p2[i] *= bachelorcharge; + // event counting + registry.fill(HIST("Counters/hEventCounter"), 0.5); + if (doSel8selection && !collision.sel8()) { + continue; + } + registry.fill(HIST("Counters/hEventCounter"), 1.5); + if (doPosZselection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; + } + registry.fill(HIST("Counters/hEventCounter"), 2.5); + } + + // vertex QA and counting + if (doVertexQA) { + registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); + registry.fill(HIST("QA/Event/hVtxX"), collision.posX()); + registry.fill(HIST("QA/Event/hVtxY"), collision.posY()); + registry.fill(HIST("QA/Event/hVtxZ"), collision.posZ()); + registry.fill(HIST("QA/Event/hVtxCovXX"), collision.covXX()); + registry.fill(HIST("QA/Event/hVtxCovYY"), collision.covYY()); + registry.fill(HIST("QA/Event/hVtxCovZZ"), collision.covZZ()); + registry.fill(HIST("QA/Event/hVtxCovXY"), collision.covXY()); + registry.fill(HIST("QA/Event/hVtxCovXZ"), collision.covXZ()); + registry.fill(HIST("QA/Event/hVtxCovYZ"), collision.covYZ()); + } + + // In case of MC: reco collision survived event selection filter --> fill value for MC collision if collision is "true" MC collision + if constexpr (soa::is_table) { + if (collision.mcCollisionId() >= 0) { + isGoodCollision[collision.mcCollisionId()] = true; + } + } } - std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; - if (fitter3body.getChi2AtPCACandidate() > dcavtxdau) { - return; - } - registry.fill(HIST("hVtx3BodyCounter"), kVtxDcaDau); + int nDecay3Bodys = 0; - float VtxcosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{pos[0], pos[1], pos[2]}, std::array{p3B[0], p3B[1], p3B[2]}); - if (VtxcosPA < minCosPA3body) { - return; - } - registry.fill(HIST("hVtx3BodyCounter"), kVtxCosPA); - registry.fill(HIST("hBachelorTOFNSigmaDe"), t2.sign() * t2.p(), tofNSigmaBach); - - // additional cut for EM - if (decay3bodyId == -1) { - registry.fill(HIST("h3bodyEMCutCounter"), 0.5); - auto v0Track0 = getTrackParCov(t0); - auto v0Track1 = getTrackParCov(t1); - int nV0 = fitterV0.process(v0Track0, v0Track1); - if (nV0 == 0) { + // Loop over all decay3bodys in same time frame + registry.fill(HIST("hInputStatistics"), kVtx3BodyDatas, decay3bodys.size()); + int lastRunNumber = -1; + for (const auto& decay3body : decay3bodys) { + // skip decay3body without assigned collision + /// TODO: do we want this?? + if (decay3body.collisionId() < 0) { return; } - registry.fill(HIST("h3bodyEMCutCounter"), 1.5); - std::array v0pos = {0.}; - const auto& v0vtxXYZ = fitterV0.getPCACandidate(); - for (int i = 0; i < 3; i++) { - v0pos[i] = v0vtxXYZ[i]; - } - const int cand = 0; - if (!fitterV0.isPropagateTracksToVertexDone(cand) && !fitterV0.propagateTracksToVertex(cand)) { - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 2.5); - - const auto& trPProp = fitterV0.getTrack(0, cand); - const auto& trNProp = fitterV0.getTrack(1, cand); - std::array pP{}, pN{}; - trPProp.getPxPyPzGlo(pP); - trNProp.getPxPyPzGlo(pN); - std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; - // Cut for Virtual V0 - float dxv0 = v0pos[0] - mMeanVertex.getX(), dyv0 = v0pos[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; - float rv0 = std::sqrt(r2v0); - float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; - if (dcaFitterEMSel.cfgApplyV0Cut && pt2V0 <= dcaFitterEMSel.mMinPt2V0) { - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 3.5); - if (dcaFitterEMSel.cfgApplyV0Cut && pV0[2] * pV0[2] / pt2V0 > dcaFitterEMSel.mMaxTgl2V0) { // tgLambda cut - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 4.5); - - float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); - // apply mass selections - 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]; - bool good3bodyV0Hyp = false; - for (int ipid = 0; ipid < 2; ipid++) { - float massForLambdaHyp = mV0Hyps[ipid].calcMass(p2Pos, p2Neg, p2V0); - if (massForLambdaHyp - mV0Hyps[ipid].getMassV0Hyp() < mV0Hyps[ipid].getMargin(ptV0)) { - good3bodyV0Hyp = true; - break; + // aquire collision + auto const& collision = collisions.rawIteratorAt(decay3body.collisionId()); + + // initialise CCDB from run number saved in reduced collisions table when running over reduced data + if constexpr (!soa::is_table) { // only do if running over reduced data (otherwise CCDB is initialised in process function) + if (collision.runNumber() != lastRunNumber) { + initCCDBfromRunNumber(collision.runNumber()); + lastRunNumber = collision.runNumber(); // Update the last run number + LOG(debug) << "CCDB initialized for run " << lastRunNumber; } } - if (dcaFitterEMSel.cfgApplyV0Cut && !good3bodyV0Hyp) { - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 5.5); - float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; - float cosPAXY = prodXYv0 / rv0 * ptV0; - if (dcaFitterEMSel.cfgApplyV0Cut && dca2 > dcaFitterEMSel.mMaxDCAXY2ToMeanVertex3bodyV0) { - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 6.5); - // FIXME: V0 cosPA cut to be investigated - if (dcaFitterEMSel.cfgApplyV0Cut && cosPAXY < dcaFitterEMSel.minCosPAXYMeanVertex3bodyV0) { - return; + // event selection + if constexpr (soa::is_table) { + if (doSel8selection && !collision.sel8()) { // only when NOT running over reduced data + continue; + } } - registry.fill(HIST("h3bodyEMCutCounter"), 7.5); - // Check: CosPA Cut of Virtual V0 may not be used since the V0 may be based on another PV - float dx = v0pos[0] - collision.posX(), dy = v0pos[1] - collision.posY(), dz = v0pos[2] - collision.posZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; - float v0CosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); - if (dcaFitterEMSel.cfgApplyV0Cut && v0CosPA < dcaFitterEMSel.minCosPA3bodyV0) { - return; + if (doPosZselection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; } - registry.fill(HIST("h3bodyEMCutCounter"), 8.5); - float r3body = std::hypot(pos[0], pos[1]); - if (r3body < 0.5) { - return; + // aquire tracks + auto trackPos = decay3body.template track0_as(); + auto trackNeg = decay3body.template track1_as(); + auto trackDeuteron = decay3body.template track2_as(); + auto trackProton = trackPos; + auto trackPion = trackNeg; + if (trackDeuteron.sign() < 0) { + trackProton = trackNeg; + trackPion = trackPos; + } + + // get deuteron TOF PID + float tofNSigmaDeuteron; + if constexpr (!soa::is_table) { + tofNSigmaDeuteron = trackDeuteron.tofNSigmaDe(); + } else if constexpr (soa::is_table) { + tofNSigmaDeuteron = getTOFnSigma(collision, trackDeuteron); + } + + /// build Decay3body candidate + if (!helper.buildDecay3BodyCandidate(collision, + trackProton, + trackPion, + trackDeuteron, + decay3body.globalIndex(), + tofNSigmaDeuteron, + fTrackedClSizeVector[decay3body.globalIndex()], + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + decay3bodyBuilderOpts.isEventMixing)) { + continue; } - registry.fill(HIST("h3bodyEMCutCounter"), 9.5); + nDecay3Bodys++; + + // fill QA histograms + if (doTrackQA) { // histograms filled for daughter tracks of (selected) 3body candidates + registry.fill(HIST("QA/Tracks/hTrackProtonTPCNcls"), trackProton.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCNcls"), trackPion.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronTPCNcls"), trackDeuteron.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackProtonHasTPC"), trackProton.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackPionHasTPC"), trackPion.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronHasTPC"), trackDeuteron.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronITSClusSizes"), trackDeuteron.itsClusterSizes()); + registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackProton.sign() * trackProton.tpcInnerParam(), trackProton.tpcNSigmaPr()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackPion.sign() * trackPion.tpcInnerParam(), trackPion.tpcNSigmaPi()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronTPCPID"), trackDeuteron.sign() * trackDeuteron.tpcInnerParam(), trackDeuteron.tpcNSigmaDe()); + registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackProton.pt()); + registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackPion.pt()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronPt"), trackDeuteron.pt()); + } + + // generate analysis tables with current candidate (only Vtx3BodyDatas is filled here, McVtx3BodyDatas table is filled later) + if (!mEnabledTables[kMcVtx3BodyDatas]) { + fillAnalysisTables(); + } + + // ___________________________________________________________ + // MC handling part: matching of reconstructed candidates + // ___________________________________________________________ + // fill MC table with reco MC candidate information and gen information if matched to MC particle + if constexpr (soa::is_table) { + // MC info + resetMCInfo(this3BodyMCInfo); + this3BodyMCInfo.isReco = true; + + // check if daughters have MC particle + if (!trackProton.has_mcParticle() || !trackPion.has_mcParticle() || !trackDeuteron.has_mcParticle()) { + continue; + } - // Cut for the compatibility of V0 and 3body vertex - float deltaR = std::abs(rv0 - r3body); - if (deltaR > dcaFitterEMSel.maxRDiffV03body) { - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 10.5); + // get MC daughter particles + auto mcTrackProton = trackProton.template mcParticle_as(); + auto mcTrackPion = trackPion.template mcParticle_as(); + auto mcTrackDeuteron = trackDeuteron.template mcParticle_as(); + + // set daughter MC info (also for non-matched candidates) + this3BodyMCInfo.daughterPrPdgCode = mcTrackProton.pdgCode(); + this3BodyMCInfo.daughterPiPdgCode = mcTrackPion.pdgCode(); + this3BodyMCInfo.daughterDePdgCode = mcTrackDeuteron.pdgCode(); + this3BodyMCInfo.isDeuteronPrimary = mcTrackDeuteron.isPhysicalPrimary(); + this3BodyMCInfo.genMomProton = mcTrackProton.p(); + this3BodyMCInfo.genMomPion = mcTrackPion.p(); + this3BodyMCInfo.genMomDeuteron = mcTrackDeuteron.p(); + this3BodyMCInfo.genPtProton = mcTrackProton.pt(); + this3BodyMCInfo.genPtPion = mcTrackPion.pt(); + this3BodyMCInfo.genPtDeuteron = mcTrackDeuteron.pt(); + + // check if reco mother is true H3L/Anti-H3l + bool isMuonReco; + int motherID = checkH3LTruth(mcTrackProton, mcTrackPion, mcTrackDeuteron, isMuonReco); + + // get generated mother MC info + if (motherID > 0) { + auto mcTrackH3L = mcParticles.rawIteratorAt(motherID); + int chargeFactor = mcTrackH3L.pdgCode() > 0 ? 1 : -1; + this3BodyMCInfo.label = motherID; + this3BodyMCInfo.genMomentum = {mcTrackH3L.px(), mcTrackH3L.py(), mcTrackH3L.pz()}; + this3BodyMCInfo.genDecVtx = {mcTrackProton.vx(), mcTrackProton.vy(), mcTrackProton.vz()}; + this3BodyMCInfo.genCt = RecoDecay::sqrtSumOfSquares(mcTrackProton.vx() - mcTrackH3L.vx(), mcTrackProton.vy() - mcTrackH3L.vy(), mcTrackProton.vz() - mcTrackH3L.vz()) * o2::constants::physics::MassHyperTriton / mcTrackH3L.p(); + this3BodyMCInfo.genPhi = mcTrackH3L.phi(); + this3BodyMCInfo.genEta = mcTrackH3L.eta(); + this3BodyMCInfo.genRapidity = mcTrackH3L.y(); + this3BodyMCInfo.isTrueH3L = chargeFactor > 0; + this3BodyMCInfo.isTrueAntiH3L = chargeFactor < 0; + } - float pt3B = std::hypot(p3B[0], p3B[1]); - if (pt3B < dcaFitterEMSel.minPt3Body) { // pt cut - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 11.5); - if (p3B[2] / pt3B > dcaFitterEMSel.maxTgl3Body) { // tgLambda cut - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 12.5); - - // H3L DCA Check - const auto& vertexXYZ = fitter3body.getPCACandidatePos(); - auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, t2.sign()); - o2::dataformats::DCA dca; - if (!track3B.propagateToDCA({{collision.posX(), collision.posY(), collision.posZ()}, {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}}, fitter3body.getBz(), &dca, 5.) || - std::abs(dca.getY()) > dcaFitterEMSel.maxDCAXY3Body || std::abs(dca.getZ()) > dcaFitterEMSel.maxDCAZ3Body) { - return; - } - registry.fill(HIST("h3bodyEMCutCounter"), 13.5); - } + // fill analysis tables (only McVtx3BodyDatas is filled here) + fillAnalysisTables(); - VtxCandidate candVtx; - candVtx.track0Id = t0.globalIndex(); - candVtx.track1Id = t1.globalIndex(); - candVtx.track2Id = t2.globalIndex(); - candVtx.collisionId = collision.globalIndex(); - candVtx.decay3bodyId = decay3bodyId; - candVtx.vtxPos[0] = pos[0]; - candVtx.vtxPos[1] = pos[1]; - candVtx.vtxPos[2] = pos[2]; - candVtx.track0P[0] = p0[0]; - candVtx.track0P[1] = p0[1]; - candVtx.track0P[2] = p0[2]; - candVtx.track1P[0] = p1[0]; - candVtx.track1P[1] = p1[1]; - candVtx.track1P[2] = p1[2]; - candVtx.track2P[0] = p2[0]; - candVtx.track2P[1] = p2[1]; - candVtx.track2P[2] = p2[2]; - candVtx.dcadaughters = fitter3body.getChi2AtPCACandidate(); - candVtx.daudcaxytopv[0] = Track0dcaXY; - candVtx.daudcaxytopv[1] = Track1dcaXY; - candVtx.daudcaxytopv[2] = Track2dcaXY; - candVtx.daudcatopv[0] = Track0dca; - candVtx.daudcatopv[1] = Track1dca; - candVtx.daudcatopv[2] = Track2dca; - candVtx.bachelortofNsigma = tofNSigmaBach; - if (saveInTable) { - fillVtx3BodyTable(candVtx); - } else { - VtxCandidates.push_back(candVtx); - } + // mark mcParticle as reconstructed + if (this3BodyMCInfo.label > -1) { + mcParticleIsReco[this3BodyMCInfo.label] = true; + } + } // constexpr requires mcParticles check + } // decay3body loop + + // ____________________________________________________________________ + // MC handling part: generated information of non-reco candidates + // ____________________________________________________________________ + if constexpr (soa::is_table) { + for (auto& mcparticle : mcParticles) { + // MC info + resetMCInfo(this3BodyMCInfo); + this3BodyMCInfo.isReco = false; + + // skip MC particle if reconstructed and already filled previously + if (mcParticleIsReco[mcparticle.globalIndex()] == true) { + continue; + } + + // set flag if corresponding MC collision has matched reconstructed collision which passed event selection + this3BodyMCInfo.survivedEventSel = isGoodCollision[mcparticle.mcCollisionId()]; + + // check if MC particle is hypertriton + if (std::abs(mcparticle.pdgCode()) != 1010010030) { + continue; + } + + // check daughter identities + bool haveProton = false, havePion = false, haveDeuteron = false; + bool haveAntiProton = false, haveAntiPion = false, haveAntiDeuteron = false; + for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (mcparticleDaughter.pdgCode() == PDG_t::kProton) + haveProton = true; + if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) + haveAntiProton = true; + if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) + havePion = true; + if (mcparticleDaughter.pdgCode() == PDG_t::kPiMinus) + haveAntiPion = true; + if (mcparticleDaughter.pdgCode() == 1000010020) + haveDeuteron = true; + if (mcparticleDaughter.pdgCode() == -1000010020) + haveAntiDeuteron = true; + } + + // check if hypertriton decayed via 3-body decay and is particle or anti-particle + if ((haveProton && haveAntiPion && haveDeuteron) || (haveAntiProton && havePion && haveAntiDeuteron)) { + if (mcparticle.pdgCode() > 0) { + this3BodyMCInfo.isTrueH3L = true; + } else if (mcparticle.pdgCode() < 0) { + this3BodyMCInfo.isTrueAntiH3L = true; + } + // get daughters + for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (abs(mcparticleDaughter.pdgCode()) == PDG_t::kProton) { // proton + this3BodyMCInfo.genMomProton = mcparticleDaughter.p(); + this3BodyMCInfo.genPtProton = mcparticleDaughter.pt(); + this3BodyMCInfo.daughterPrPdgCode = mcparticleDaughter.pdgCode(); + this3BodyMCInfo.genDecVtx = {mcparticleDaughter.vx(), mcparticleDaughter.vy(), mcparticleDaughter.vz()}; + } else if (abs(mcparticleDaughter.pdgCode()) == PDG_t::kPiPlus) { // pion + this3BodyMCInfo.genMomPion = mcparticleDaughter.p(); + this3BodyMCInfo.genPtPion = mcparticleDaughter.pt(); + this3BodyMCInfo.daughterPiPdgCode = mcparticleDaughter.pdgCode(); + } else if (std::abs(mcparticleDaughter.pdgCode()) == 1000010020) { // deuteron + this3BodyMCInfo.genMomDeuteron = mcparticleDaughter.p(); + this3BodyMCInfo.genPtDeuteron = mcparticleDaughter.pt(); + this3BodyMCInfo.daughterDePdgCode = mcparticleDaughter.pdgCode(); + this3BodyMCInfo.isDeuteronPrimary = mcparticleDaughter.isPhysicalPrimary(); + } + } + } else { + continue; // stop if particle is not decayed via 3-body decay + } + + // calculate ctau + this3BodyMCInfo.genCt = RecoDecay::sqrtSumOfSquares(this3BodyMCInfo.genDecVtx[0] - mcparticle.vx(), this3BodyMCInfo.genDecVtx[1] - mcparticle.vy(), this3BodyMCInfo.genDecVtx[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); + + // fill MCDecay3BodyCores table if requested + if (mEnabledTables[kMcVtx3BodyDatas]) { + products.mcvtx3bodydatas(-1, // sign + -1., -1., // mass, massV0 + -1., -1., -1., // position + -1., -1., -1., // momentum + -1., // chi2 + -1., // trackedClSize + -1., -1., -1., // momProton + -1., -1., -1., // momPion + -1., -1., -1., // momDeuteron + -1., -1., -1., // trackDCAxyToPV: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // trackDCAzToPV: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // daughterDCAtoSV: 0 - proton, 1 - pion, 2 - deuteron + -1., // daughterDCAatSV + -1., -1., -1., -1., // tpcNsigma: 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + -1., // tofNsigmaDeuteron + -1., -1., -1., // average ITS cluster sizes: proton, pion, deuteron + -1., -1., -1., // TPCNCl: proton, pion, deuteron + -1., // pidForTrackingDeuteron + // MC information + mcparticle.px(), mcparticle.py(), mcparticle.pz(), + this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], + this3BodyMCInfo.genCt, + mcparticle.phi(), mcparticle.eta(), mcparticle.y(), + this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, + this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, + this3BodyMCInfo.isReco, + this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, + this3BodyMCInfo.isDeuteronPrimary, + this3BodyMCInfo.survivedEventSel); + } // enabled table check + } // mcParticles loop + } // constexpr requires mcParticles check } - //------------------------------------------------------------------ - // event mixing - template - void doMixed3Body(TMixed3bodys decay3bodys, TBinningType binningType) + + // ______________________________________________________________ + // function to build mixed decay3body candidates + template + void buildMixedCandidates(TRedDecay3Bodys const& decay3bodys, TBinningType const& binningType) { + if (!mEnabledTables[kVtx3BodyDatas]) { + return; // don't do if no request for decay3bodys in place + } + // Strictly upper index policy for decay3body objects binned by radius, phi - for (const auto& [decay3body0, decay3body1] : selfCombinations(binningType, dcaFitterEMSel.nUseMixed, -1, decay3bodys, decay3bodys)) { - auto tpos0 = decay3body0.template track0_as(); - auto tneg0 = decay3body0.template track1_as(); - auto tbach0 = decay3body0.template track2_as(); - auto tpos1 = decay3body1.template track0_as(); - auto tneg1 = decay3body1.template track1_as(); - auto tbach1 = decay3body1.template track2_as(); + for (const auto& [decay3body0, decay3body1] : selfPairCombinations(binningType, mixingOpts.n3bodyMixing, -1, decay3bodys)) { + auto trackPos0 = decay3body0.template track0_as(); + auto trackNeg0 = decay3body0.template track1_as(); + auto trackDeuteron0 = decay3body0.template track2_as(); + auto trackPos1 = decay3body1.template track0_as(); + auto trackNeg1 = decay3body1.template track1_as(); + auto trackDeuteron1 = decay3body1.template track2_as(); registry.fill(HIST("h3bodyCombinationCounter"), 0.5); - // ---------- selections ---------- - if ((tbach0.sign() > 0 && !(tbach1.sign() > 0)) || (tbach0.sign() < 0 && !(tbach1.sign() < 0)) || tbach0.globalIndex() == tbach1.globalIndex()) { // only combine if tbach1 has correct sign and is not same as tbach0 + // only combine if from different event + if (decay3body0.collisionId() == decay3body1.collisionId()) { continue; } - registry.fill(HIST("h3bodyCombinationCounter"), 1.5); + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 1.5); - if (decay3body0.collisionId() == decay3body1.collisionId()) { // only combine if from different event + // collision vertex selection + auto collision0 = decay3body0.template collision_as(); + auto collision1 = decay3body1.template collision_as(); + initCCDBfromRunNumber(collision0.runNumber()); + initCCDBfromRunNumber(collision1.runNumber()); + + // only combine if collision similar in VtxZ + if (mixingOpts.selectPVPosZ3bodyMixing && std::abs(collision0.posZ() - collision1.posZ()) > mixingOpts.maxDeltaPVPosZ3bodyMixing) { continue; } - registry.fill(HIST("h3bodyCombinationCounter"), 2.5); - - auto c0 = decay3body0.template collision_as(); - auto c1 = decay3body1.template collision_as(); + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 2.5); - if (dcaFitterEMSel.selectPVPosZ3bodyMixing && std::abs(c0.posZ() - c1.posZ()) > dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing) { // only combine if collision similar in PV posZ + // selections + if ((trackDeuteron0.sign() > 0 && !(trackDeuteron1.sign() > 0)) || (trackDeuteron0.sign() < 0 && !(trackDeuteron1.sign() < 0)) || trackDeuteron0.globalIndex() == trackDeuteron1.globalIndex()) { // only combine if trackDeuteron1 has correct sign and is not same as trackDeuteron0 continue; } - registry.fill(HIST("h3bodyCombinationCounter"), 3.5); - - initCCDBfromRunNumber(c0.runNumber()); - - if (dcaFitterEMSel.cfgMix3BodyMethod == 0) { // mix bachelor (deuteron) - fillVtxCand(c0, tpos0, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); - fillVtxCand(c1, tpos1, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); - } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() > 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() < 0)) { // mix piMinus or proton - fillVtxCand(c0, tpos0, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); - fillVtxCand(c1, tpos1, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); - } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() < 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() > 0)) { // mix piPlus or anti-proton - fillVtxCand(c0, tpos1, tneg0, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); - fillVtxCand(c1, tpos0, tneg1, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); - } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); - VtxCandidates.clear(); + // assign tracks + auto trackProton0 = trackPos0; + auto trackPion0 = trackNeg0; + auto trackProton1 = trackPos1; + auto trackPion1 = trackNeg1; + if (trackDeuteron0.sign() < 0) { + trackProton0 = trackNeg0; + trackPion0 = trackPos0; + } + if (trackDeuteron1.sign() < 0) { + trackProton1 = trackNeg1; + trackPion1 = trackPos1; + } + + // candidate analysis + // mix deuteron + if (mixingOpts.mixingType == 0) { + if (helper.buildDecay3BodyCandidate(collision0, trackProton0, trackPion0, trackDeuteron1, + -1 /*decay3bodyIndex*/, + trackDeuteron1.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + true /*isEventMixing*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + } + if (helper.buildDecay3BodyCandidate(collision0, trackProton1, trackPion1, trackDeuteron0, + -1 /*decay3bodyIndex*/, + trackDeuteron0.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + true /*isEventMixing*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + } + // mix proton + } else if (mixingOpts.mixingType == 1) { + if (helper.buildDecay3BodyCandidate(collision0, trackProton1, trackPion0, trackDeuteron0, + -1 /*decay3bodyIndex*/, + trackDeuteron0.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + true /*isEventMixing*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + } + if (helper.buildDecay3BodyCandidate(collision0, trackProton0, trackPion1, trackDeuteron1, + -1 /*decay3bodyIndex*/, + trackDeuteron1.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + true /*isEventMixing*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + } + // mix pion + } else if (mixingOpts.mixingType == 2) { + if (helper.buildDecay3BodyCandidate(collision0, trackProton0, trackPion1, trackDeuteron0, + -1 /*decay3bodyIndex*/, + trackDeuteron0.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + true /*isEventMixing*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + } + if (helper.buildDecay3BodyCandidate(collision0, trackProton1, trackPion0, trackDeuteron1, + -1 /*decay3bodyIndex*/, + trackDeuteron1.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + true /*isEventMixing*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + } + } } // end decay3body combinations loop } - //------------------------------------------------------------------ - // fill the StoredVtx3BodyDatas table - void fillVtx3BodyTable(VtxCandidate const& candVtx) + + // ______________________________________________________________ + // function to fill analysis tables + void fillAnalysisTables() { - vtx3bodydata( - candVtx.track0Id, candVtx.track1Id, candVtx.track2Id, candVtx.collisionId, candVtx.decay3bodyId, - candVtx.vtxPos[0], candVtx.vtxPos[1], candVtx.vtxPos[2], - candVtx.track0P[0], candVtx.track0P[1], candVtx.track0P[2], candVtx.track1P[0], candVtx.track1P[1], candVtx.track1P[2], candVtx.track2P[0], candVtx.track2P[1], candVtx.track2P[2], - candVtx.dcadaughters, - candVtx.daudcaxytopv[0], candVtx.daudcaxytopv[1], candVtx.daudcaxytopv[2], - candVtx.daudcatopv[0], candVtx.daudcatopv[1], candVtx.daudcatopv[2], - candVtx.bachelortofNsigma); + // generate analysis tables + if (mEnabledTables[kVtx3BodyDatas]) { + products.vtx3bodydatas(helper.decay3body.sign, + helper.decay3body.mass, helper.decay3body.massV0, + helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], + helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], + helper.decay3body.chi2, + helper.decay3body.trackedClSize, + helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], + helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], + helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], + helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAzToPV[0], helper.decay3body.trackDCAzToPV[1], helper.decay3body.trackDCAzToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAatSV, + helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + helper.decay3body.tofNsigmaDeuteron, + helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.pidForTrackingDeuteron); + registry.fill(HIST("hTableBuildingStatistics"), kVtx3BodyDatas); + } + if (mEnabledTables[kVtx3BodyCovs]) { + products.vtx3bodycovs(helper.decay3body.covProton, + helper.decay3body.covPion, + helper.decay3body.covDeuteron, + helper.decay3body.covariance); + registry.fill(HIST("hTableBuildingStatistics"), kVtx3BodyCovs); + } + if (mEnabledTables[kMcVtx3BodyDatas]) { + products.mcvtx3bodydatas(helper.decay3body.sign, + helper.decay3body.mass, helper.decay3body.massV0, + helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], + helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], + helper.decay3body.chi2, + helper.decay3body.trackedClSize, + helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], + helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], + helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], + helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAzToPV[0], helper.decay3body.trackDCAzToPV[1], helper.decay3body.trackDCAzToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAatSV, + helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + helper.decay3body.tofNsigmaDeuteron, + helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.pidForTrackingDeuteron, + // MC information + this3BodyMCInfo.genMomentum[0], this3BodyMCInfo.genMomentum[1], this3BodyMCInfo.genMomentum[2], + this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], + this3BodyMCInfo.genCt, + this3BodyMCInfo.genPhi, this3BodyMCInfo.genEta, this3BodyMCInfo.genRapidity, + this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, + this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, + this3BodyMCInfo.isReco, + this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, + this3BodyMCInfo.isDeuteronPrimary, + this3BodyMCInfo.survivedEventSel); + registry.fill(HIST("hTableBuildingStatistics"), kMcVtx3BodyDatas); + } } - //------------------------------------------------------------------ - //-------------------- KFParticle reconstruction ------------------- - //------------------------------------------------------------------ - // function to select daughter track PID - template - bool selectTPCPID(TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackDeuteron) + // ______________________________________________________________ + // function to check if a reconstructed mother is a true H3L/Anti-H3L (returns -1 if not) + template + int checkH3LTruth(MCTrack3B const& mcParticlePr, MCTrack3B const& mcParticlePi, MCTrack3B const& mcParticleDe, bool& isMuonReco) { - if (std::abs(trackProton.tpcNSigmaPr()) > kfparticleConfigurations.maxtpcnSigma) { - return false; + if (abs(mcParticlePr.pdgCode()) != 2212 || abs(mcParticleDe.pdgCode()) != 1000010020) { + return -1; + } + // check proton and deuteron mother + int prDeMomID = -1; + for (const auto& motherPr : mcParticlePr.template mothers_as()) { + for (const auto& motherDe : mcParticleDe.template mothers_as()) { + if (motherPr.globalIndex() == motherDe.globalIndex() && std::abs(motherPr.pdgCode()) == 1010010030) { + prDeMomID = motherPr.globalIndex(); + break; + } + } } - if (std::abs(trackDeuteron.tpcNSigmaDe()) > kfparticleConfigurations.maxtpcnSigma) { - return false; + if (prDeMomID == -1) { + return -1; } - if (kfparticleConfigurations.useTPCforPion && std::abs(trackPion.tpcNSigmaPi()) > kfparticleConfigurations.maxtpcnSigma) { - return false; + if (std::abs(mcParticlePi.pdgCode()) != 211 && std::abs(mcParticlePi.pdgCode()) != 13) { + return -1; } - return true; - } - - template - double getTOFnSigma(TCollision const& collision, TTrack const& track, bool isEventMixing) - { - // TOF PID of deuteron (set motherhyp correctly) - double tofNSigmaDeuteron = -999; - if (track.has_collision() && track.hasTOF()) { - if (isEventMixing) { - tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, collision, collision); - } else { - auto originalcol = track.template collision_as(); - tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); + // check if the pion track is a muon coming from a pi -> mu + vu decay, if yes, take the mother pi + auto mcParticlePiTmp = mcParticlePi; + if (std::abs(mcParticlePiTmp.pdgCode()) == 13) { + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (std::abs(motherPi.pdgCode()) == 211) { + mcParticlePiTmp = motherPi; + isMuonReco = true; + break; + } + } + } + // now loop over the pion mother + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (motherPi.globalIndex() == prDeMomID) { + return motherPi.globalIndex(); } } - return tofNSigmaDeuteron; + return -1; } - //------------------------------------------------------------------ - // function to fill candidate table - template - void fillCandidateTable(TCandidate const& candidate) + // ______________________________________________________________ + // function to reset MCInfo + void resetMCInfo(mc3Bodyinfo mcInfo) { - kfvtx3bodydatalite( - // hypertriton - candidate.mass, - candidate.pos[0], candidate.pos[1], candidate.pos[2], - candidate.mom[0], candidate.mom[1], candidate.mom[2], candidate.mom[3], - candidate.charge, - candidate.dcaToPV[0], candidate.dcaToPV[1], // 3D, xy - candidate.cpaToPV[0], candidate.cpaToPV[1], // 3D, xy - candidate.decLen[0], candidate.decLen[1], // 3D, xy - candidate.ldl, - candidate.chi2geoNDF, candidate.chi2topoNDF, - candidate.ctau, - candidate.trackedClSize, - // V0 - candidate.massV0, - candidate.cpaV0ToPV, - // daughter momenta at vertex - candidate.protonMom[0], candidate.protonMom[1], candidate.protonMom[2], - candidate.pionMom[0], candidate.pionMom[1], candidate.pionMom[2], - candidate.deuteronMom[0], candidate.deuteronMom[1], candidate.deuteronMom[2], - candidate.tpcInnerParam[0], candidate.tpcInnerParam[1], candidate.tpcInnerParam[2], // proton, pion, deuteron - // daughter track quality - candidate.tpcNClDaughters[0], candidate.tpcNClDaughters[1], candidate.tpcNClDaughters[2], // proton, pion, deuteron - candidate.tpcChi2NClDeuteron, - candidate.DeltaPhiRotDeuteron, candidate.DeltaPhiRotProton, - // daughter DCAs KF - candidate.DCAdaughterToPV[0], candidate.DCAdaughterToPV[1], candidate.DCAdaughterToPV[2], // proton, pion, deuteron - candidate.DCAdaughterToPVxy[0], candidate.DCAdaughterToPVxy[1], candidate.DCAdaughterToPVxy[2], // proton, pion, deuteron - candidate.DCAdaughterToSVxy[0], candidate.DCAdaughterToSVxy[1], candidate.DCAdaughterToSVxy[2], // proton, pion, deuteron - candidate.DCAprotonToPion, candidate.DCAprotonToDeuteron, candidate.DCApionToDeuteron, - candidate.DCAvtxDaughters3D, - // daughter signs - candidate.daughterCharge[0], candidate.daughterCharge[1], candidate.daughterCharge[2], // proton, pion, deuteron - // daughter PID - candidate.tpcNsigma[0], candidate.tpcNsigma[1], candidate.tpcNsigma[2], candidate.tpcNsigma[3], // proton, pion, deuteron, bach with pion hyp - candidate.tofNsigmaDeuteron, - candidate.averageClusterSizeDeuteron, - candidate.pidForTrackingDeuteron); - - if (kfparticleConfigurations.fillCandidateFullTable) { - kfvtx3bodydata( - candidate.collisionID, candidate.trackPosID, candidate.trackNegID, candidate.trackBachID, candidate.decay3bodyID, - // hypertriton - candidate.mass, - candidate.pos[0], candidate.pos[1], candidate.pos[2], - candidate.posErr[0], candidate.posErr[1], candidate.posErr[2], - candidate.mom[0], candidate.mom[1], candidate.mom[2], candidate.mom[3], - candidate.momErr[0], candidate.momErr[1], candidate.momErr[2], candidate.momErr[3], - candidate.charge, - candidate.dcaToPV[0], candidate.dcaToPV[1], // 3D, xy - candidate.cpaToPV[0], candidate.cpaToPV[1], // 3D, xy - candidate.cpaToPVtopo[0], candidate.cpaToPVtopo[1], // 3D, xy - candidate.decLen[0], candidate.decLen[1], // 3D, xy - candidate.ldl, - candidate.chi2geoNDF, candidate.chi2topoNDF, - candidate.ctau, - candidate.trackedClSize, - // V0 - candidate.massV0, candidate.chi2massV0, - candidate.cpaV0ToPV, - // daughter momenta (at vertex and TPC) - candidate.protonMom[0], candidate.protonMom[1], candidate.protonMom[2], - candidate.pionMom[0], candidate.pionMom[1], candidate.pionMom[2], - candidate.deuteronMom[0], candidate.deuteronMom[1], candidate.deuteronMom[2], - candidate.tpcInnerParam[0], candidate.tpcInnerParam[1], candidate.tpcInnerParam[2], // proton, pion, deuteron - // daughter track quality - candidate.tpcNClDaughters[0], candidate.tpcNClDaughters[1], candidate.tpcNClDaughters[2], // proton, pion, deuteron - candidate.tpcChi2NClDeuteron, - candidate.DeltaPhiRotDeuteron, candidate.DeltaPhiRotProton, - // daughter DCAs KF - candidate.DCAdaughterToPV[0], candidate.DCAdaughterToPV[1], candidate.DCAdaughterToPV[2], // proton, pion, deuteron - candidate.DCAdaughterToPVxy[0], candidate.DCAdaughterToPVxy[1], candidate.DCAdaughterToPVxy[2], // proton, pion, deuteron - candidate.DCAdaughterToSVxy[0], candidate.DCAdaughterToSVxy[1], candidate.DCAdaughterToSVxy[2], // proton, pion, deuteron - candidate.DCAprotonToPion, candidate.DCAprotonToDeuteron, candidate.DCApionToDeuteron, - candidate.DCAvtxDaughters3D, - // daughter DCAs to PV propagated with material - candidate.trackDCAxy[0], candidate.trackDCAxy[1], candidate.trackDCAxy[2], // pos, neg, bach - candidate.trackDCA[0], candidate.trackDCA[1], candidate.trackDCA[2], // pos, neg, bach - // daughter signs - candidate.daughterCharge[0], candidate.daughterCharge[1], candidate.daughterCharge[2], // proton, pion, deuteron - // daughter PID - candidate.tpcNsigma[0], candidate.tpcNsigma[1], candidate.tpcNsigma[2], candidate.tpcNsigma[3], // proton, pion, deuteron, bach with pion hyp - candidate.tpcdEdx[0], candidate.tpcdEdx[1], candidate.tpcdEdx[2], // proton, pion, deuteron - candidate.tofNsigmaDeuteron, - candidate.averageClusterSizeDeuteron, - candidate.pidForTrackingDeuteron); - } - LOG(debug) << "Table filled."; + mcInfo.label = -1; + mcInfo.genMomentum[0] = -1., mcInfo.genMomentum[1] = -1., mcInfo.genMomentum[2] = -1.; + mcInfo.genDecVtx[0] = -1., mcInfo.genDecVtx[1] = -1., mcInfo.genDecVtx[2] = -1.; + mcInfo.genCt = -1.; + mcInfo.genPhi = -1., mcInfo.genEta = -1., mcInfo.genRapidity = -1.; + mcInfo.genMomProton = -1., mcInfo.genMomPion = -1., mcInfo.genMomDeuteron = -1.; + mcInfo.genPtProton = -1., mcInfo.genPtPion = -1., mcInfo.genPtDeuteron = -1.; + mcInfo.isTrueH3L = false, mcInfo.isTrueAntiH3L = false; + mcInfo.isReco = false; + mcInfo.daughterPrPdgCode = -1, mcInfo.daughterPiPdgCode = -1, mcInfo.daughterDePdgCode = -1; + mcInfo.isDeuteronPrimary = false; + mcInfo.survivedEventSel = false; } - //------------------------------------------------------------------ - // function to fit KFParticle 3body vertex - template - void fit3bodyVertex(TKFParticle& kfpProton, TKFParticle& kfpPion, TKFParticle& kfpDeuteron, TKFParticle& KFHt) + // ______________________________________________________________ + // process functions + void processRealData(ColswithEvTimes const& collisions, + aod::Decay3Bodys const& decay3bodys, + aod::Tracked3Bodys const& tracked3bodys, + TracksExtPIDIUwithEvTimes const&, + aod::BCsWithTimestamps const& bcs) { - // Construct 3body vertex - int nDaughters3body = 3; - const KFParticle* Daughters3body[3] = {&kfpProton, &kfpPion, &kfpDeuteron}; - KFHt.SetConstructMethod(2); - try { - KFHt.Construct(Daughters3body, nDaughters3body); - } catch (std::runtime_error& e) { - LOG(debug) << "Failed to create Hyper triton 3-body vertex." << e.what(); + // initialise CCDB from BCs + if (!initCCDB(bcs, collisions)) { return; } - // transport all daughter tracks to hypertriton vertex - float HtVtx[3] = {0.}; - HtVtx[0] = KFHt.GetX(); - HtVtx[1] = KFHt.GetY(); - HtVtx[2] = KFHt.GetZ(); - kfpProton.TransportToPoint(HtVtx); - kfpPion.TransportToPoint(HtVtx); - kfpDeuteron.TransportToPoint(HtVtx); - LOG(debug) << "Hypertriton vertex constructed."; + + // get tracked cluster size info + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); + } + + // do candidate analysis without MC processing + buildCandidates(bcs, // bc table + collisions, // collision table + decay3bodys, // decay3body table + static_cast(nullptr), // MC particle table + static_cast(nullptr)); // MC collision table } - //------------------------------------------------------------------ - // 3body candidate builder with KFParticle - template - void buildVtx3BodyDataTableKFParticle(TCollision const& collision, TTrack const& trackPos, TTrack const& trackNeg, TTrack const& trackBach, int64_t decay3bodyID, int bachelorcharge, double tofNSigmaDeuteron) + void processRealDataReduced(aod::RedCollisions const& collisions, + soa::Join const& decay3bodys, + aod::RedIUTracks const&) { - gROOT->SetBatch(true); - gRandom->SetSeed(42); - - // initialise KF primary vertex - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - KFParticle kfpv(kfpVertex); - LOG(debug) << "Created KF PV."; - - // fill event QA histograms --> only for events with a decay3body! - if (kfparticleConfigurations.doVertexQA) { - registry.fill(HIST("QA/Event/hVtxXKF"), kfpv.GetX()); - registry.fill(HIST("QA/Event/hVtxYKF"), kfpv.GetY()); - registry.fill(HIST("QA/Event/hVtxZKF"), kfpv.GetZ()); - registry.fill(HIST("QA/Event/hVtxCovXXKF"), kfpv.GetCovariance(0)); - registry.fill(HIST("QA/Event/hVtxCovYYKF"), kfpv.GetCovariance(2)); - registry.fill(HIST("QA/Event/hVtxCovZZKF"), kfpv.GetCovariance(5)); - registry.fill(HIST("QA/Event/hVtxCovXYKF"), kfpv.GetCovariance(1)); - registry.fill(HIST("QA/Event/hVtxCovXZKF"), kfpv.GetCovariance(3)); - registry.fill(HIST("QA/Event/hVtxCovYZKF"), kfpv.GetCovariance(4)); - registry.fill(HIST("QA/Event/hVtxX"), collision.posX()); - registry.fill(HIST("QA/Event/hVtxY"), collision.posY()); - registry.fill(HIST("QA/Event/hVtxZ"), collision.posZ()); - registry.fill(HIST("QA/Event/hVtxCovXX"), collision.covXX()); - registry.fill(HIST("QA/Event/hVtxCovYY"), collision.covYY()); - registry.fill(HIST("QA/Event/hVtxCovZZ"), collision.covZZ()); - registry.fill(HIST("QA/Event/hVtxCovXY"), collision.covXY()); - registry.fill(HIST("QA/Event/hVtxCovXZ"), collision.covXZ()); - registry.fill(HIST("QA/Event/hVtxCovYZ"), collision.covYZ()); + // get tracked cluster size info (saved in aod::Red3BodyInfo) + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& vtx3body : decay3bodys) { + fTrackedClSizeVector[vtx3body.globalIndex()] = vtx3body.trackedClSize(); } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxAll); - - auto trackParCovPos = getTrackParCov(trackPos); - auto trackParCovNeg = getTrackParCov(trackNeg); - auto trackParCovBach = getTrackParCov(trackBach); - LOG(debug) << "Got all daughter tracks."; - - bool isMatter = trackBach.sign() > 0 ? true : false; - - // ---------- fill track QA histograms ---------- - if (kfparticleConfigurations.doTrackQA) { - registry.fill(HIST("QA/Tracks/hTrackPosTPCNcls"), trackPos.tpcNClsFound()); - registry.fill(HIST("QA/Tracks/hTrackNegTPCNcls"), trackNeg.tpcNClsFound()); - registry.fill(HIST("QA/Tracks/hTrackBachTPCNcls"), trackBach.tpcNClsFound()); - registry.fill(HIST("QA/Tracks/hTrackPosHasTPC"), trackPos.hasTPC()); - registry.fill(HIST("QA/Tracks/hTrackNegHasTPC"), trackNeg.hasTPC()); - registry.fill(HIST("QA/Tracks/hTrackBachHasTPC"), trackBach.hasTPC()); - registry.fill(HIST("QA/Tracks/hTrackBachITSClusSizes"), trackBach.itsClusterSizes()); - if (isMatter) { - registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPr()); - registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPi()); - registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackPos.pt()); - registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackNeg.pt()); + // do candidate analysis without MC processing + buildCandidates(static_cast(nullptr), // bc table + collisions, // collision table + decay3bodys, // decay3body table + static_cast(nullptr), // MC particle table + static_cast(nullptr)); // MC collision table + } + + void processRealDataReduced3bodyMixing(aod::RedCollisions const&, + soa::Join const& decay3bodys, + aod::RedIUTracks const&) + { + auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); + auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); + + for (const auto& decay3body : decay3bodys) { + int bin_Radius, bin_Phi; + if (decay3bodyBuilderOpts.useKFParticle) { + bin_Radius = xAxis->FindBin(decay3body.radiusKF()); + bin_Phi = yAxis->FindBin(decay3body.phiKF()); + registry.fill(HIST("hDecay3BodyPosZ"), decay3body.poszKF()); } else { - registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPr()); - registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPi()); - registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackNeg.pt()); - registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackPos.pt()); + bin_Radius = xAxis->FindBin(decay3body.radiusDCA()); + bin_Phi = yAxis->FindBin(decay3body.phiDCA()); + registry.fill(HIST("hDecay3BodyPosZ"), decay3body.poszDCA()); } - registry.fill(HIST("QA/Tracks/hTrackBachTPCPID"), trackBach.sign() * trackBach.tpcInnerParam(), trackBach.tpcNSigmaDe()); - registry.fill(HIST("QA/Tracks/hTrackBachPt"), trackBach.pt()); + registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); } - // -------- STEP 1: track selection -------- - // collision ID --> not correct? tracks can have different collisions, but belong to one 3prong vertex! - // if (trackPos.collisionId() != trackNeg.collisionId() || trackPos.collisionId() != trackBach.collisionId() || trackNeg.collisionId() != trackBach.collisionId()) { - // continue; - // } - // track IDs --> already checked in SVertexer! - - // track signs (pos, neg, bach) --> sanity check, should already be in SVertexer - if (trackPos.sign() != +1 || trackNeg.sign() != -1) { - return; + if (decay3bodyBuilderOpts.useKFParticle) { + Binning3BodyKF binningOnRadPhi{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; + buildMixedCandidates(decay3bodys, binningOnRadPhi); + } else { + Binning3BodyDCAfitter binningOnRadPhi{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; + buildMixedCandidates(decay3bodys, binningOnRadPhi); } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCharge); + } - // track eta - if (std::abs(trackPos.eta()) > kfparticleConfigurations.maxEta || std::abs(trackNeg.eta()) > kfparticleConfigurations.maxEta || std::abs(trackBach.eta()) > kfparticleConfigurations.maxEtaDeuteron) { + void processMonteCarlo(ColswithEvTimesLabeled const& collisions, + aod::Decay3Bodys const& decay3bodys, + aod::Tracked3Bodys const& tracked3bodys, + TracksExtPIDIUwithEvTimesLabeled const&, + aod::BCsWithTimestamps const& bcs, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions) + { + // initialise CCDB from BCs + if (!initCCDB(bcs, collisions)) { return; } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxEta); - // number of TPC clusters - if (trackBach.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsBach) { - return; - } - if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { - return; - } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { - return; + // get tracked cluster size info + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCNcls); - // number of TPC crossed rows - if (trackBach.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows) { - return; - } - if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { - return; - } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCRows); - - // TPC PID - float tpcNsigmaProton; - float tpcNsigmaPion; - float dEdxProton; - float dEdxPion; - float tpcNsigmaDeuteron = trackBach.tpcNSigmaDe(); - float tpcNsigmaPionBach = trackBach.tpcNSigmaPi(); - float dEdxDeuteron = trackBach.tpcSignal(); - if (isMatter) { // hypertriton (proton, pi-, deuteron) - tpcNsigmaProton = trackPos.tpcNSigmaPr(); - tpcNsigmaPion = trackNeg.tpcNSigmaPi(); - dEdxProton = trackPos.tpcSignal(); - dEdxPion = trackNeg.tpcSignal(); - if (!selectTPCPID(trackPos, trackNeg, trackBach)) { - return; - } - } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) - tpcNsigmaProton = trackNeg.tpcNSigmaPr(); - tpcNsigmaPion = trackPos.tpcNSigmaPi(); - dEdxProton = trackNeg.tpcSignal(); - dEdxPion = trackPos.tpcSignal(); - if (!selectTPCPID(trackNeg, trackPos, trackBach)) { - return; - } - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCPID); - LOG(debug) << "Basic track selections done."; - - // Average ITS cluster size of deuteron track - double averageClusterSizeDeuteron(0); - int nCls(0); - for (int i = 0; i < 7; i++) { - int clusterSize = trackBach.itsClsSizeInLayer(i); - averageClusterSizeDeuteron += static_cast(clusterSize); - if (clusterSize > 0) - nCls++; - } - averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nCls); - - // track DCAxy and DCAz to PV associated with decay3body - o2::dataformats::VertexBase mPV; - o2::dataformats::DCA mDcaInfoCovPos; - o2::dataformats::DCA mDcaInfoCovNeg; - o2::dataformats::DCA mDcaInfoCovBach; - auto trackParCovPVPos = trackParCovPos; - auto trackParCovPVNeg = trackParCovNeg; - auto trackParCovPVBach = trackParCovBach; - mPV.setPos({collision.posX(), collision.posY(), collision.posZ()}); - mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVPos, 2.f, matCorr, &mDcaInfoCovPos); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVNeg, 2.f, matCorr, &mDcaInfoCovNeg); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVBach, 2.f, matCorr, &mDcaInfoCovBach); - auto TrackPosDcaXY = mDcaInfoCovPos.getY(); - auto TrackNegDcaXY = mDcaInfoCovNeg.getY(); - auto TrackBachDcaXY = mDcaInfoCovBach.getY(); - auto TrackPosDcaZ = mDcaInfoCovPos.getZ(); - auto TrackNegDcaZ = mDcaInfoCovNeg.getZ(); - auto TrackBachDcaZ = mDcaInfoCovBach.getZ(); - // calculate 3D track DCA - auto TrackPosDca = std::sqrt(TrackPosDcaXY * TrackPosDcaXY + TrackPosDcaZ * TrackPosDcaZ); - auto TrackNegDca = std::sqrt(TrackNegDcaXY * TrackNegDcaXY + TrackNegDcaZ * TrackNegDcaZ); - auto TrackBachDca = std::sqrt(TrackBachDcaXY * TrackBachDcaXY + TrackBachDcaZ * TrackBachDcaZ); - // selection - if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { - return; - } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAxyPV); - if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { - return; - } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAzPV); - - // daughter track momentum at inner wall of TPC - float tpcInnerParamProton; - float tpcInnerParamPion; - float tpcInnerParamDeuteron = trackBach.tpcInnerParam(); - if (isMatter) { // hypertriton (proton, pi-, deuteron) - tpcInnerParamProton = trackPos.tpcInnerParam(); - tpcInnerParamPion = trackNeg.tpcInnerParam(); - } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) - tpcInnerParamProton = trackNeg.tpcInnerParam(); - tpcInnerParamPion = trackPos.tpcInnerParam(); - } + // do candidate analysis with MC processing + buildCandidates(bcs, // bc table + collisions, // collision table + decay3bodys, // decay3body table + mcParticles, // MC particle table + mcCollisions); // MC collision table + } - // -------- STEP 2: fit vertex with proton and pion -------- - // Fit vertex with DCA fitter to find minimization point --> uses material corrections implicitly - if (kfparticleConfigurations.doDCAFitterPreMinimum) { - try { - fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); - } catch (std::runtime_error& e) { - LOG(error) << "Exception caught in DCA fitter process call: Not able to fit decay3body vertex!"; - return; - } - // re-acquire tracks at vertex position from DCA fitter - trackParCovPos = fitter3body.getTrack(0); - trackParCovNeg = fitter3body.getTrack(1); - trackParCovBach = fitter3body.getTrack(2); - - LOG(debug) << "Minimum found with DCA fitter for decay3body."; - } - - // create KFParticle objects from tracks - KFParticle kfpProton, kfpPion; - if (isMatter) { - kfpProton = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassProton); - kfpPion = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassPionCharged); - } else if (!isMatter) { - kfpProton = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassProton); - kfpPion = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassPionCharged); - } - LOG(debug) << "KFParticle objects created from daughter tracks."; - - // Construct V0 as intermediate step - KFParticle KFV0; - int nDaughtersV0 = 2; - const KFParticle* DaughtersV0[2] = {&kfpProton, &kfpPion}; - KFV0.SetConstructMethod(2); - try { - KFV0.Construct(DaughtersV0, nDaughtersV0); - } catch (std::runtime_error& e) { - LOG(debug) << "Failed to create V0 vertex from daughter tracks." << e.what(); - return; - } - KFV0.TransportToDecayVertex(); - LOG(debug) << "V0 constructed."; - - // check V0 mass and set mass constraint - float massV0, sigmaMassV0; - KFV0.GetMass(massV0, sigmaMassV0); - KFParticle KFV0Mass = KFV0; - KFV0Mass.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); - float chi2massV0 = KFV0Mass.GetChi2() / KFV0Mass.GetNDF(); - if (kfparticleConfigurations.useLambdaMassConstraint) { - LOG(debug) << "V0 mass constraint applied."; - KFV0 = KFV0Mass; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxV0MassConst); - - // apply virtual V0 cuts used in SVertexer in case of 3body mixing with proton track - if (kfparticleConfigurations.mixingType == 1 && kfparticleConfigurations.applySVertexerV0Cuts) { - // V0 radius - if (std::sqrt(KFV0.GetX() * KFV0.GetX() + KFV0.GetY() * KFV0.GetY()) <= 0.5) { - return; - } - // pT - if (KFV0.GetPt() <= 0.01) { - return; - } - // pz/pT - if (KFV0.GetPz() / KFV0.GetPt() >= 2) { - return; - } - // cos(PA) - if (cpaXYFromKF(KFV0, kfpv) <= 0.9 || cpaFromKF(KFV0, kfpv) <= 0.8) { - return; - } - } - - // -------- STEP 3: fit three body vertex -------- - // Create KFParticle object from deuteron track - KFParticle kfpDeuteron; - kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, trackBach.sign() * bachelorcharge, constants::physics::MassDeuteron); - LOG(debug) << "KFParticle created from deuteron track."; - - // Construct vertex - KFParticle KFHt; - fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt); - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxhasSV); - - // -------- STEP 4: daughter selections after geometrical vertex fit -------- - // daughter DCAs with KF - if ((kfpProton.GetDistanceFromParticle(kfpPion) >= kfparticleConfigurations.maxDcaProPi) || (kfpProton.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaProDeu) || (kfpPion.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaPiDe)) { - return; - } - float DCAvtxDaughters3D = kfpProton.GetDistanceFromParticle(kfpPion) + kfpProton.GetDistanceFromParticle(kfpDeuteron) + kfpPion.GetDistanceFromParticle(kfpDeuteron); - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDau); - LOG(debug) << "DCA selection after vertex fit applied."; - - // daughter DCAs to vertex - if (kfpProton.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpPion.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpDeuteron.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDauVtx); - LOG(debug) << "DCA to vertex selection after vertex fit applied."; - - // daughter pT - if (kfpProton.GetPt() < kfparticleConfigurations.minPtProton || kfpProton.GetPt() > kfparticleConfigurations.maxPtProton || kfpPion.GetPt() < kfparticleConfigurations.minPtPion || kfpPion.GetPt() > kfparticleConfigurations.maxPtPion || kfpDeuteron.GetPt() < kfparticleConfigurations.minPtDeuteron || kfpDeuteron.GetPt() > kfparticleConfigurations.maxPtDeuteron) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDauPt); - LOG(debug) << "Daughter pT selection applied."; - - // -------- STEP 5: candidate selection and constraint after geometrical vertex fit -------- - // Rapidity - float rapHt = RecoDecay::y(std::array{KFHt.GetPx(), KFHt.GetPy(), KFHt.GetPz()}, o2::constants::physics::MassHyperTriton); - if (std::abs(rapHt) > kfparticleConfigurations.maxRapidityHt) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxRap); - - // Pt selection - if (KFHt.GetPt() <= kfparticleConfigurations.minPtHt || KFHt.GetPt() >= kfparticleConfigurations.maxPtHt) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxPt); - - // Mass window - float massHt, sigmaMassHt; - KFHt.GetMass(massHt, sigmaMassHt); - if (massHt <= kfparticleConfigurations.minMassHt || massHt >= kfparticleConfigurations.maxMassHt) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxMass); - - // cos(PA) to PV - if (std::abs(cpaFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPA) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPA); - - // cos(PA) xy to PV - if (std::abs(cpaXYFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPAxy) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPAXY); - - // chi2 geometrical - float chi2geoNDF = KFHt.GetChi2() / KFHt.GetNDF(); - if (kfparticleConfigurations.applyTopoSel && chi2geoNDF >= kfparticleConfigurations.maxChi2geo) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2geo); - LOG(debug) << "Basic selections after vertex fit done."; - - // ctau before topo constraint - if (KFHt.GetLifeTime() > kfparticleConfigurations.maxctauHt) { - return; - } - - // Set vertex constraint and topological selection - KFParticle KFHtPV = KFHt; - try { - KFHtPV.SetProductionVertex(kfpv); - } catch (std::runtime_error& e) { - LOG(error) << "Exception caught KFParticle process call: Topological constraint failed"; - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTopoConstr); // to check if topo constraint fails - // get topological chi2 - float chi2topoNDF = KFHtPV.GetChi2() / KFHtPV.GetNDF(); - KFHtPV.TransportToDecayVertex(); - if (kfparticleConfigurations.applyTopoSel && chi2topoNDF >= kfparticleConfigurations.maxChi2topo) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2topo); - - // -------- STEP 6: collect and fill candidate info -------- - // get cluster size of strangeness tracked 3bodies - float trackedClSize; - if (decay3bodyID == -1) { - trackedClSize = 0; - } else { - trackedClSize = !fTrackedClSizeVector.empty() ? fTrackedClSizeVector[decay3bodyID] : 0; - } - - // candidate filling - kfCandidate candidate; - candidate.collisionID = collision.globalIndex(); - candidate.trackPosID = trackPos.globalIndex(); - candidate.trackNegID = trackNeg.globalIndex(); - candidate.trackBachID = trackBach.globalIndex(); - candidate.decay3bodyID = decay3bodyID; - // hypertriton - candidate.mass = massHt; - candidate.pos[0] = KFHt.GetX(); - candidate.pos[1] = KFHt.GetY(); - candidate.pos[2] = KFHt.GetZ(); - candidate.posErr[0] = KFHt.GetErrX(); - candidate.posErr[1] = KFHt.GetErrY(); - candidate.posErr[2] = KFHt.GetErrZ(); - candidate.mom[0] = KFHt.GetPx(); - candidate.mom[1] = KFHt.GetPy(); - candidate.mom[2] = KFHt.GetPz(); - candidate.mom[3] = KFHt.GetPt(); - candidate.momErr[0] = KFHt.GetErrPx(); - candidate.momErr[1] = KFHt.GetErrPy(); - candidate.momErr[2] = KFHt.GetErrPz(); - candidate.momErr[3] = KFHt.GetErrPt(); - candidate.charge = KFHt.GetQ(); - candidate.dcaToPV[0] = KFHt.GetDistanceFromVertex(kfpv); - candidate.dcaToPV[1] = KFHt.GetDistanceFromVertexXY(kfpv); - candidate.cpaToPV[0] = cpaFromKF(KFHt, kfpv); - candidate.cpaToPV[1] = cpaXYFromKF(KFHt, kfpv); - candidate.cpaToPVtopo[0] = cpaFromKF(KFHtPV, kfpv); - candidate.cpaToPVtopo[1] = cpaXYFromKF(KFHtPV, kfpv); - candidate.decLen[0] = KFHtPV.GetDecayLength(); - candidate.decLen[1] = KFHtPV.GetDecayLengthXY(); - candidate.ldl = KFHtPV.GetDecayLength() / KFHtPV.GetErrDecayLength(); - candidate.chi2geoNDF = chi2geoNDF; - candidate.chi2topoNDF = chi2topoNDF; - candidate.ctau = KFHtPV.GetLifeTime(); - candidate.trackedClSize = trackedClSize; - // V0 - candidate.massV0 = massV0; - candidate.chi2massV0 = chi2massV0; - candidate.cpaV0ToPV = cpaFromKF(KFV0, kfpv); - // daughter momenta - candidate.protonMom[0] = kfpProton.GetPx(); - candidate.protonMom[1] = kfpProton.GetPy(); - candidate.protonMom[2] = kfpProton.GetPz(); - candidate.pionMom[0] = kfpPion.GetPx(); - candidate.pionMom[1] = kfpPion.GetPy(); - candidate.pionMom[2] = kfpPion.GetPz(); - candidate.deuteronMom[0] = kfpDeuteron.GetPx(); - candidate.deuteronMom[1] = kfpDeuteron.GetPy(); - candidate.deuteronMom[2] = kfpDeuteron.GetPz(); - candidate.tpcInnerParam[0] = tpcInnerParamProton; - candidate.tpcInnerParam[1] = tpcInnerParamPion; - candidate.tpcInnerParam[2] = tpcInnerParamDeuteron; - // daughter DCAs with KF - candidate.DCAdaughterToPV[0] = kfpProton.GetDistanceFromVertex(kfpv); - candidate.DCAdaughterToPV[1] = kfpPion.GetDistanceFromVertex(kfpv); - candidate.DCAdaughterToPV[2] = kfpDeuteron.GetDistanceFromVertex(kfpv); - candidate.DCAdaughterToPVxy[0] = kfpProton.GetDistanceFromVertexXY(kfpv); - candidate.DCAdaughterToPVxy[1] = kfpPion.GetDistanceFromVertexXY(kfpv); - candidate.DCAdaughterToPVxy[2] = kfpDeuteron.GetDistanceFromVertexXY(kfpv); - candidate.DCAdaughterToSVxy[0] = kfpProton.GetDistanceFromVertexXY(KFHt); - candidate.DCAdaughterToSVxy[1] = kfpPion.GetDistanceFromVertexXY(KFHt); - candidate.DCAdaughterToSVxy[2] = kfpDeuteron.GetDistanceFromVertexXY(KFHt); - candidate.DCAprotonToPion = kfpProton.GetDistanceFromParticle(kfpPion); - candidate.DCAprotonToDeuteron = kfpProton.GetDistanceFromParticle(kfpDeuteron); - candidate.DCApionToDeuteron = kfpPion.GetDistanceFromParticle(kfpDeuteron); - candidate.DCAvtxDaughters3D = DCAvtxDaughters3D; - // daughter DCAs with material corrections - candidate.trackDCAxy[0] = TrackPosDcaXY; - candidate.trackDCAxy[1] = TrackNegDcaXY; - candidate.trackDCAxy[2] = TrackBachDcaXY; - candidate.trackDCA[0] = TrackPosDca; - candidate.trackDCA[1] = TrackNegDca; - candidate.trackDCA[2] = TrackBachDca; - // daughter signs - candidate.daughterCharge[0] = kfpProton.GetQ(); - candidate.daughterCharge[1] = kfpPion.GetQ(); - candidate.daughterCharge[2] = trackBach.sign(); - // daughter PID - candidate.tpcNsigma[0] = tpcNsigmaProton; - candidate.tpcNsigma[1] = tpcNsigmaPion; - candidate.tpcNsigma[2] = tpcNsigmaDeuteron; - candidate.tpcNsigma[3] = tpcNsigmaPionBach; - candidate.tpcdEdx[0] = dEdxProton; - candidate.tpcdEdx[1] = dEdxPion; - candidate.tpcdEdx[2] = dEdxDeuteron; - candidate.tofNsigmaDeuteron = tofNSigmaDeuteron; - candidate.averageClusterSizeDeuteron = averageClusterSizeDeuteron; - candidate.pidForTrackingDeuteron = trackBach.pidForTracking(); - - //------------------------------------------------------------------ - // table filling - fillCandidateTable(candidate); - LOG(debug) << "Table filled."; - - // fill event counter hist (has selected candidate) --> only filled once per vertex - registry.fill(HIST("Counters/hEventCounterKFParticle"), 3.5); - } // end buildVtx3BodyDataTableKFParticle - - //------------------------------------------------------------------ - void processRun3(ColwithEvTimes const& collisions, aod::Decay3Bodys const& decay3bodys, TrackExtPIDIUwithEvTimes const&, aod::BCsWithTimestamps const&) - { - VtxCandidates.clear(); - - registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); - - for (const auto& d3body : decay3bodys) { - auto t0 = d3body.track0_as(); - auto t1 = d3body.track1_as(); - auto t2 = d3body.track2_as(); - auto collision = d3body.collision_as(); - auto bc = collision.bc_as(); - initCCDB(bc); - - // Recalculate the TOF PID - double tofNSigmaBach = -999; - if (t2.has_collision() && t2.hasTOF()) { - auto originalcol = t2.template collision_as(); - tofNSigmaBach = bachelorTOFPID.GetTOFNSigma(t2, originalcol, collision); - } - - fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, tofNSigmaBach); - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3, "Produce DCA fitter decay3body tables", true); - - //------------------------------------------------------------------ - void processRun3Reduced(aod::RedCollisions const& collisions, aod::RedDecay3Bodys const& decay3bodys, aod::RedIUTracks const&) - { - VtxCandidates.clear(); - - registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); - - for (const auto& d3body : decay3bodys) { - auto t0 = d3body.track0_as(); - auto t1 = d3body.track1_as(); - auto t2 = d3body.track2_as(); - auto collision = d3body.collision_as(); - - initCCDBfromRunNumber(collision.runNumber()); - fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, t2.tofNSigmaDe()); - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced, "Produce DCA fitter decay3body tables with reduced data", false); - - //------------------------------------------------------------------ - // Event-mixing background - void processRun3ReducedEM(ReducedCollisionsMultsCents const& collisions, aod::RedDecay3Bodys const& decay3bodys, aod::RedIUTracks const&) - { - auto xAxis = registry.get(HIST("hEventPairs"))->GetXaxis(); - auto yAxis = registry.get(HIST("hEventPairs"))->GetYaxis(); - - // fill collisions counter - for (const auto& collision : collisions) { - int bin_PosZ = xAxis->FindBin(collision.posZ()); - int bin_Mult = yAxis->FindBin(collision.multNTracksPV()); - registry.fill(HIST("hEventCount"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); - } - VtxCandidates.clear(); - - auto tuple = std::make_tuple(decay3bodys); - BinningTypeColEM binningEvent{{dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}, true}; - SameKindPair pair{binningEvent, dcaFitterEMSel.nUseMixed, -1, collisions, tuple, &cache}; - - for (const auto& [c0, decay3bodys0, c1, decay3bodys1] : pair) { - // LOG(info) << "Processing event mixing with collisions " << c0.globalIndex() << " and " << c1.globalIndex(); - initCCDBfromRunNumber(c0.runNumber()); - - int bin_PosZ = xAxis->FindBin(c0.posZ()); - int bin_Mult = yAxis->FindBin(c0.multNTracksPV()); - registry.fill(HIST("hEventPairs"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); - - for (const auto& [d3body0, d3body1] : combinations(soa::CombinationsFullIndexPolicy(decay3bodys0, decay3bodys1))) { - - registry.fill(HIST("hDecay3BodyPairsBeforeCut"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); - - auto tpos0 = d3body0.track0_as(); - auto tneg0 = d3body0.track1_as(); - auto tbach0 = d3body0.track2_as(); - auto tpos1 = d3body1.track0_as(); - auto tneg1 = d3body1.track1_as(); - auto tbach1 = d3body1.track2_as(); - - // try to fit the vertex for decay3body0 - auto Trackpos0 = getTrackParCov(tpos0); - auto Trackneg0 = getTrackParCov(tneg0); - auto Trackbach0 = getTrackParCov(tbach0); - int nVtx0 = fitter3body.process(Trackpos0, Trackneg0, Trackbach0); - if (nVtx0 == 0) { - continue; - ; - } - - if ((tbach0.sign() > 0 && !(tbach1.sign() > 0)) || (tbach0.sign() < 0 && !(tbach1.sign() < 0)) || tbach0.globalIndex() == tbach1.globalIndex()) { // only combine if tbach1 has correct sign and is not same as tbach0 - continue; - } - - const auto& vtx0XYZ = fitter3body.getPCACandidate(); - float rVtx0 = std::hypot(vtx0XYZ[0], vtx0XYZ[1]); - registry.fill(HIST("hRadius0"), rVtx0); - - std::array ppos0 = {0.}, pneg0 = {0.}, pbach0{0.}; - const auto& propagatedtpos0 = fitter3body.getTrack(0); - const auto& propagatedtneg0 = fitter3body.getTrack(1); - const auto& propagatedtbach0 = fitter3body.getTrack(2); - propagatedtpos0.getPxPyPzGlo(ppos0); - propagatedtneg0.getPxPyPzGlo(pneg0); - propagatedtbach0.getPxPyPzGlo(pbach0); - for (int i = 0; i < 3; i++) { - pbach0[i] *= bachelorcharge; - } - std::array p3B0 = {ppos0[0] + pneg0[0] + pbach0[0], ppos0[1] + pneg0[1] + pbach0[1], ppos0[2] + pneg0[2] + pbach0[2]}; - float phiVtx0 = std::atan2(p3B0[1], p3B0[0]); - - // try to fit the vertex for decay3body1 - auto Trackpos1 = getTrackParCov(tpos1); - auto Trackneg1 = getTrackParCov(tneg1); - auto Trackbach1 = getTrackParCov(tbach1); - int nVtx1 = fitter3body.process(Trackpos1, Trackneg1, Trackbach1); - if (nVtx1 == 0) { - continue; - } - - const auto& vtx1XYZ = fitter3body.getPCACandidate(); - float rVtx1 = std::hypot(vtx1XYZ[0], vtx1XYZ[1]); - registry.fill(HIST("hRadius1"), rVtx1); - - std::array ppos1 = {0.}, pneg1 = {0.}, pbach1{0.}; - const auto& propagatedtpos1 = fitter3body.getTrack(0); - const auto& propagatedtneg1 = fitter3body.getTrack(1); - const auto& propagatedtbach1 = fitter3body.getTrack(2); - propagatedtpos1.getPxPyPzGlo(ppos1); - propagatedtneg1.getPxPyPzGlo(pneg1); - propagatedtbach1.getPxPyPzGlo(pbach1); - for (int i = 0; i < 3; i++) { - pbach1[i] *= bachelorcharge; - } - std::array p3B1 = {ppos1[0] + pneg1[0] + pbach1[0], ppos1[1] + pneg1[1] + pbach1[1], ppos1[2] + pneg1[2] + pbach1[2]}; - float phiVtx1 = std::atan2(p3B1[1], p3B1[0]); - registry.fill(HIST("hPhi0"), phiVtx0 * o2::constants::math::Rad2Deg); - registry.fill(HIST("hPhi1"), phiVtx1 * o2::constants::math::Rad2Deg); - // convert deltaPhi to range [-pi, pi] - float deltaPhi = RecoDecay::constrainAngle(phiVtx1 - phiVtx0, -o2::constants::math::PI); - // check if radius and phi of the two vertices are compatible - registry.fill(HIST("hDeltaRadius"), rVtx1 - rVtx0); - registry.fill(HIST("hDeltaPhi"), deltaPhi * o2::constants::math::Rad2Deg); - if (std::abs(deltaPhi) * o2::constants::math::Rad2Deg > dcaFitterEMSel.maxDeltaPhiColMixing || std::abs(rVtx1 - rVtx0) > dcaFitterEMSel.maxDeltaRadiusColMixing) { - continue; - } - registry.fill(HIST("hDecay3BodyPairsAfterCut"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); - - fillVtxCand(c0, tpos0, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); - // initCCDBfromRunNumber(c1.runNumber()); - fillVtxCand(c1, tpos1, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); - } - } - - // Aviod break of preslice in following workflow - /*std::sort(VtxCandidates.begin(), VtxCandidates.end(), [](const VtxCandidate a, const VtxCandidate b) { - return a.collisionId < b.collisionId; - });*/ - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3ReducedEM, "Produce event-mixing background", false); - - void processRun3Reduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) - { - VtxCandidates.clear(); - - auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); - auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); - - for (const auto& decay3body : decay3bodys) { - int bin_Radius = xAxis->FindBin(decay3body.svRadius()); - int bin_Phi = yAxis->FindBin(decay3body.momPhi()); - registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); - registry.fill(HIST("hDecay3BodyPosZ"), decay3body.svPosZ()); - } - - Binning3BodyDCAFitter binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhiDegree}, true}; - doMixed3Body(decay3bodys, binningOnRadiusPhi); - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixing, "Produce mixing background directly from mixed decay3bodys based on DCAFitter Info", false); - - void processRun3Reduced3bodyMixingKFInfo(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) - { - VtxCandidates.clear(); - - auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); - auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); - - for (const auto& decay3body : decay3bodys) { - int bin_Radius = xAxis->FindBin(decay3body.radius()); - int bin_Phi = yAxis->FindBin(decay3body.phi()); - registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); - registry.fill(HIST("hDecay3BodyPosZ"), decay3body.posz()); - } - - Binning3BodyKFInfo binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}, true}; - doMixed3Body(decay3bodys, binningOnRadiusPhi); - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixingKFInfo, "Produce mixing background directly from mixed decay3bodys based on KF Info", false); - - //------------------------------------------------------------------ - void processRun3withKFParticle(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) - { - for (const auto& collision : collisions) { - - auto bc = collision.bc_as(); - initCCDB(bc); - LOG(debug) << "CCDB initialised."; - - // Zorro event counting - bool isZorroSelected = false; - if (kfparticleConfigurations.cfgSkimmedProcessing) { - isZorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); - if (isZorroSelected) { - registry.fill(HIST("Counters/hEventCounterZorro"), 0.); - } else { - if (kfparticleConfigurations.cfgOnlyKeepInterestedTrigger) { - continue; - } - } - } - - // event selection - registry.fill(HIST("Counters/hEventCounterKFParticle"), 0.5); - if (kfparticleConfigurations.doSel8selection && !collision.sel8()) { - continue; - } - registry.fill(HIST("Counters/hEventCounterKFParticle"), 1.5); - if (kfparticleConfigurations.doPosZselection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { - continue; - } - registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); - registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); - - if (isZorroSelected) { - registry.fill(HIST("Counters/hEventCounterZorro"), 1.); - } - - // slice Decay3Body table by collision - const uint64_t collIdx = collision.globalIndex(); - auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perCollision, collIdx); - for (auto& vtx3body : Decay3BodyTable_thisCollision) { - auto trackPos = vtx3body.template track0_as(); - auto trackNeg = vtx3body.template track1_as(); - auto trackBach = vtx3body.template track2_as(); - buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, getTOFnSigma(collision, trackBach, false /*isEventMixing*/)); - LOG(debug) << "End of processKFParticle."; - } - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticle, "Produce KFParticle decay3body tables", false); - - void processRun3withKFParticleStrangenessTracking(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const& tracks, aod::Decay3Bodys const& decay3bodys, aod::Tracked3Bodys const& tracked3bodys, aod::BCsWithTimestamps const& bcs) - { - fTrackedClSizeVector.clear(); - fTrackedClSizeVector.resize(decay3bodys.size(), 0); - for (const auto& tvtx3body : tracked3bodys) { - fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); - } - processRun3withKFParticle(collisions, tracks, decay3bodys, bcs); - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleStrangenessTracking, "Produce KFParticle strangeness tracked decay3body tables", false); - - void processRun3withKFParticleReduced(aod::RedCollisions const& collisions, aod::RedIUTracks const&, aod::RedDecay3Bodys const& decay3bodys) - { - int lastRunNumber = -1; - - for (const auto& collision : collisions) { - // set magnetic field only when run number changes - if (collision.runNumber() != lastRunNumber) { - initCCDBfromRunNumber(collision.runNumber()); - lastRunNumber = collision.runNumber(); // Update the last run number - LOG(debug) << "CCDB initialized for run " << lastRunNumber; - } - - // event selection - registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); - registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); - - // slice Decay3Body table by collision - const uint64_t collIdx = collision.globalIndex(); - auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perReducedCollision, collIdx); - for (auto& vtx3body : Decay3BodyTable_thisCollision) { - auto trackPos = vtx3body.template track0_as(); - auto trackNeg = vtx3body.template track1_as(); - auto trackBach = vtx3body.template track2_as(); - buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, trackBach.tofNSigmaDe()); - } - LOG(debug) << "End of processKFParticleDerived."; - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced, "Produce KFParticle decay3body tables from derived decay3body data", false); - - void processRun3withKFParticleReducedEM(ReducedCollisionsMults const& collisions, aod::RedIUTracks const&, aod::RedDecay3Bodys const& decay3bodys) - { - // ------------- Check number of events in bins -------------- - // Define a 2D array to count events and pairs per bin - std::vector> binEventCounts(10, std::vector(13, 0)); // 10 vtxZ bins, 13 multiplicity bins - std::vector> binPairCounts(10, std::vector(13, 0)); - - // Function to find bin index (returns -1 if out of range) - auto findBin = [](float value, const std::vector& binEdges) -> int { - for (size_t i = 0; i < binEdges.size() - 1; ++i) { - if (value > binEdges[i] && value <= binEdges[i + 1]) { - return i; - } - } - return -1; // Shouldn't happen if events are within range - }; - // Loop over all collisions to count them in bins - for (auto& collision : collisions) { - float vtxZ = collision.posZ(); - float mult = collision.multNTracksPV(); - - // Determine bin indices - int vtxZBin = findBin(vtxZ, {-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}); - int multBin = findBin(mult, {0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}); - - if (vtxZBin >= 0 && multBin >= 0) { - binEventCounts[vtxZBin][multBin]++; - } - } - // Print out the number of events per bin - LOG(info) << "Event count per bin (vtxZ, mult):"; - for (size_t i = 0; i < binEventCounts.size(); ++i) { - for (size_t j = 0; j < binEventCounts[i].size(); ++j) { - LOG(info) << "Bin (" << i << ", " << j << "): " << binEventCounts[i][j] << " events"; - } - } - // Fill histogram with numbers per bin - for (size_t i = 0; i < binEventCounts.size(); ++i) { - for (size_t j = 0; j < binEventCounts[i].size(); ++j) { - registry.fill(HIST("QA/EM/hEventBinCounts"), i, j, binEventCounts[i][j]); - } - } - LOG(info) << "Integral of hEventBinCounts:" << registry.get(HIST("QA/EM/hEventBinCounts"))->Integral(); - - // ------------- Check number of decay3bodys in bins ------------- - // Define a 2D array to count events and pairs per bin - std::vector> binDecay3BodyCounts(10, std::vector(13, 0)); // 10 vtxZ bins, 13 multiplicity bins - // Loop over all decay3bodys to count them in bins - for (auto& decay3body : decay3bodys) { - auto collision = decay3body.template collision_as(); - float vtx3bodyZ = collision.posZ(); - float mult3body = collision.multNTracksPV(); - - // Determine bin indices - int vtx3bodyZBin = findBin(vtx3bodyZ, {-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}); - int mult3bodyBin = findBin(mult3body, {0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}); - - if (vtx3bodyZBin >= 0 && mult3bodyBin >= 0) { - binDecay3BodyCounts[vtx3bodyZBin][mult3bodyBin]++; - } - } - // Print out the number of events per bin - LOG(debug) << "Event count per bin (vtxZ, mult):"; - for (size_t i = 0; i < binDecay3BodyCounts.size(); ++i) { - for (size_t j = 0; j < binDecay3BodyCounts[i].size(); ++j) { - LOG(debug) << "Bin (" << i << ", " << j << "): " << binDecay3BodyCounts[i][j] << " events"; - } - } - // Fill histogram with numbers per bin - for (size_t i = 0; i < binDecay3BodyCounts.size(); ++i) { - for (size_t j = 0; j < binDecay3BodyCounts[i].size(); ++j) { - registry.fill(HIST("QA/EM/h3bodyBinCounts"), i, j, binDecay3BodyCounts[i][j]); - } - } - LOG(info) << "Integral of h3bodyBinCounts:" << registry.get(HIST("QA/EM/h3bodyBinCounts"))->Integral(); - - // ------------- Do event mixing -------------- - auto tuple = std::make_tuple(decay3bodys); - BinningTypeKF binningOnPosAndMult{{kfparticleConfigurations.binsVtxZ, kfparticleConfigurations.binsMultiplicity}, true}; // ignore over-/underflow - SameKindPair pair{binningOnPosAndMult, kfparticleConfigurations.nEvtMixing, -1, collisions, tuple, &cache}; // indicates that under/overflow (-1) to be ignored - - int lastRunNumber = -1; - - for (auto& [c1, decays3body1, c2, decays3body2] : pair) { - registry.fill(HIST("QA/EM/hPairCounterMixing"), 0.5); - - // event selection already applied in reducer task - - // set magnetic field only when run number changes - if (c1.runNumber() != lastRunNumber) { - initCCDBfromRunNumber(c1.runNumber()); - lastRunNumber = c1.runNumber(); // Update the last run number - LOG(debug) << "CCDB initialized for run " << lastRunNumber; - } - - // Get vtxZ and multiplicity from collision - float vtxZpair = c1.posZ(); - float multpair = c1.multNTracksPV(); - // Find the bin index - int vtxZpairBin = findBin(vtxZpair, {-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}); - int multpairBin = findBin(multpair, {0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}); - if (vtxZpairBin >= 0 && multpairBin >= 0) { - binPairCounts[vtxZpairBin][multpairBin]++; // Count the pair - } - - for (auto& [decay3body1, decay3body2] : soa::combinations(soa::CombinationsFullIndexPolicy(decays3body1, decays3body2))) { - auto trackPos1 = decay3body1.template track0_as(); - auto trackNeg1 = decay3body1.template track1_as(); - auto trackBach1 = decay3body1.template track2_as(); - auto trackPos2 = decay3body2.template track0_as(); - auto trackNeg2 = decay3body2.template track1_as(); - auto trackBach2 = decay3body2.template track2_as(); - - registry.fill(HIST("QA/EM/hCombinationCounterMixing"), 0.5); - - // ---------- selections bachelor track ---------- - if ((trackBach1.sign() > 0 && !(trackBach2.sign() > 0)) || (trackBach1.sign() < 0 && !(trackBach2.sign() < 0)) || trackBach1.globalIndex() == trackBach2.globalIndex()) { // only combine if trackBach2 has correct sign and is not same as trackBach1 - continue; - } - registry.fill(HIST("QA/EM/hCombinationCounterMixing"), 1.5); - - // ---------- check radius and phi of decay3bodys ---------- - auto trackParCovPos1 = getTrackParCov(trackPos1); - auto trackParCovNeg1 = getTrackParCov(trackNeg1); - auto trackParCovBach1 = getTrackParCov(trackBach1); - auto trackParCovPos2 = getTrackParCov(trackPos2); - auto trackParCovNeg2 = getTrackParCov(trackNeg2); - auto trackParCovBach2 = getTrackParCov(trackBach2); - // create KFParticle objects from tracks - KFParticle kfpProton1, kfpPion1, kfpDeuteron1; - if (trackBach1.sign() > 0) { - kfpProton1 = createKFParticleFromTrackParCov(trackParCovPos1, trackPos1.sign(), constants::physics::MassProton); - kfpPion1 = createKFParticleFromTrackParCov(trackParCovNeg1, trackNeg1.sign(), constants::physics::MassPionCharged); - } else if (!(trackBach1.sign() > 0)) { - kfpProton1 = createKFParticleFromTrackParCov(trackParCovNeg1, trackNeg1.sign(), constants::physics::MassProton); - kfpPion1 = createKFParticleFromTrackParCov(trackParCovPos1, trackPos1.sign(), constants::physics::MassPionCharged); - } - kfpDeuteron1 = createKFParticleFromTrackParCov(trackParCovBach1, trackBach1.sign() * bachelorcharge, constants::physics::MassDeuteron); - KFParticle kfpProton2, kfpPion2, kfpDeuteron2; - if (trackBach2.sign() > 0) { - kfpProton2 = createKFParticleFromTrackParCov(trackParCovPos2, trackPos2.sign(), constants::physics::MassProton); - kfpPion2 = createKFParticleFromTrackParCov(trackParCovNeg2, trackNeg2.sign(), constants::physics::MassPionCharged); - } else if (!(trackBach2.sign() > 0)) { - kfpProton2 = createKFParticleFromTrackParCov(trackParCovNeg2, trackNeg2.sign(), constants::physics::MassProton); - kfpPion2 = createKFParticleFromTrackParCov(trackParCovPos2, trackPos2.sign(), constants::physics::MassPionCharged); - } - kfpDeuteron2 = createKFParticleFromTrackParCov(trackParCovBach2, trackBach2.sign() * bachelorcharge, constants::physics::MassDeuteron); - // fit vertices - KFParticle KFHt1, KFHt2; - fit3bodyVertex(kfpProton1, kfpPion1, kfpDeuteron1, KFHt1); - fit3bodyVertex(kfpProton2, kfpPion2, kfpDeuteron2, KFHt2); - - // ---------- select common radius and phi region ---------- - auto radius1 = std::sqrt(KFHt1.GetX() * KFHt1.GetX() + KFHt1.GetY() * KFHt1.GetY()); - auto radius2 = std::sqrt(KFHt2.GetX() * KFHt2.GetX() + KFHt2.GetY() * KFHt2.GetY()); - registry.fill(HIST("QA/EM/hRadius1"), radius1); - registry.fill(HIST("QA/EM/hRadius2"), radius2); - registry.fill(HIST("QA/EM/hPhi1"), KFHt1.GetPhi() * (180.0 / TMath::Pi())); - registry.fill(HIST("QA/EM/hPhi2"), KFHt2.GetPhi() * (180.0 / TMath::Pi())); - registry.fill(HIST("QA/EM/hDeltaRadius"), std::abs(radius1 - radius2)); - registry.fill(HIST("QA/EM/hDeltaPhi"), std::abs(KFHt1.GetPhi() - KFHt2.GetPhi()) * (180.0 / TMath::Pi())); - if (std::abs(KFHt1.GetPhi() - KFHt2.GetPhi()) * (180.0 / TMath::Pi()) > 10 || std::abs(radius1 - radius2) > 2) { - continue; - } - registry.fill(HIST("QA/EM/hCombinationCounterMixing"), 2.5); - - // fill 2D pair counter per bin - registry.fill(HIST("QA/EM/hPairBinCounts"), vtxZpairBin, multpairBin, 1); - - // ---------- do candidate analysis ---------- - buildVtx3BodyDataTableKFParticle(c1, trackPos1, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); - } // end decay3body combinations loop - } // end pairing loop - } // end process - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReducedEM, "Produce KFParticle event mixing decay3body tables from derived decay3body data", false); - - void processRun3withKFParticleReduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) - { - // Define a 2D array to count 3bodies per bin (radius, phi, posZ) - std::vector> bin3bodyCounts(16, std::vector(36, 0)); - - // Function to find bin index (returns -1 if out of range) - auto findBin = [](float value, const std::vector& binEdges) -> int { - for (size_t i = 0; i < binEdges.size() - 1; ++i) { - if (value > binEdges[i] && value <= binEdges[i + 1]) { - return i; - } - } - return -1; // Out of range - }; - - int counter = 0; - // Loop over all collisions to count them in bins - for (auto& decay3body : decay3bodys) { - counter++; - float radius = decay3body.radius(); - float phi = decay3body.phi(); - float posZ = decay3body.posz(); - - registry.fill(HIST("QA/EM/hRadius"), radius); - registry.fill(HIST("QA/EM/hPhi"), phi); - registry.fill(HIST("QA/EM/hPosZ"), posZ); - - // float degToRad = TMath::Pi()/180; - - // Determine bin indices - int radiusBin = findBin(radius, {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}); - int phiBin = findBin(phi, {-180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}); - if (radiusBin >= 0 && phiBin >= 0) { // && posZBin >= 0) { - bin3bodyCounts[radiusBin][phiBin]++; //[posZBin]++; - } - } - LOG(info) << "3body counter: " << counter; - - // Print out the number of 3-body decays per bin - LOG(info) << "3body count per bin (radius, phi, posZ):"; - for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { - for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { - LOG(info) << "Bin (" << i << ", " << j << "): " << bin3bodyCounts[i][j] << " 3bodies"; - } - } - // Fill 3D histogram with numbers per bin - for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { - for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { - registry.fill(HIST("QA/EM/h3bodyBinCounts"), i, j, bin3bodyCounts[i][j]); - } - } - LOG(info) << "Integral of h3bodyBinCounts: " << registry.get(HIST("QA/EM/h3bodyBinCounts"))->Integral(); - - Binning3Body binningOnRadPhi{{kfparticleConfigurations.bins3BodyRadius, kfparticleConfigurations.bins3BodyPhi}, true}; - - // Strictly upper index policy for decay3body objects binned by radius, phi and z position - for (auto& [decay3body1, decay3body2] : selfPairCombinations(binningOnRadPhi, kfparticleConfigurations.nEvtMixing, -1, decay3bodys)) { - auto trackPos1 = decay3body1.template track0_as(); - auto trackNeg1 = decay3body1.template track1_as(); - auto trackBach1 = decay3body1.template track2_as(); - auto trackPos2 = decay3body2.template track0_as(); - auto trackNeg2 = decay3body2.template track1_as(); - auto trackBach2 = decay3body2.template track2_as(); - - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 0.5); - - // collision vertex selections - auto collision1 = decay3body1.template collision_as(); - auto collision2 = decay3body2.template collision_as(); - initCCDBfromRunNumber(collision2.runNumber()); - initCCDBfromRunNumber(collision1.runNumber()); - - if (decay3body1.collisionId() == decay3body2.collisionId()) { // only combine if from different event - continue; - } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 1.5); - if (kfparticleConfigurations.selectVtxZ3bodyMixing && std::abs(collision1.posZ() - collision2.posZ()) > kfparticleConfigurations.VtxZBin3bodyMixing) { // only combine if collision similar in VtxZ - continue; - } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 2.5); - - // ---------- selections ---------- - if ((trackBach1.sign() > 0 && !(trackBach2.sign() > 0)) || (trackBach1.sign() < 0 && !(trackBach2.sign() < 0)) || trackBach1.globalIndex() == trackBach2.globalIndex()) { // only combine if trackBach2 has correct sign and is not same as trackBach1 - continue; - } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); - - // ---------- do candidate analysis ---------- - bool isMatter1 = false; - if (trackBach1.sign() > 0) { - isMatter1 = true; - } - if (kfparticleConfigurations.mixingType == 0) { // mix deuteron - buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); - buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); - } else if (kfparticleConfigurations.mixingType == 1) { // mix proton - if (isMatter1 == true) { - buildVtx3BodyDataTableKFParticle(collision1, trackPos2, trackNeg1, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); - buildVtx3BodyDataTableKFParticle(collision2, trackPos1, trackNeg2, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); - } else if (isMatter1 == false) { - buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); - buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); - } - } - } // end decay3body combinations loop - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced3bodyMixing, "Produce KFParticle mixed decay3body tables from derived decay3body data", false); -}; - -// build link from decay3body -> vtx3body -struct decay3bodyDataLinkBuilder { - Produces VtxDataLink; - - void init(InitContext const&) {} - - template - void buildDecay3BodyLabel(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) - { - std::vector lIndices; - lIndices.reserve(decay3bodytable.size()); - for (int ii = 0; ii < decay3bodytable.size(); ii++) - lIndices[ii] = -1; - for (const auto& vtxdata : vtxdatatable) { - if (vtxdata.decay3bodyId() != -1) { - lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); - } - } - for (int ii = 0; ii < decay3bodytable.size(); ii++) { - VtxDataLink(lIndices[ii]); - } - } - - void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) - { - buildDecay3BodyLabel(decay3bodytable, vtxdatatable); - } - PROCESS_SWITCH(decay3bodyDataLinkBuilder, processStandard, "Produce label from decay3body to vtx3body", true); - - void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) - { - buildDecay3BodyLabel(decay3bodytable, vtxdatatable); - } - PROCESS_SWITCH(decay3bodyDataLinkBuilder, processReduced, "Produce label from reducedDecay3body to vtx3body", false); -}; - -struct kfdecay3bodyDataLinkBuilder { - Produces kfvtxdataLink; - - void init(InitContext const&) {} - - template - void buildDataLink(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) - { - std::vector lIndices; - lIndices.reserve(decay3bodytable.size()); - for (int ii = 0; ii < decay3bodytable.size(); ii++) - lIndices[ii] = -1; - for (auto& vtxdata : vtxdatatable) { - if (vtxdata.decay3bodyId() != -1) { - lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); - } - } - for (int ii = 0; ii < decay3bodytable.size(); ii++) { - kfvtxdataLink(lIndices[ii]); - } - } - - void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) - { - buildDataLink(decay3bodytable, vtxdatatable); // build Decay3Body -> KFDecay3BodyData link table - } - PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processStandard, "Build data link table.", true); - - void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) - { - buildDataLink(decay3bodytable, vtxdatatable); // build ReducedDecay3Body -> KFDecay3BodyData link table - } - PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processReduced, "Build data link table for reduced data.", false); -}; - -struct decay3bodyLabelBuilder { - - Produces vtxlabels; - Produces vtxfulllabels; - - HistogramRegistry registry{"registry", {}}; - - void init(InitContext const&) - { - if (doprocessDoNotBuildLabels == false) { - auto hLabelCounter = registry.add("hLabelCounter", "hLabelCounter", HistType::kTH1D, {{3, 0.0f, 3.0f}}); - hLabelCounter->GetXaxis()->SetBinLabel(1, "Total"); - hLabelCounter->GetXaxis()->SetBinLabel(2, "Have Same MotherTrack"); - hLabelCounter->GetXaxis()->SetBinLabel(3, "True H3L"); - - registry.add("hHypertritonMCPt", "hHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); - registry.add("hAntiHypertritonMCPt", "hAntiHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); - registry.add("hHypertritonMCMass", "hHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); - registry.add("hAntiHypertritonMCMass", "hAntiHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); - registry.add("hHypertritonMCLifetime", "hHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); - registry.add("hAntiHypertritonMCLifetime", "hAntiHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); - } - } - - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - - void processDoNotBuildLabels(aod::Decay3BodyDataLink const&) // is it possible to have none parameter? - { - // dummy process function - should not be required in the future - }; - PROCESS_SWITCH(decay3bodyLabelBuilder, processDoNotBuildLabels, "Do not produce MC label tables", true); - - void processBuildLabels(aod::Decay3BodysLinked const& decay3bodys, aod::Vtx3BodyDatas const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const&) - { - std::vector lIndices; - lIndices.reserve(vtx3bodydatas.size()); - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - lIndices[ii] = -1; - } - - for (const auto& decay3body : decay3bodys) { - - int lLabel = -1; - int lPDG = -1; - float lPt = -1; - double MClifetime = -1; - bool is3bodyDecay = false; - int lGlobalIndex = -1; - - auto lTrack0 = decay3body.track0_as(); - auto lTrack1 = decay3body.track1_as(); - auto lTrack2 = decay3body.track2_as(); - registry.fill(HIST("hLabelCounter"), 0.5); - - // Association check - // There might be smarter ways of doing this in the future - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - vtxfulllabels(-1); - continue; - } - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - vtxfulllabels(-1); - continue; - } - - for (const auto& lMother0 : lMCTrack0.mothers_as()) { - for (const auto& lMother1 : lMCTrack1.mothers_as()) { - for (const auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lGlobalIndex = lMother1.globalIndex(); - lPt = lMother1.pt(); - lPDG = lMother1.pdgCode(); - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); // only for hypertriton - is3bodyDecay = true; // vtxs with the same mother - } - } - } - } // end association check - if (!is3bodyDecay) { - vtxfulllabels(-1); - continue; - } - registry.fill(HIST("hLabelCounter"), 1.5); - - // Intended for hypertriton cross-checks only - if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { - lLabel = lGlobalIndex; - double hypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hHypertritonMCPt"), lPt); - registry.fill(HIST("hHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); - } - if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { - lLabel = lGlobalIndex; - double antiHypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hAntiHypertritonMCPt"), lPt); - registry.fill(HIST("hAntiHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); - } - - // Construct label table, only vtx which corresponds to true mother and true daughters with a specified order is labeled - // for matter: track0->p, track1->pi, track2->bachelor - // for antimatter: track0->pi, track1->p, track2->bachelor - vtxfulllabels(lLabel); - if (decay3body.vtx3BodyDataId() != -1) { - lIndices[decay3body.vtx3BodyDataId()] = lLabel; - } - } - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - vtxlabels(lIndices[ii]); - } - } - PROCESS_SWITCH(decay3bodyLabelBuilder, processBuildLabels, "Produce MC label tables", false); -}; - -struct decay3bodyInitializer { - Spawns vtx3bodydatas; - void init(InitContext const&) {} + PROCESS_SWITCH(decay3bodyBuilder, processRealData, "process real data", true); + PROCESS_SWITCH(decay3bodyBuilder, processRealDataReduced, "process real reduced data", false); + PROCESS_SWITCH(decay3bodyBuilder, processRealDataReduced3bodyMixing, "process real reduced data", false); + PROCESS_SWITCH(decay3bodyBuilder, processMonteCarlo, "process monte carlo", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx deleted file mode 100644 index 296ad0503a6..00000000000 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder_new.cxx +++ /dev/null @@ -1,2000 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// ======================== -/// \file decay3bodybuilder.cxx -/// \brief Builder task for 3-body decay reconstruction (p + pion + bachelor) -/// \author Yuanzhe Wang -/// \author Carolina Reetz -// ======================== - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "DCAFitter/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "DetectorsVertexing/SVertexHypothesis.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/Reduced3BodyTables.h" -#include "PWGLF/DataModel/Vtx3BodyTables.h" -#include "PWGLF/DataModel/pidTOFGeneric.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/PID/PIDTOF.h" -#include "TableHelper.h" -#include "Tools/KFparticle/KFUtilities.h" - -#include "EventFiltering/Zorro.h" -#include "EventFiltering/ZorroSummary.h" - -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "DataFormatsCalibration/MeanVertexObject.h" - -#ifndef HomogeneousField -#define HomogeneousField -#endif - -// includes KFParticle -#include "KFParticle.h" -#include "KFPTrack.h" -#include "KFPVertex.h" -#include "KFParticleBase.h" -#include "KFVertex.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -static constexpr int nParameters = 1; -static const std::vector tableNames { - "Decay3BodyIndices", - "StoredDecay3BodyCores", - "Decay3BodyCovs", - "Decay3BodyDaughterCovs", - "McDecay3BodyLabels" -}; - -static constexpr int nTablesConst = 5; - -static const std::vector parameterNames{"enable"}; -static const int defaultParameters[nTablesConst][nParameters]{ - {0}, // Decay3BodyIndices - {0}, // StoredDecay3BodyCores - {0}, // Decay3BodyCovs - {0}, // Decay3BodyDaughterCovs - {0} // McDecay3BodyLabels -}; - -using FullTracksExtIU = soa::Join; -using FullTracksExtPIDIU = soa::Join; -using FullTracksExtIULabeled = soa::Join; -using FullTracksExtIUwithEvTimes = soa::Join; -using FullTracksExtPIDIUwithEvTimes = soa::Join; - -using ColwithEvTimes = o2::soa::Join; -using ColwithEvTimesMults = o2::soa::Join; - -using ReducedCollisionsMults = soa::Join; -using ReducedCollisionsMultsCents = soa::Join; - -// namespace -// { -// const float pidCutsLambda[o2::vertexing::SVertexHypothesis::NPIDParams] = {0., 20, 0., 5.0, 0.0, 1.09004e-03, 2.62291e-04, 8.93179e-03, 2.83121}; // Lambda -// } // namespace - -// struct VtxCandidate { -// int track0Id; -// int track1Id; -// int track2Id; -// int collisionId; -// int decay3bodyId; -// float vtxPos[3]; -// float track0P[3]; -// float track1P[3]; -// float track2P[3]; -// float dcadaughters; -// float daudcaxytopv[3]; // 0 - proton, 1 - pion, 2 - bachelor -// float daudcatopv[3]; // 0 - proton, 1 - pion, 2 - bachelor -// float bachelortofNsigma; -// }; - -// struct kfCandidate { -// // hypertriton -// int collisionID; -// int trackPosID; -// int trackNegID; -// int trackBachID; -// int decay3bodyID; -// float mass; -// float pos[3]; -// float posErr[3]; -// float mom[4]; -// float momErr[4]; -// float charge; -// float dcaToPV[2]; // 3D, xy -// float cpaToPV[2]; // 3D, xy -// float cpaToPVtopo[2]; // 3D, xy -// float decLen[2]; // 3D, xy -// float ldl; -// float chi2geoNDF; -// float chi2topoNDF; -// float ctau; -// float trackedClSize; -// float DeltaPhiRotDeuteron; -// float DeltaPhiRotProton; -// // V0 -// float massV0; -// float chi2massV0; -// float cpaV0ToPV; -// // daughter momenta -// float protonMom[3]; -// float pionMom[3]; -// float deuteronMom[3]; -// float tpcInnerParam[3]; // proton, pion, deuteron -// // daughter track quality -// int tpcNClDaughters[3]; // proton, pion, deuteron -// float tpcChi2NClDeuteron; -// // daughter DCAs KF -// float DCAdaughterToPV[3]; // proton, pion, deuteron -// float DCAdaughterToPVxy[3]; // proton, pion, deuteron -// float DCAdaughterToSVxy[3]; // proton, pion, deuteron -// float DCAprotonToPion; -// float DCAprotonToDeuteron; -// float DCApionToDeuteron; -// float DCAvtxDaughters3D; -// // daughter DCAs to PV propagated with material -// float trackDCAxy[3]; // pos, neg, bach -// float trackDCA[3]; // pos, neg, bach -// // daughter signs -// float daughterCharge[3]; // proton, pion, deuteron -// // daughter PID -// float tpcNsigma[4]; // proton, pion, deuteron, bach with pion hyp -// float tpcdEdx[3]; // proton, pion, deuteron -// float tofNsigmaDeuteron; -// float averageClusterSizeDeuteron; -// float pidForTrackingDeuteron; -// }; - -struct decay3bodyBuilder { - - // helper object - o2::pwglf::decay3bodyBuilderHelper helper; - - // table index : match order above - enum tableIndex { kDecay3BodyIndices = 0, - kStoredDecay3BodyCores, - kDecay3BodyCovs, - kDecay3BodyDaughterCovs, - kMcDecay3BodyLabels, - kMcDecay3BodyCores, - kMcDecay3BodyCollRefs, - nTables }; - - struct : ProducesGroup { - Produces decay3bodyindices; - Produces decay3bodycores; - Produces decay3bodycovs; - Produces decay3bodydaugcovs; - Produces mcdecay3bodylabels; - } products; - - Configurable> enabledTables{"enabledTables", {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, "Produce this table: 0 - false, 1 - true"} - std::vector mEnabledTables; // Vector of enabled tables - - // general options - Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; - Configurable doTrackQA{"doTrackQA", false, "Flag to fill QA histograms for daughter tracks."}; - Configurable doVertexQA{"doVertexQA", false, "Flag to fill QA histograms for PV."}; - - // data processing options - Configurable doSkimmedProcessing{"doSkimmedProcessing", false, "Apply Zoroo counting in case of skimmed data input"}; - Configurable triggerList{"triggerList", "fTriggerEventF1Proton, fTrackedOmega, fTrackedXi, fOmegaLargeRadius, fDoubleOmega, fOmegaHighMult, fSingleXiYN, fQuadrupleXi, fDoubleXi, fhadronOmega, fOmegaXi, fTripleXi, fOmega, fGammaVeryLowPtEMCAL, fGammaVeryLowPtDCAL, fGammaHighPtEMCAL, fGammaLowPtEMCAL, fGammaVeryHighPtDCAL, fGammaVeryHighPtEMCAL, fGammaLowPtDCAL, fJetNeutralLowPt, fJetNeutralHighPt, fGammaHighPtDCAL, fJetFullLowPt, fJetFullHighPt, fEMCALReadout, fPCMandEE, fPHOSnbar, fPCMHighPtPhoton, fPHOSPhoton, fLD, fPPPHI, fPD, fLLL, fPLL, fPPL, fPPP, fLeadingPtTrack, fHighFt0cFv0Flat, fHighFt0cFv0Mult, fHighFt0Flat, fHighFt0Mult, fHighMultFv0, fHighTrackMult, fHfSingleNonPromptCharm3P, fHfSingleNonPromptCharm2P, fHfSingleCharm3P, fHfPhotonCharm3P, fHfHighPt2P, fHfSigmaC0K0, fHfDoubleCharm2P, fHfBeauty3P, fHfFemto3P, fHfFemto2P, fHfHighPt3P, fHfSigmaCPPK, fHfDoubleCharm3P, fHfDoubleCharmMix, fHfPhotonCharm2P, fHfV0Charm2P, fHfBeauty4P, fHfV0Charm3P, fHfSingleCharm2P, fHfCharmBarToXiBach, fSingleMuHigh, fSingleMuLow, fLMeeHMR, fDiMuon, fDiElectron, fLMeeIMR, fSingleE, fTrackHighPt, fTrackLowPt, fJetChHighPt, fJetChLowPt, fUDdiffLarge, fUDdiffSmall, fITSextremeIonisation, fITSmildIonisation, fH3L3Body, fHe, fH2", "List of triggers used to select events"}; - - // CCDB options - struct : ConfigurableGroup { - std::string prefix = "ccdb"; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - } ccdbConfigurations; - - // Decay3body building options - struct : ConfigurableGroup { - std::string prefix = "decay3bodyBuilderOpts"; - // building options - Configurable useKFParticle{"useKFParticle", false, "Use KFParticle for decay3body building"}; - Configurable kfSetTopologicalConstraint{"kfSetTopologicalConstraint", false, "Set topological vertex constraint in case of KFParticle reconstruction"}; - Configurable useSelections{"useSelections", true, "Apply selections during decay3body building"}; - Configurable acceptTPCOnly{"acceptTPCOnly", false, "Accept TPC only tracks as daughters"}; - Configurable calculateCovariance{"calculateCovariance", true, "Calculate candidate and daughter covariance matrices"}; - // daughter track selections - Configurable maxEtaDaughters{"maxEtaDaughters", 0.9, "Max eta of daughters"}; - Configurable minTPCNClProton{"minTPCNClProton", 90, "Min TPC NClusters of proton daughter"}; - Configurable minTPCNClPion{"minTPCNClPion", 70, "Min TPC NClusters of pion daughter"}; - Configurable minTPCNClBach{"minTPCNClBach", 100, "Min TPC NClusters of bachelor daughter"}; - Configurable minDCAProtonToPV{"minDCAProtonToPV", 0.1, "Min DCA of proton to PV"}; - Configurable minDCAPionToPV{"minDCAPionToPV", 0.1, "Min DCA of pion to PV"}; - Configurable minDCABachToPV{"minDCABachToPV", 0.1, "Min DCA of bachelor to PV"}; - Configurable minPtProton{"minPtProton", 0.3, "Min Pt of proton daughter"}; - Configurable minPtPion{"minPtPion", 0.1, "Min Pt of pion daughter"}; - Configurable minPtBach{"minPtBach", 0.6, "Min Pt of bachelor daughter"}; - Configurable maxPtProton{"maxPtProton", 5.0, "Max Pt of proton daughter"}; - Configurable maxPtPion{"maxPtPion", 1.2, "Max Pt of pion daughter"}; - Configurable maxPtBach{"maxPtBach", 10.0, "Max Pt of bachelor daughter"}; - Configurable maxTPCnSigma{"maxTPCnSigma", 5.0, "Min/max TPC nSigma of daughter tracks"}; - Configurable minTOFnSigmaDeuteron{"minTOFnSigmaDeuteron", -5.0, "Min TOF nSigma of deuteron daughter"}; - Configurable maxTOFnSigmaDeuteron{"maxTOFnSigmaDeuteron", 5.0, "Max TOF nSigma of deuteron daughter"}; - Configurable minPBachUseTOF{"minPBaChUseTOF", 1.0, "Min P of bachelor to use TOF PID"}; - Configurable maxDCADauAtSV{"maxDCADauAtSV", 0.5, "Max DCA of daughters at SV (quadratic sum of daughter DCAs between each other)"}; - // candidate selections - Configurable maxRapidity{"maxRapidity", 1.0, "Max rapidity of decay3body vertex"}; - Configurable minPt{"minPt", 2.0, "Min Pt of decay3body candidate"}; - Configurable maxPt{"maxPt", 5.0, "Max Pt of decay3body candidate"}; - Configurable minMass{"minMass", 2.96, "Min mass of decay3body candidate"}; - Configurable maxMass{"maxMass", 3.04, "Max mass of decay3body candidate"}; - Configurable minCtau{"minCtau", 0.0, "Min ctau of decay3body candidate"}; - Configurable maxCtau{"maxCtau", 100.0, "Max ctau of decay3body candidate"}; - Configurable minCosPA{"minCosPA", 0.9, "Min cosPA of decay3body candidate"}; - Configurable maxChi2{"maxChi2", 100.0, "Max chi2 of decay3body candidate"}; - } decay3bodyBuilderOpts; - - struct : ConfigurableGroup { - std::string prefix = "eventMixingOpts"; - Configurable minPt2V0{"minPt2V0", 0.5, "Min Pt squared of V0"}; - Configurable maxTgl2V0{"maxTgl2V0", 4, "Max tgl squared of V0"}; - Configurable maxDCAXY2ToMeanVertex3bodyV0{"maxDCAXY2ToMeanVertex3bodyV0", 4, "Max DCA XY squared of V0 to mean vertex"}; - Configurable minCosPAXYMeanVertex3bodyV0{"minCosPAXYMeanVertex3bodyV0", 0.9, "Min cosPA XY of V0 to mean vertex"}; - Configurable minCosPA3bodyV0{"minCosPA3bodyV0", 0.8, "Min cosPA of V0"}; - Configurable maxRDiffV03body{"maxRDiffV03body", 3, "Max RDiff of V0 to 3body"}; - Configurable minPt3Body{"minPt3Body", 0.5, "Min Pt of 3body"}; - Configurable maxTgl3Body{"maxTgl3Body", 0.01, "Max tgl of 3body"}; - Configurable maxDCAXY3Body{"maxDCAXY3Body", 0.5, "Max DCA XY of 3body"}; - Configurable maxDCAZ3Body{"maxDCAZ3Body", 1.0, "Max DCA Z of 3body"}; - } eventMixingOpts; - - struct : ConfigurableGroup { - std::string prefix = "tofPIDOpts"; - Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; - Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; - Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; - Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; - Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; - Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; - Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; - } tofPIDOpts; - - - Service ccdb; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - - int mRunNumber; - o2::base::MatLayerCylSel* lut = nullptr; - - HistogramRegistry registry{"Registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - - std::vector sorted_decay3body; - - // bachelor TOF PID - o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init base on the hypothesis - o2::pid::tof::TOFResoParamsV2 mRespParamsV2; - - // event mixing selection - std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda - bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc - - // skimmed processing - Zorro zorro; - OutputObj zorroSummary{"zorroSummary"}; - - - // ========================== - std::vector VtxCandidates; - - std::unordered_map ccdbCache; // Maps runNumber -> d_bz - std::unordered_map> grpMagCache; // Maps runNumber -> grpmap - - - std::vector fTrackedClSizeVector; - - // Configurables - Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; - - enum Hyp3Body { kH3L = 0, - kH4L, - kHe4L, - kHe5L, - kNHyp3body }; - - enum VtxStep { kVtxAll = 0, - kVtxTPCNcls, - kVtxPIDCut, - kVtxhasSV, - kVtxDcaDau, - kVtxCosPA, - kNVtxSteps }; - - enum kfvtxstep { kKfVtxAll = 0, - kKfVtxCharge, - kKfVtxEta, - kKfVtxTPCNcls, - kKfVtxTPCRows, - kKfVtxTPCPID, - kKfVtxDCAxyPV, - kKfVtxDCAzPV, - kKfVtxV0MassConst, - kKfVtxhasSV, - kKfVtxDcaDau, - kKfVtxDcaDauVtx, - kKfVtxDauPt, - kKfVtxRap, - kKfVtxPt, - kKfVtxMass, - kKfVtxCosPA, - kKfVtxCosPAXY, - kKfVtxChi2geo, - kKfVtxTopoConstr, - kKfVtxChi2topo, - kKfNVtxSteps }; - - - - // for KFParticle reconstruction - struct : ConfigurableGroup { - Configurable cfgOnlyKeepInterestedTrigger{"kfparticleConfigurations.cfgOnlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; - Configurable fillCandidateFullTable{"kfparticleConfigurations.fillCandidateFullTable", false, "Switch to fill full table with candidate properties"}; - Configurable doSel8selection{"kfparticleConfigurations.doSel8selection", true, "flag for sel8 event selection"}; - Configurable doPosZselection{"kfparticleConfigurations.doPosZselection", true, "flag for posZ event selection"}; - - Configurable applyTopoSel{"kfparticleConfigurations.applyTopoSel", false, "Apply selection constraining the mother to the PV with KFParticle"}; - Configurable maxChi2topo{"kfparticleConfigurations.maxChi2topo", 1000., "Maximum chi2 topological with KFParticle"}; - // 3body mixing - Configurable mixingType{"kfparticleConfigurations.mixingType", 0, "0: mix V0 from one event with bachelor from another, 1: mix pion and bachelor from one event with proton from another "}; - ConfigurableAxis bins3BodyRadius{"kfparticleConfigurations.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}, "Mixing bins - 3body radius"}; - // ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f*TMath::Pi()/180, -170.0f*TMath::Pi()/180, -160.0f*TMath::Pi()/180, -150.0f*TMath::Pi()/180, -140.0f*TMath::Pi()/180, -130.0f*TMath::Pi()/180, -120.0f*TMath::Pi()/180, -110.0f*TMath::Pi()/180, -100.0f*TMath::Pi()/180, -90.0f*TMath::Pi()/180, -80.0f*TMath::Pi()/180, -70.0f*TMath::Pi()/180, -60.0f*TMath::Pi()/180, -50.0f*TMath::Pi()/180, -40.0f*TMath::Pi()/180, -30.0f*TMath::Pi()/180, -20.0f*TMath::Pi()/180, -10.0f*TMath::Pi()/180, 0.0f, 10.0f*TMath::Pi()/180, 20.0f*TMath::Pi()/180, 30.0f*TMath::Pi()/180, 40.0f*TMath::Pi()/180, 50.0f*TMath::Pi()/180, 60.0f*TMath::Pi()/180, 70.0f*TMath::Pi()/180, 80.0f*TMath::Pi()/180, 90.0f*TMath::Pi()/180, 100.0f*TMath::Pi()/180, 110.0f*TMath::Pi()/180, 120.0f*TMath::Pi()/180, 130.0f*TMath::Pi()/180, 140.0f*TMath::Pi()/180, 150.0f*TMath::Pi()/180, 160.0f*TMath::Pi()/180, 170.0f*TMath::Pi()/180, 180.0f*TMath::Pi()/180}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPosZ{"kfparticleConfigurations.bins3BodyPosZ", {VARIABLE_WIDTH, -300.0f, -42.0f, -13.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 13.0f, 42.0f, 300.0f}, "Mixing bins - 3body z position"}; - Configurable selectVtxZ3bodyMixing{"kfparticleConfigurations.selectVtxZ3bodyMixing", true, "Select same VtxZ events in case of 3body mixing"}; - Configurable VtxZBin3bodyMixing{"kfparticleConfigurations.VtxZBin3bodyMixing", 1., "Bin width for event vtx z position in case of 3body mixing"}; - } kfparticleConfigurations; - - //------------------------------------------------------------------ - // Sets for DCAFitter event mixing - struct : ConfigurableGroup { - // Binning for mixing events - ConfigurableAxis binsVtxZ{"dcaFitterEMSel.binsVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis binsMultiplicity{"dcaFitterEMSel.binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - multiplicity"}; - Configurable maxDeltaRadiusColMixing{"dcaFitterEMSel.maxDeltaRadiusColMixing", 2., "max difference between pv z position in case of collision mixing"}; - Configurable maxDeltaPhiColMixing{"dcaFitterEMSel.maxDeltaPhiColMixing", 30., "max difference between Phi of monther particle in case of collision mixing (degree)"}; - // Configurations for mixing decay3bodys - // Configurable cfgUseDCAFitterInfo{"dcaFitterEMSel.cfgUseDCAFitterInfo", true, ""}; // if use information from dcatFitter while mixing reduced 3bodys - Configurable cfgMix3BodyMethod{"dcaFitterEMSel.cfgMix3BodyMethod", 0, ""}; // 0: bachelor, 1: pion, 2: proton - Configurable cfgApplyV0Cut{"dcaFitterEMSel.cfgApplyV0Cut", true, "if apply V0 cut while performing event-mixing"}; - ConfigurableAxis bins3BodyRadius{"dcaFitterEMSel.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 2.0f, 4.0f, 7.0f, 10.0f, 14.0f, 18.0f, 22.0f, 30.0f, 40.0f}, "Mixing bins - 3body radius"}; - ConfigurableAxis bins3BodyPhi{"dcaFitterEMSel.bins3BodyPhi", {VARIABLE_WIDTH, -3.15, -2.15, -1, 0, 1, 2.15, 3.15}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPhiDegree{"dcaFitterEMSel.bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi"}; - ConfigurableAxis bins3BodyPosZ{"dcaFitterEMSel.bins3BodyPosZ", {VARIABLE_WIDTH, -500.0f, -200.0f, -100.0f, -70.0f, -60.0f, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -20.0f, -15.0f, -13.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f, 13.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f, 60.0f, 70.0f, 100.0f, 200.0f, 500.0f}, "3body SV z position"}; - Configurable selectPVPosZ3bodyMixing{"dcaFitterEMSel.selectPVPosZ3bodyMixing", true, "Select same pvPosZ events in case of 3body mixing"}; - Configurable maxDeltaPVPosZ3bodyMixing{"dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing", 1., "max difference between pv z position in case of 3body mixing"}; - } dcaFitterEMSel; - - SliceCache cache; - using BinningTypeColEM = ColumnBinningPolicy; - using Binning3BodyDCAFitter = ColumnBinningPolicy; - using Binning3BodyKFInfo = ColumnBinningPolicy; - - // KF event mixing - using BinningTypeKF = ColumnBinningPolicy; - - // 3body mixing - using Binning3Body = ColumnBinningPolicy; - - // Filters and slices - Preslice perCollision = o2::aod::decay3body::collisionId; - Preslice perReducedCollision = o2::aod::reduceddecay3body::collisionId; - - int mRunNumber; - float d_bz; - - o2::pid::tof::TOFResoParamsV2 mRespParamsV2; - std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda - bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc - o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; - - - // ========================== - - - - - - void init(InitContext&) - { - zorroSummary.setObject(zorro.getZorroSummary()); - - mRunNumber = 0; - d_bz = 0; - - mEnabledTables.resize(nTables, 0); - - // CCDB options - ccdb->setURL(ccdbConfigurations.ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - // Set material correction - if (useMatCorrType == 1) { - LOGF(info, "TGeo correction requested, loading geometry"); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(ccdbConfigurations.geoPath); - } - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - } - if (useMatCorrType == 2) { - LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbConfigurations.lutPath)); - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - } - - fitterV0.setMatCorrType(matCorr); - fitter3body.setMatCorrType(matCorr); - - // set bachelor PID - bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); - - // set decay3body parameters in the helper - helper.decay3bodyselections.maxEtaDaughters = decay3bodyBuilderOpts.maxEtaDaughters; - helper.decay3bodyselections.minTPCNClProton = decay3bodyBuilderOpts.minTPCNClProton; - helper.decay3bodyselections.minTPCNClPion = decay3bodyBuilderOpts.minTPCNClPion; - helper.decay3bodyselections.minTPCNClBach = decay3bodyBuilderOpts.minTPCNClBach; - helper.decay3bodyselections.minDCAProtonToPV = decay3bodyBuilderOpts.minDCAProtonToPV; - helper.decay3bodyselections.minDCAPionToPV = decay3bodyBuilderOpts.minDCAPionToPV; - helper.decay3bodyselections.minDCABachToPV = decay3bodyBuilderOpts.minDCABachToPV; - helper.decay3bodyselections.minPtProton = decay3bodyBuilderOpts.minPtProton; - helper.decay3bodyselections.minPtPion = decay3bodyBuilderOpts.minPtPion; - helper.decay3bodyselections.minPtBach = decay3bodyBuilderOpts.minPtBach; - helper.decay3bodyselections.maxPtProton = decay3bodyBuilderOpts.maxPtProton; - helper.decay3bodyselections.maxPtPion = decay3bodyBuilderOpts.maxPtPion; - helper.decay3bodyselections.maxPtBach = decay3bodyBuilderOpts.maxPtBach; - helper.decay3bodyselections.maxTPCnSigma = decay3bodyBuilderOpts.maxTPCnSigma; - helper.decay3bodyselections.minTOFnSigmaDeuteron = decay3bodyBuilderOpts.minTOFnSigmaDeuteron; - helper.decay3bodyselections.maxTOFnSigmaDeuteron = decay3bodyBuilderOpts.maxTOFnSigmaDeuteron; - helper.decay3bodyselections.minPBachUseTOF = decay3bodyBuilderOpts.minPBachUseTOF; - helper.decay3bodyselections.maxDCADauAtSV = decay3bodyBuilderOpts.maxDCADauAtSV; - helper.decay3bodylelections.maxRapidity = decay3bodyBuilderOpts.maxRapidity; - helper.decay3bodyselections.minPt = decay3bodyBuilderOpts.minPt; - helper.decay3bodyselections.maxPt = decay3bodyBuilderOpts.maxPt; - helper.decay3bodyselections.minMass = decay3bodyBuilderOpts.minMass; - helper.decay3bodyselections.maxMass = decay3bodyBuilderOpts.maxMass; - helper.decay3bodyselections.minCtau = decay3bodyBuilderOpts.minCtau; - helper.decay3bodyselections.maxCtau = decay3bodyBuilderOpts.maxCtau; - helper.decay3bodyselections.minCosPA = decay3bodyBuilderOpts.minCosPA; - helper.decay3bodyselections.maxChi2 = decay3bodyBuilderOpts.maxChi2; - - // set SVertexer selection parameters in the helper - helper.svselections.minPt2V0 = eventMixingOpts.minPt2V0; - helper.svselections.maxTgl2V0 = eventMixingOpts.maxTgl2V0; - helper.svselections.maxDCAXY2ToMeanVertex3bodyV0 = eventMixingOpts.maxDCAXY2ToMeanVertex3bodyV0; - helper.svselections.minCosPAXYMeanVertex3bodyV0 = eventMixingOpts.minCosPAXYMeanVertex3bodyV0; - helper.svselections.minCosPA3bodyV0 = eventMixingOpts.minCosPA3bodyV0; - helper.svselections.maxRDiffV03body = eventMixingOpts.maxRDiffV03body; - helper.svselections.minPt3Body = eventMixingOpts.minPt3Body; - helper.svselections.maxTgl3Body = eventMixingOpts.maxTgl3Body; - helper.svselections.maxDCAXY3Body = eventMixingOpts.maxDCAXY3Body; - helper.svselections.maxDCAZ3Body = eventMixingOpts.maxDCAZ3Body; - - // configure tables to generate - // setup bookkeeping histograms - auto h = registry.add("hTableBuildingStatistics", "hTableBuildingStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); - auto h2 = registry.add("hInputStatistics", "hInputStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); - h2->SetTitle("Input table sizes"); - - for (int i = 0; i < nTables; i++) { - h->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); - h->SetBinContent(i + 1, -1); // mark all as disabled to start - - int f = enabledTables->get(tableNames[i].c_str(), "enable"); - if (f == 1) { - mEnabledTables[i] = 1; - h->SetBinContent(i + 1, 0); // mark enabled - } - } - - // list enabled process functions - LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); - LOGF(info, " Decay3body builder: basic configuration listing"); - LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); - - if (doprocessRealData) { - LOGF(info, " ===> process function enabled: processRealData"); - } - if (doprocessRealDataReduced) { - LOGF(info, " ===> process function enabled: processRealData"); - } - if (doprocessMonteCarlo) { - LOGF(info, " ===> process function enabled: processMonteCarlo"); - } - if (doprocessEventMixing) { - LOGF(info, " ===> process function enabled: processEventMixing"); - } - - // list enabled tables - for (int i = 0; i < nTables; i++) { - // printout to be improved in the future - if (mEnabledTables[i]) { - LOGF(info, " -~> Table enabled: %s", tableNames[i]); - } - } - // print base cuts - LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); - LOGF(info, "-~> max daughter eta ..............: %i", decay3bodyBuilderOpts.maxEtaDaughters.value); - LOGF(info, "-~> min TPC ncls proton ...........: %i", decay3bodyBuilderOpts.minTPCNClProton.value); - LOGF(info, "-~> min TPC ncls pion .............: %i", decay3bodyBuilderOpts.minTPCNClPion.value); - LOGF(info, "-~> min TPC ncls bach .............: %i", decay3bodyBuilderOpts.minTPCNClBach.value); - LOGF(info, "-~> min DCA proton to PV ..........: %f", decay3bodyBuilderOpts.minDCAProtonToPV.value); - LOGF(info, "-~> min DCA pion to PV ............: %f", decay3bodyBuilderOpts.minDCAPionToPV.value); - LOGF(info, "-~> min DCA bach to PV ............: %f", decay3bodyBuilderOpts.minDCABachToPV.value); - LOGF(info, "-~> min pT proton .................: %f", decay3bodyBuilderOpts.minPtProton.value); - LOGF(info, "-~> min pT pion ...................: %f", decay3bodyBuilderOpts.minPtPion.value); - LOGF(info, "-~> min pT bach ...................: %f", decay3bodyBuilderOpts.minPtBach.value); - LOGF(info, "-~> max pT proton .................: %f", decay3bodyBuilderOpts.maxPtProton.value); - LOGF(info, "-~> max pT pion ...................: %f", decay3bodyBuilderOpts.maxPtPion.value); - LOGF(info, "-~> max pT bach ...................: %f", decay3bodyBuilderOpts.maxPtBach.value); - LOGF(info, "-~> max TPC nSigma ...............: %f", decay3bodyBuilderOpts.maxTPCnSigma.value); - LOGF(info, "-~> min TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.minTOFnSigmaDeuteron.value); - LOGF(info, "-~> max TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.maxTOFnSigmaDeuteron.value); - LOGF(info, "-~> min p bach use TOF ...........: %f", decay3bodyBuilderOpts.minPBachUseTOF.value); - LOGF(info, "-~> max DCA dau at SV ............: %f", decay3bodyBuilderOpts.maxDCADauAtSV.value); - LOGF(info, "-~> max rapidity .................: %f", decay3bodyBuilderOpts.maxRapidity.value); - LOGF(info, "-~> min pT .......................: %f", decay3bodyBuilderOpts.minPt.value); - LOGF(info, "-~> max pT .......................: %f", decay3bodyBuilderOpts.maxPt.value); - LOGF(info, "-~> min mass .....................: %f", decay3bodyBuilderOpts.minMass.value); - LOGF(info, "-~> max mass .....................: %f", decay3bodyBuilderOpts.maxMass.value); - LOGF(info, "-~> min ctau .....................: %f", decay3bodyBuilderOpts.minCtau.value); - LOGF(info, "-~> max ctau .....................: %f", decay3bodyBuilderOpts.maxCtau.value); - LOGF(info, "-~> min cosPA ....................: %f", decay3bodyBuilderOpts.minCosPA.value); - LOGF(info, "-~> max chi2 .....................: %f", decay3bodyBuilderOpts.maxChi2.value); - LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); - - // Add histograms separately for different process functions - if (doprocessRealData == true || doprocessRealDataReduced == true) { - registry.add("hEventCounter", "Counters/hEventCounter", HistType::kTH1F, {{1, 0.0f, 1.0f}}); - } - - if (doTrackQA) { - registry.add("QA/Tracks/hTrackPosTPCNcls", "hTrackPosTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); - registry.add("QA/Tracks/hTrackNegTPCNcls", "hTrackNegTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); - registry.add("QA/Tracks/hTrackBachTPCNcls", "hTrackBachTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); - registry.add("QA/Tracks/hTrackPosHasTPC", "hTrackPosHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); - registry.add("QA/Tracks/hTrackNegHasTPC", "hTrackNegHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); - registry.add("QA/Tracks/hTrackBachHasTPC", "hTrackBachHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); - registry.add("QA/Tracks/hTrackProtonTPCPID", "hTrackProtonTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); - registry.add("QA/Tracks/hTrackPionTPCPID", "hTrackPionTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); - registry.add("QA/Tracks/hTrackBachTPCPID", "hTrackBachTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); - registry.add("QA/Tracks/hTrackProtonPt", "hTrackProtonPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); - registry.add("QA/Tracks/hTrackPionPt", "hTrackPionPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); - registry.add("QA/Tracks/hTrackBachPt", "hTrackBachPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); - } - if (doEventQA) { - registry.add("QA/Event/hAllSelEventsVtxZ", "hAllSelEventsVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); - registry.add("QA/Event/hVtxX", "hVtxX", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV X (cm)"}}); - registry.add("QA/Event/hVtxY", "hVtxY", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV Y (cm)"}}); - registry.add("QA/Event/hVtxZ", "hVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); - registry.add("QA/Event/hVtxCovXX", "hVtxCovXX", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XX) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovYY", "hVtxCovYY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YY) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovZZ", "hVtxCovZZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(ZZ) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovXY", "hVtxCovXY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XY) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovXZ", "hVtxCovXZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XZ) (cm^{2})"}}); - registry.add("QA/Event/hVtxCovYZ", "hVtxCovYZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); - } - - // if (doprocessRun3 == true || doprocessRun3Reduced || doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { - // auto hVtx3BodyCounter = registry.add("hVtx3BodyCounter", "hVtx3BodyCounter", HistType::kTH1D, {{6, 0.0f, 6.0f}}); - // hVtx3BodyCounter->GetXaxis()->SetBinLabel(1, "Total"); - // hVtx3BodyCounter->GetXaxis()->SetBinLabel(2, "TPCNcls"); - // hVtx3BodyCounter->GetXaxis()->SetBinLabel(3, "PIDCut"); - // hVtx3BodyCounter->GetXaxis()->SetBinLabel(4, "HasSV"); - // hVtx3BodyCounter->GetXaxis()->SetBinLabel(5, "DcaDau"); - // hVtx3BodyCounter->GetXaxis()->SetBinLabel(6, "CosPA"); - // registry.add("hBachelorTOFNSigmaDe", "", HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}); - // } - - // if (doprocessRun3ReducedEM == true) { - // registry.add("hEventCount", "hEventCount", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - // registry.add("hEventPairs", "hEventPairs", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - // registry.add("hDecay3BodyPairsBeforeCut", "hDecay3BodyPairsBeforeCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - // registry.add("hDecay3BodyPairsAfterCut", "hDecay3BodyPairsAfterCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); - // registry.add("hRadius0", "hRadius0", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - // registry.add("hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - // registry.add("hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{400, -20.0f, 20.0f, "#Delta Radius (cm)"}}); - // registry.add("hPhi0", "hPhi0", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); - // registry.add("hPhi1", "hPhi1", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); - // registry.add("hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, -180.0f, 180.0f, "#Delta #phi (degree)"}}); - // } - - // if (doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { - // registry.add("hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}); - // registry.add("hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {dcaFitterEMSel.bins3BodyPosZ}); - // auto h3bodyCombinationCounter = registry.add("h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "bach sign/ID"); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "not same collision"); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "collision VtxZ"); - // } - - // if (doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { - // doUpdateGRPMagField = true; - // registry.add("h3bodyEMCutCounter", "h3bodyEMCutCounter", HistType::kTH1D, {{14, 0.0f, 14.0f}}); - // } - - // if (doprocessRun3withKFParticle == true || doprocessRun3withKFParticleStrangenessTracking == true || doprocessRun3withKFParticleReduced == true || doprocessRun3withKFParticleReducedEM == true || doprocessRun3withKFParticleReduced3bodyMixing == true) { - // auto hEventCounterZorro = registry.add("Counters/hEventCounterZorro", "hEventCounterZorro", HistType::kTH1D, {{2, -0.5, 1.5}}); - // hEventCounterZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); - // hEventCounterZorro->GetXaxis()->SetBinLabel(2, "Zorro after evsel"); - // auto hEventCounterKFParticle = registry.add("Counters/hEventCounterKFParticle", "hEventCounterKFParticle", HistType::kTH1D, {{4, 0.0f, 4.0f}}); - // hEventCounterKFParticle->GetXaxis()->SetBinLabel(1, "total"); - // hEventCounterKFParticle->GetXaxis()->SetBinLabel(2, "sel8"); - // hEventCounterKFParticle->GetXaxis()->SetBinLabel(3, "vertexZ"); - // hEventCounterKFParticle->GetXaxis()->SetBinLabel(4, "has candidate"); - // hEventCounterKFParticle->LabelsOption("v"); - // auto hVtx3BodyCounterKFParticle = registry.add("Counters/hVtx3BodyCounterKFParticle", "hVtx3BodyCounterKFParticle", HistType::kTH1D, {{21, 0.0f, 21.0f}}); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(1, "Total"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(2, "Charge"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(3, "Eta"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(4, "TPCNcls"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(5, "TPCRows"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(6, "TPCpid"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(7, "DCAxyPV"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(8, "DCAzPV"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(9, "V0MassConst"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(10, "HasSV"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(11, "DcaDau"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(12, "DCADauVtx"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(13, "DauPt"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(14, "Rapidity"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(15, "Pt"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(16, "Mass"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(17, "CosPA"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(18, "CosPAXY"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(19, "Chi2geo"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(20, "TopoConstr"); - // hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(21, "Chi2topo"); - // hVtx3BodyCounterKFParticle->LabelsOption("v"); - // } - - // if (doprocessRun3withKFParticleReducedEM == true) { - // registry.add("QA/EM/hPairCounterMixing", "hPairCounterMixing", HistType::kTH1D, {{1, 0.0f, 1.0f}}); - // auto hCombinationCounterMixing = registry.add("QA/EM/hCombinationCounterMixing", "hCombinationCounterMixing", HistType::kTH1D, {{3, 0.0f, 3.0f}}); - // hCombinationCounterMixing->GetXaxis()->SetBinLabel(1, "total"); - // hCombinationCounterMixing->GetXaxis()->SetBinLabel(2, "bach sign/ID"); - // hCombinationCounterMixing->GetXaxis()->SetBinLabel(3, "radius, phi"); - // hCombinationCounterMixing->LabelsOption("v"); - - // registry.add("QA/EM/hEventBinCounts", "hEventBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); - // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); - // registry.add("QA/EM/hPairBinCounts", "hPairBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); - - // registry.add("QA/EM/hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - // registry.add("QA/EM/hRadius2", "hRadius2", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); - // registry.add("QA/EM/hPhi1", "hPhi1", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); - // registry.add("QA/EM/hPhi2", "hPhi2", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); - // registry.add("QA/EM/hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{200, 0.0f, 10.0f, "#Delta Radius (cm)"}}); - // registry.add("QA/EM/hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, 0.0f, 360.0f, "#Delta #phi (degree)"}}); - // } - - // if (doprocessRun3withKFParticleReduced3bodyMixing == true) { - // auto h3bodyCombinationCounter = registry.add("QA/EM/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "not same collision"); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "collision VtxZ"); - // h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "bach sign/ID"); - // h3bodyCombinationCounter->LabelsOption("v"); - // // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH3D, {{16, 0, 16, "bins radius"}, {36, 0, 36, "bins phi"}, {12, 0, 12, "bins pos Z"}}); - // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{16, 0, 16, "bins radius"}, {18, 0, 18, "bins phi"}}); - - // AxisSpec radiusAxis = {kfparticleConfigurations.bins3BodyRadius, "Radius (cm)"}; - // AxisSpec phiAxis = {kfparticleConfigurations.bins3BodyPhi, "#phi (degree)"}; - // AxisSpec posZAxis = {kfparticleConfigurations.bins3BodyPosZ, "position in z (cm)"}; - - // registry.add("QA/EM/hRadius", "hRadius", HistType::kTH1F, {radiusAxis}); - // registry.add("QA/EM/hPhi", "hPhi", HistType::kTH1F, {phiAxis}); - // registry.add("QA/EM/hPosZ", "hPosZ", HistType::kTH1F, {posZAxis}); - // } - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - if (doSkimmedProcessing) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); - zorro.populateHistRegistry(registry, bc.runNumber()); - } - - auto timestamp = bc.timestamp(); - o2::parameters::GRPMagField* grpmag = 0x0; - grpmag = ccdb->getForTimeStamp(ccdbConfigurations.grpmagPath, timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField for timestamp " << timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - // Fetch magnetic field from ccdb for current collision - auto d_bz = o2::base::Propagator::Instance()->getNominalBz(); - LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << magneticField << " kG"; - - // set magnetic field value for DCA fitter - fitterV0.setBz(d_bz); - fitter3body.setBz(d_bz); -// Set magnetic field for KF vertexing -#ifdef HomogeneousField - KFParticle::SetField(d_bz); -#endif - - if (useMatCorrType == 2) { - // setMatLUT only after magfield has been initalized - // (setMatLUT has implicit and problematic init field call if not) - LOG(info) << "Loading material look-up table for timestamp: " << timestamp; - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); - o2::base::Propagator::Instance()->setMatLUT(lut); - helper.lut = lut; - } - - // mark run as configured - mRunNumber = bc.runNumber(); - - // Initial TOF PID Paras, copied from PIDTOF.h - tofPIDOpts.timestamp.value = bc.timestamp(); - ccdb->setTimestamp(tofPIDOpts.timestamp.value); - // Not later than now objects - ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - // TODO: implement the automatic pass name detection from metadata - if (tofPIDOpts.passName.value == "") { - tofPIDOpts.passName.value = "unanchored"; // temporary default - LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << tofPIDOpts.passName.value << "'"; - } - LOG(info) << "Using parameter collection, starting from pass '" << tofPIDOpts.passName.value << "'"; - - const std::string fname = tofPIDOpts.paramFileName.value; - if (!fname.empty()) { // Loading the parametrization from file - LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << tofPIDOpts.parametrizationPath.value; - if (1) { - o2::tof::ParameterCollection paramCollection; - paramCollection.loadParamFromFile(fname, tofPIDOpts.parametrizationPath.value); - LOG(info) << "+++ Loaded parameter collection from file +++"; - if (!paramCollection.retrieveParameters(mRespParamsV2, tofPIDOpts.passName.value)) { - if (tofPIDOpts.fatalOnPassNotAvailable) { - LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); - } else { - LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); - } - } else { - mRespParamsV2.setShiftParameters(paramCollection.getPars(tofPIDOpts.passName.value)); - mRespParamsV2.printShiftParameters(); - } - } else { - mRespParamsV2.loadParamFromFile(fname.data(), tofPIDOpts.parametrizationPath.value); - } - } else if (tofPIDOpts.loadResponseFromCCDB) { // Loading it from CCDB - LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << tofPIDOpts.parametrizationPath.value << " for timestamp " << timestamp.value; - o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(tofPIDOpts.parametrizationPath.value, timestamp.value); - paramCollection->print(); - if (!paramCollection->retrieveParameters(mRespParamsV2, tofPIDOpts.passName.value)) { // Attempt at loading the parameters with the pass defined - if (tofPIDOpts.fatalOnPassNotAvailable) { - LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); - } else { - LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", tofPIDOpts.passName.value.data()); - } - } else { // Pass is available, load non standard parameters - mRespParamsV2.setShiftParameters(paramCollection->getPars(tofPIDOpts.passName.value)); - mRespParamsV2.printShiftParameters(); - } - } - mRespParamsV2.print(); - if (tofPIDOpts.timeShiftCCDBPath.value != "") { - if (tofPIDOpts.timeShiftCCDBPath.value.find(".root") != std::string::npos) { - mRespParamsV2.setTimeShiftParameters(tofPIDOpts.timeShiftCCDBPath.value, "gmean_Pos", true); - mRespParamsV2.setTimeShiftParameters(tofPIDOpts.timeShiftCCDBPath.value, "gmean_Neg", false); - } else { - mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", tofPIDOpts.timeShiftCCDBPath.value.c_str()), tofPIDOpts.timestamp.value), true); - mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", tofPIDOpts.timeShiftCCDBPath.value.c_str()), tofPIDOpts.timestamp.value), false); - } - } - - bachelorTOFPID.SetParams(mRespParamsV2); - } - - void initCCDBfromRunNumber(int runNumber) - { - // set magnetic field only when run number changes - if (mRunNumber == runNumber) { - LOG(debug) << "CCDB initialized for run " << mRunNumber; - return; - } - mRunNumber = runNumber; // Update the last run number - - // Check if the CCDB data for this run is already cached - if (ccdbCache.find(runNumber) != ccdbCache.end()) { - LOG(debug) << "CCDB data already cached for run " << runNumber; - d_bz = ccdbCache[runNumber]; - if (doUpdateGRPMagField == true) { - o2::base::Propagator::initFieldFromGRP(grpMagCache[runNumber].get()); - } - } else { - std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(ccdbConfigurations.grpmagPath, runNumber)); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.grpPath << " of object GRPObject for run number " << runNumber; - } - o2::base::Propagator::initFieldFromGRP(grpmag.get()); - // Fetch magnetic field from ccdb for current collision - d_bz = o2::base::Propagator::Instance()->getNominalBz(); - LOG(info) << "Retrieved GRP for run number " << runNumber << " with magnetic field of " << d_bz << " kZG"; - - ccdbCache[runNumber] = d_bz; - grpMagCache[runNumber] = grpmag; - } - - // Set magnetic field for KF vertexing -#ifdef HomogeneousField - KFParticle::SetField(d_bz); -#endif - // Set field for DCAfitter - fitterV0.setBz(d_bz); - fitter3body.setBz(d_bz); - - mV0Hyps[0].set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, d_bz); - mV0Hyps[1].set(o2::track::PID::Lambda, o2::track::PID::Pion, o2::track::PID::Proton, pidCutsLambda, d_bz); - - if (useMatCorrType == 2) { - // setMatLUT only after magfield has been initalized - o2::base::Propagator::Instance()->setMatLUT(lut); - } - - // cache magnetic field info - ccdbCache[runNumber] = d_bz; - } - - - - - //------------------------------------------------------------------ - // event mixing - template - void doMixed3Body(TMixed3bodys decay3bodys, TBinningType binningType) - { - // Strictly upper index policy for decay3body objects binned by radius, phi - for (const auto& [decay3body0, decay3body1] : selfCombinations(binningType, dcaFitterEMSel.nUseMixed, -1, decay3bodys, decay3bodys)) { - auto tpos0 = decay3body0.template track0_as(); - auto tneg0 = decay3body0.template track1_as(); - auto tbach0 = decay3body0.template track2_as(); - auto tpos1 = decay3body1.template track0_as(); - auto tneg1 = decay3body1.template track1_as(); - auto tbach1 = decay3body1.template track2_as(); - - registry.fill(HIST("h3bodyCombinationCounter"), 0.5); - - // ---------- selections ---------- - if ((tbach0.sign() > 0 && !(tbach1.sign() > 0)) || (tbach0.sign() < 0 && !(tbach1.sign() < 0)) || tbach0.globalIndex() == tbach1.globalIndex()) { // only combine if tbach1 has correct sign and is not same as tbach0 - continue; - } - registry.fill(HIST("h3bodyCombinationCounter"), 1.5); - - if (decay3body0.collisionId() == decay3body1.collisionId()) { // only combine if from different event - continue; - } - registry.fill(HIST("h3bodyCombinationCounter"), 2.5); - - auto c0 = decay3body0.template collision_as(); - auto c1 = decay3body1.template collision_as(); - - if (dcaFitterEMSel.selectPVPosZ3bodyMixing && std::abs(c0.posZ() - c1.posZ()) > dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing) { // only combine if collision similar in PV posZ - continue; - } - registry.fill(HIST("h3bodyCombinationCounter"), 3.5); - - initCCDBfromRunNumber(c0.runNumber()); - - if (dcaFitterEMSel.cfgMix3BodyMethod == 0) { // mix bachelor (deuteron) - fillVtxCand(c0, tpos0, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); - fillVtxCand(c1, tpos1, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); - } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() > 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() < 0)) { // mix piMinus or proton - fillVtxCand(c0, tpos0, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); - fillVtxCand(c1, tpos1, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); - } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() < 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() > 0)) { // mix piPlus or anti-proton - fillVtxCand(c0, tpos1, tneg0, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); - fillVtxCand(c1, tpos0, tneg1, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); - } - - VtxCandidates.clear(); - } // end decay3body combinations loop - } - //------------------------------------------------------------------ - // fill the StoredVtx3BodyDatas table - void fillVtx3BodyTable(VtxCandidate const& candVtx) - { - vtx3bodydata( - candVtx.track0Id, candVtx.track1Id, candVtx.track2Id, candVtx.collisionId, candVtx.decay3bodyId, - candVtx.vtxPos[0], candVtx.vtxPos[1], candVtx.vtxPos[2], - candVtx.track0P[0], candVtx.track0P[1], candVtx.track0P[2], candVtx.track1P[0], candVtx.track1P[1], candVtx.track1P[2], candVtx.track2P[0], candVtx.track2P[1], candVtx.track2P[2], - candVtx.dcadaughters, - candVtx.daudcaxytopv[0], candVtx.daudcaxytopv[1], candVtx.daudcaxytopv[2], - candVtx.daudcatopv[0], candVtx.daudcatopv[1], candVtx.daudcatopv[2], - candVtx.bachelortofNsigma); - } - - //------------------------------------------------------------------ - //-------------------- KFParticle reconstruction ------------------- - //------------------------------------------------------------------ - - template - double getTOFnSigma(TCollision const& collision, TTrack const& track, bool isEventMixing) - { - // TOF PID of deuteron (set motherhyp correctly) - double tofNSigmaDeuteron = -999; - if (track.has_collision() && track.hasTOF()) { - if (isEventMixing) { - tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, collision, collision); - } else { - auto originalcol = track.template collision_as(); - tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); - } - } - return tofNSigmaDeuteron; - } - - - // ______________________________________________________________ - // function to build decay3body candidates - template - void buildDecay3Bodies(TCollision const& collisions, T3Bodies const& decay3bodies, TTrack const& tracks) - { - if (!mEnabledTables[kStoredDecay3BodyCores]) { - return; // don't do if no request for decay3bodies in place - } - - int nDecay3Bodies = 0; - // Loop over all decay3bodies in same time frame - resgistry.fill(HIST("hInputStatistics"), kStoredDecay3BodyCores, decay3bodies.size()); - for (size_t i3body = 0; i3body < decay3bodies.size(); i3body++) { - // Get tracks and generate candidate - auto const& decay3body = decay3bodies[sorted_decay3body[i3body]]; /// TODO: FIX!! - // if collisionId positive: get vertex, negative: origin - float pvX = 0.0f, pvY = 0.0f, pvZ = 0.0f; - if (decay3body.collisionId >= 0) { - auto const& collision = collisions.rawIteratorAt(decay3body.collisionID); - pvX = collision.posX(); - pvY = collision.posY(); - pvZ = collision.posZ(); - } - - // Aquire tracks - auto const& trackPos = tracks.rawIteratorAt(decay3body.trackPosID); - auto const& trackNeg = tracks.rawIteratorAt(decay3body.trackNegID); - auto const& trackBach = tracks.rawIteratorAt(decay3body.traclBachID); - - // Calculate TOD nSigma - /// TODO: Calculate TOD nSigma - - // generate analysis tables - if (mEnabledTables[kDecay3BodyIndices]) { - products.decay3bodyindices(decay3body.) - registry.fill(HIST("hTableBuildingStatistics"), kDecay3BodyIndices); - } - if (mEnabledTables[kStoredDecay3BodyCores]) { - products.decay3bodycores(); - registry.fill(HIST("hTableBuildingStatistics"), kStoredDecay3BodyCores); - } - if (mEnabledTables[kDecay3BodyCovs]) { - products.decay3bodycovs(); - registry.fill(HIST("hTableBuildingStatistics"), kDecay3BodyCovs); - } - - /// TODO: - // ___________________________________________________________ - // MC handling part - // prepare MC containers (not necessarily used) - std::vector mcCascinfos; // Decay3bodyMCCore information - std::vector mcParticleIsReco; - - if constexpr (soa::is_table) { - // do this if provided with a mcParticle table as well - mcParticleIsReco.resize(mcParticles.size(), false); - - if ((mEnabledTables[kMcDEcay3BodyCores] || mEnabledTables[kMcDEcay3BodyLabels] || mEnabledTables[kMcDecay3BodyCollRefs])) { - extractMonteCarloProperties(); - - // generate label table (joinable with Decay3BodyCores) - if (mEnabledTables[kMcDecay3BodyLabels]) { - products.mcDecay3bodylabels(); - registry.fill(HIST("hTableBuildingStatistics"), kMcDecay3BodyLabels); - } - - // mark mcParticle as reconstructed - if (thisDecay3bodyInfo.label > -1) { - mcParticleIsReco[thisDecay3bodyInfo.label] = true; - } - - // generate MC cores table (joinable with Decay3BodyCores) - if (mEnabledTables[kMcDecay3BodyCores]) { - products.mcDecay3bodycores(); - registry.fill(HIST("hTableBuildingStatistics"), kMcDecay3BodyCores); - } - if (mEnabledTables[kMcDecay3BodyCollRefs]) { - products.mcDecay3bodycollrefs(thisDecay3bodyInfo.mcCollision); - registry.fill(HIST("hTableBuildingStatistics"), kMcDecay3BodyCollRefs); - } - } // enabled tables check - } // constexpr requires mcParticles check - } // decay3body loop - - /// TODO: - // ____________________________________________________________ - // MC handling part - if constexpr (soa::is_table) { - if ((mEnabledTables[kMcDEcay3BodyCores] || mEnabledTables[kMcDEcay3BodyLabels] || mEnabledTables[kMcDecay3BodyCollRefs])) { - - } // enabled tables check - } // constexpr requires mcParticles check - } - - // ______________________________________________________________ - // function to get MC properties - template - void extractMonteCarloProperties(TTrack const& trackPos, TTrack const& trackNeg, TTrack const& trackBach, TMMParticles const& mcParticles) - { - // encapsulates acquisition of MC properties from MC - thisDecay3bodyInfo.pdgCode = -1, thisDecay3bodyInfo.pdgCodeMother = -1; - thisDecay3bodyInfo.pdgCodePositive = -1, thisDecay3bodyInfo.pdgCodeNegative = -1; - thisDecay3bodyInfo.pdgCodeBachelor = -1, thisDecay3bodyInfo.pdgCodeV0 = -1; - thisDecay3bodyInfo.isPhysicalPrimary = false; - thisDecay3bodyInfo.xyz[0] = -999.0f, thisDecay3bodyInfo.xyz[1] = -999.0f, thisDecay3bodyInfo.xyz[2] = -999.0f; - thisDecay3bodyInfo.lxyz[0] = -999.0f, thisDecay3bodyInfo.lxyz[1] = -999.0f, thisDecay3bodyInfo.lxyz[2] = -999.0f; - thisDecay3bodyInfo.posP[0] = -999.0f, thisDecay3bodyInfo.posP[1] = -999.0f, thisDecay3bodyInfo.posP[2] = -999.0f; - thisDecay3bodyInfo.negP[0] = -999.0f, thisDecay3bodyInfo.negP[1] = -999.0f, thisDecay3bodyInfo.negP[2] = -999.0f; - thisDecay3bodyInfo.bachP[0] = -999.0f, thisDecay3bodyInfo.bachP[1] = -999.0f, thisDecay3bodyInfo.bachP[2] = -999.0f; - thisDecay3bodyInfo.momentum[0] = -999.0f, thisDecay3bodyInfo.momentum[1] = -999.0f, thisDecay3bodyInfo.momentum[2] = -999.0f; - thisDecay3bodyInfo.label = -1, thisDecay3bodyInfo.motherLabel = -1; - thisDecay3bodyInfo.mcParticlePositive = -1; - thisDecay3bodyInfo.mcParticleNegative = -1; - thisDecay3bodyInfo.mcParticleBachelor = -1; - - // association check - if (trackPos.has_mcParticle() && trackNeg.has_mcParticle() && trackBach.has_mcParticle()) { - auto lMCBachTrack = trackPos.template mcParticle_as(); - auto lMCNegTrack = trackNeg.template mcParticle_as(); - auto lMCPosTrack = trackBach.template mcParticle_as(); - - thisDecay3bodyInfo.mcParticlePositive = lMCPosTrack.globalIndex(); - thisDecay3bodyInfo.mcParticleNegative = lMCNegTrack.globalIndex(); - thisDecay3bodyInfo.mcParticleBachelor = lMCBachTrack.globalIndex(); - thisDecay3bodyInfo.pdgCodePositive = lMCPosTrack.pdgCode(); - thisDecay3bodyInfo.pdgCodeNegative = lMCNegTrack.pdgCode(); - thisDecay3bodyInfo.pdgCodeBachelor = lMCBachTrack.pdgCode(); - thisDecay3bodyInfo.posP[0] = lMCPosTrack.px(); - thisDecay3bodyInfo.posP[1] = lMCPosTrack.py(); - thisDecay3bodyInfo.posP[2] = lMCPosTrack.pz(); - thisDecay3bodyInfo.negP[0] = lMCNegTrack.px(); - thisDecay3bodyInfo.negP[1] = lMCNegTrack.py(); - thisDecay3bodyInfo.negP[2] = lMCNegTrack.pz(); - thisDecay3bodyInfo.bachP[0] = lMCBachTrack.px(); - thisDecay3bodyInfo.bachP[1] = lMCBachTrack.py(); - thisDecay3bodyInfo.bachP[2] = lMCBachTrack.pz(); - } - - // treat pi -> mu + antineutrino decays - - - } - - //------------------------------------------------------------------ - // 3body candidate builder with KFParticle - template - void buildVtx3BodyDataTableKFParticle(TCollision const& collision, TTrack const& trackPos, TTrack const& trackNeg, TTrack const& trackBach, int64_t decay3bodyID, int bachelorcharge, double tofNSigmaDeuteron) - { - gROOT->SetBatch(true); - gRandom->SetSeed(42); - - // initialise KF primary vertex - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - KFParticle kfpv(kfpVertex); - LOG(debug) << "Created KF PV."; - - // fill event QA histograms --> only for events with a decay3body! - if (kfparticleConfigurations.doVertexQA) { - registry.fill(HIST("QA/Event/hVtxXKF"), kfpv.GetX()); - registry.fill(HIST("QA/Event/hVtxYKF"), kfpv.GetY()); - registry.fill(HIST("QA/Event/hVtxZKF"), kfpv.GetZ()); - registry.fill(HIST("QA/Event/hVtxCovXXKF"), kfpv.GetCovariance(0)); - registry.fill(HIST("QA/Event/hVtxCovYYKF"), kfpv.GetCovariance(2)); - registry.fill(HIST("QA/Event/hVtxCovZZKF"), kfpv.GetCovariance(5)); - registry.fill(HIST("QA/Event/hVtxCovXYKF"), kfpv.GetCovariance(1)); - registry.fill(HIST("QA/Event/hVtxCovXZKF"), kfpv.GetCovariance(3)); - registry.fill(HIST("QA/Event/hVtxCovYZKF"), kfpv.GetCovariance(4)); - registry.fill(HIST("QA/Event/hVtxX"), collision.posX()); - registry.fill(HIST("QA/Event/hVtxY"), collision.posY()); - registry.fill(HIST("QA/Event/hVtxZ"), collision.posZ()); - registry.fill(HIST("QA/Event/hVtxCovXX"), collision.covXX()); - registry.fill(HIST("QA/Event/hVtxCovYY"), collision.covYY()); - registry.fill(HIST("QA/Event/hVtxCovZZ"), collision.covZZ()); - registry.fill(HIST("QA/Event/hVtxCovXY"), collision.covXY()); - registry.fill(HIST("QA/Event/hVtxCovXZ"), collision.covXZ()); - registry.fill(HIST("QA/Event/hVtxCovYZ"), collision.covYZ()); - } - - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxAll); - - auto trackParCovPos = getTrackParCov(trackPos); - auto trackParCovNeg = getTrackParCov(trackNeg); - auto trackParCovBach = getTrackParCov(trackBach); - LOG(debug) << "Got all daughter tracks."; - - bool isMatter = trackBach.sign() > 0 ? true : false; - - // ---------- fill track QA histograms ---------- - if (kfparticleConfigurations.doTrackQA) { - registry.fill(HIST("QA/Tracks/hTrackPosTPCNcls"), trackPos.tpcNClsFound()); - registry.fill(HIST("QA/Tracks/hTrackNegTPCNcls"), trackNeg.tpcNClsFound()); - registry.fill(HIST("QA/Tracks/hTrackBachTPCNcls"), trackBach.tpcNClsFound()); - registry.fill(HIST("QA/Tracks/hTrackPosHasTPC"), trackPos.hasTPC()); - registry.fill(HIST("QA/Tracks/hTrackNegHasTPC"), trackNeg.hasTPC()); - registry.fill(HIST("QA/Tracks/hTrackBachHasTPC"), trackBach.hasTPC()); - registry.fill(HIST("QA/Tracks/hTrackBachITSClusSizes"), trackBach.itsClusterSizes()); - if (isMatter) { - registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPr()); - registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPi()); - registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackPos.pt()); - registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackNeg.pt()); - } else { - registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPr()); - registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPi()); - registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackNeg.pt()); - registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackPos.pt()); - } - registry.fill(HIST("QA/Tracks/hTrackBachTPCPID"), trackBach.sign() * trackBach.tpcInnerParam(), trackBach.tpcNSigmaDe()); - registry.fill(HIST("QA/Tracks/hTrackBachPt"), trackBach.pt()); - } - - // -------- STEP 1: track selection -------- - // collision ID --> not correct? tracks can have different collisions, but belong to one 3prong vertex! - // if (trackPos.collisionId() != trackNeg.collisionId() || trackPos.collisionId() != trackBach.collisionId() || trackNeg.collisionId() != trackBach.collisionId()) { - // continue; - // } - // track IDs --> already checked in SVertexer! - - // track signs (pos, neg, bach) --> sanity check, should already be in SVertexer - if (trackPos.sign() != +1 || trackNeg.sign() != -1) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCharge); - - // track eta - if (std::abs(trackPos.eta()) > kfparticleConfigurations.maxEta || std::abs(trackNeg.eta()) > kfparticleConfigurations.maxEta || std::abs(trackBach.eta()) > kfparticleConfigurations.maxEtaDeuteron) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxEta); - - // number of TPC clusters - if (trackBach.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsBach) { - return; - } - if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { - return; - } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCNcls); - - // number of TPC crossed rows - if (trackBach.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows) { - return; - } - if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { - return; - } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCRows); - - // TPC PID - float tpcNsigmaProton; - float tpcNsigmaPion; - float dEdxProton; - float dEdxPion; - float tpcNsigmaDeuteron = trackBach.tpcNSigmaDe(); - float tpcNsigmaPionBach = trackBach.tpcNSigmaPi(); - float dEdxDeuteron = trackBach.tpcSignal(); - if (isMatter) { // hypertriton (proton, pi-, deuteron) - tpcNsigmaProton = trackPos.tpcNSigmaPr(); - tpcNsigmaPion = trackNeg.tpcNSigmaPi(); - dEdxProton = trackPos.tpcSignal(); - dEdxPion = trackNeg.tpcSignal(); - if (!selectTPCPID(trackPos, trackNeg, trackBach)) { - return; - } - } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) - tpcNsigmaProton = trackNeg.tpcNSigmaPr(); - tpcNsigmaPion = trackPos.tpcNSigmaPi(); - dEdxProton = trackNeg.tpcSignal(); - dEdxPion = trackPos.tpcSignal(); - if (!selectTPCPID(trackNeg, trackPos, trackBach)) { - return; - } - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCPID); - LOG(debug) << "Basic track selections done."; - - // Average ITS cluster size of deuteron track - double averageClusterSizeDeuteron(0); - int nCls(0); - for (int i = 0; i < 7; i++) { - int clusterSize = trackBach.itsClsSizeInLayer(i); - averageClusterSizeDeuteron += static_cast(clusterSize); - if (clusterSize > 0) - nCls++; - } - averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nCls); - - // track DCAxy and DCAz to PV associated with decay3body - o2::dataformats::VertexBase mPV; - o2::dataformats::DCA mDcaInfoCovPos; - o2::dataformats::DCA mDcaInfoCovNeg; - o2::dataformats::DCA mDcaInfoCovBach; - auto trackParCovPVPos = trackParCovPos; - auto trackParCovPVNeg = trackParCovNeg; - auto trackParCovPVBach = trackParCovBach; - mPV.setPos({collision.posX(), collision.posY(), collision.posZ()}); - mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVPos, 2.f, matCorr, &mDcaInfoCovPos); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVNeg, 2.f, matCorr, &mDcaInfoCovNeg); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVBach, 2.f, matCorr, &mDcaInfoCovBach); - auto TrackPosDcaXY = mDcaInfoCovPos.getY(); - auto TrackNegDcaXY = mDcaInfoCovNeg.getY(); - auto TrackBachDcaXY = mDcaInfoCovBach.getY(); - auto TrackPosDcaZ = mDcaInfoCovPos.getZ(); - auto TrackNegDcaZ = mDcaInfoCovNeg.getZ(); - auto TrackBachDcaZ = mDcaInfoCovBach.getZ(); - // calculate 3D track DCA - auto TrackPosDca = std::sqrt(TrackPosDcaXY * TrackPosDcaXY + TrackPosDcaZ * TrackPosDcaZ); - auto TrackNegDca = std::sqrt(TrackNegDcaXY * TrackNegDcaXY + TrackNegDcaZ * TrackNegDcaZ); - auto TrackBachDca = std::sqrt(TrackBachDcaXY * TrackBachDcaXY + TrackBachDcaZ * TrackBachDcaZ); - // selection - if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { - return; - } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAxyPV); - if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { - return; - } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAzPV); - - // daughter track momentum at inner wall of TPC - float tpcInnerParamProton; - float tpcInnerParamPion; - float tpcInnerParamDeuteron = trackBach.tpcInnerParam(); - if (isMatter) { // hypertriton (proton, pi-, deuteron) - tpcInnerParamProton = trackPos.tpcInnerParam(); - tpcInnerParamPion = trackNeg.tpcInnerParam(); - } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) - tpcInnerParamProton = trackNeg.tpcInnerParam(); - tpcInnerParamPion = trackPos.tpcInnerParam(); - } - - // -------- STEP 2: fit vertex with proton and pion -------- - // Fit vertex with DCA fitter to find minimization point --> uses material corrections implicitly - if (kfparticleConfigurations.doDCAFitterPreMinimum) { - try { - fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); - } catch (std::runtime_error& e) { - LOG(error) << "Exception caught in DCA fitter process call: Not able to fit decay3body vertex!"; - return; - } - // re-acquire tracks at vertex position from DCA fitter - trackParCovPos = fitter3body.getTrack(0); - trackParCovNeg = fitter3body.getTrack(1); - trackParCovBach = fitter3body.getTrack(2); - - LOG(debug) << "Minimum found with DCA fitter for decay3body."; - } - - // create KFParticle objects from tracks - KFParticle kfpProton, kfpPion; - if (isMatter) { - kfpProton = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassProton); - kfpPion = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassPionCharged); - } else if (!isMatter) { - kfpProton = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassProton); - kfpPion = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassPionCharged); - } - LOG(debug) << "KFParticle objects created from daughter tracks."; - - // Construct V0 as intermediate step - KFParticle KFV0; - int nDaughtersV0 = 2; - const KFParticle* DaughtersV0[2] = {&kfpProton, &kfpPion}; - KFV0.SetConstructMethod(2); - try { - KFV0.Construct(DaughtersV0, nDaughtersV0); - } catch (std::runtime_error& e) { - LOG(debug) << "Failed to create V0 vertex from daughter tracks." << e.what(); - return; - } - KFV0.TransportToDecayVertex(); - LOG(debug) << "V0 constructed."; - - // check V0 mass and set mass constraint - float massV0, sigmaMassV0; - KFV0.GetMass(massV0, sigmaMassV0); - KFParticle KFV0Mass = KFV0; - KFV0Mass.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); - float chi2massV0 = KFV0Mass.GetChi2() / KFV0Mass.GetNDF(); - if (kfparticleConfigurations.useLambdaMassConstraint) { - LOG(debug) << "V0 mass constraint applied."; - KFV0 = KFV0Mass; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxV0MassConst); - - // apply virtual V0 cuts used in SVertexer in case of 3body mixing with proton track - if (kfparticleConfigurations.mixingType == 1 && kfparticleConfigurations.applySVertexerV0Cuts) { - // V0 radius - if (std::sqrt(KFV0.GetX() * KFV0.GetX() + KFV0.GetY() * KFV0.GetY()) <= 0.5) { - return; - } - // pT - if (KFV0.GetPt() <= 0.01) { - return; - } - // pz/pT - if (KFV0.GetPz() / KFV0.GetPt() >= 2) { - return; - } - // cos(PA) - if (cpaXYFromKF(KFV0, kfpv) <= 0.9 || cpaFromKF(KFV0, kfpv) <= 0.8) { - return; - } - } - - // -------- STEP 3: fit three body vertex -------- - // Create KFParticle object from deuteron track - KFParticle kfpDeuteron; - kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, trackBach.sign() * bachelorcharge, constants::physics::MassDeuteron); - LOG(debug) << "KFParticle created from deuteron track."; - - // Construct vertex - KFParticle KFHt; - fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt); - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxhasSV); - - // -------- STEP 4: daughter selections after geometrical vertex fit -------- - // daughter DCAs with KF - if ((kfpProton.GetDistanceFromParticle(kfpPion) >= kfparticleConfigurations.maxDcaProPi) || (kfpProton.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaProDeu) || (kfpPion.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaPiDe)) { - return; - } - float DCAvtxDaughters3D = kfpProton.GetDistanceFromParticle(kfpPion) + kfpProton.GetDistanceFromParticle(kfpDeuteron) + kfpPion.GetDistanceFromParticle(kfpDeuteron); - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDau); - LOG(debug) << "DCA selection after vertex fit applied."; - - // daughter DCAs to vertex - if (kfpProton.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpPion.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpDeuteron.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDauVtx); - LOG(debug) << "DCA to vertex selection after vertex fit applied."; - - // daughter pT - if (kfpProton.GetPt() < kfparticleConfigurations.minPtProton || kfpProton.GetPt() > kfparticleConfigurations.maxPtProton || kfpPion.GetPt() < kfparticleConfigurations.minPtPion || kfpPion.GetPt() > kfparticleConfigurations.maxPtPion || kfpDeuteron.GetPt() < kfparticleConfigurations.minPtDeuteron || kfpDeuteron.GetPt() > kfparticleConfigurations.maxPtDeuteron) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDauPt); - LOG(debug) << "Daughter pT selection applied."; - - // -------- STEP 5: candidate selection and constraint after geometrical vertex fit -------- - // Rapidity - float rapHt = RecoDecay::y(std::array{KFHt.GetPx(), KFHt.GetPy(), KFHt.GetPz()}, o2::constants::physics::MassHyperTriton); - if (std::abs(rapHt) > kfparticleConfigurations.maxRapidityHt) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxRap); - - // Pt selection - if (KFHt.GetPt() <= kfparticleConfigurations.minPtHt || KFHt.GetPt() >= kfparticleConfigurations.maxPtHt) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxPt); - - // Mass window - float massHt, sigmaMassHt; - KFHt.GetMass(massHt, sigmaMassHt); - if (massHt <= kfparticleConfigurations.minMassHt || massHt >= kfparticleConfigurations.maxMassHt) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxMass); - - // cos(PA) to PV - if (std::abs(cpaFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPA) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPA); - - // cos(PA) xy to PV - if (std::abs(cpaXYFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPAxy) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPAXY); - - // chi2 geometrical - float chi2geoNDF = KFHt.GetChi2() / KFHt.GetNDF(); - if (kfparticleConfigurations.applyTopoSel && chi2geoNDF >= kfparticleConfigurations.maxChi2geo) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2geo); - LOG(debug) << "Basic selections after vertex fit done."; - - // ctau before topo constraint - if (KFHt.GetLifeTime() > kfparticleConfigurations.maxctauHt) { - return; - } - - // Set vertex constraint and topological selection - KFParticle KFHtPV = KFHt; - try { - KFHtPV.SetProductionVertex(kfpv); - } catch (std::runtime_error& e) { - LOG(error) << "Exception caught KFParticle process call: Topological constraint failed"; - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTopoConstr); // to check if topo constraint fails - // get topological chi2 - float chi2topoNDF = KFHtPV.GetChi2() / KFHtPV.GetNDF(); - KFHtPV.TransportToDecayVertex(); - if (kfparticleConfigurations.applyTopoSel && chi2topoNDF >= kfparticleConfigurations.maxChi2topo) { - return; - } - registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2topo); - - // -------- STEP 6: collect and fill candidate info -------- - // get cluster size of strangeness tracked 3bodies - float trackedClSize; - if (decay3bodyID == -1) { - trackedClSize = 0; - } else { - trackedClSize = !fTrackedClSizeVector.empty() ? fTrackedClSizeVector[decay3bodyID] : 0; - } - - - - //------------------------------------------------------------------ - // table filling - fillCandidateTable(candidate); - LOG(debug) << "Table filled."; - - // fill event counter hist (has selected candidate) --> only filled once per vertex - registry.fill(HIST("Counters/hEventCounterKFParticle"), 3.5); - } // end buildVtx3BodyDataTableKFParticle - - //------------------------------------------------------------------ - void processRun3(ColwithEvTimes const& collisions, aod::Decay3Bodys const& decay3bodys, TrackExtPIDIUwithEvTimes const&, aod::BCsWithTimestamps const&) - { - VtxCandidates.clear(); - - registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); - - for (const auto& d3body : decay3bodys) { - auto t0 = d3body.track0_as(); - auto t1 = d3body.track1_as(); - auto t2 = d3body.track2_as(); - auto collision = d3body.collision_as(); - auto bc = collision.bc_as(); - initCCDB(bc); - - // Recalculate the TOF PID - double tofNSigmaBach = -999; - if (t2.has_collision() && t2.hasTOF()) { - auto originalcol = t2.template collision_as(); - tofNSigmaBach = bachelorTOFPID.GetTOFNSigma(t2, originalcol, collision); - } - - fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, tofNSigmaBach); - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3, "Produce DCA fitter decay3body tables", true); - - //------------------------------------------------------------------ - void processRun3Reduced(aod::RedCollisions const& collisions, aod::RedDecay3Bodys const& decay3bodys, aod::RedIUTracks const&) - { - VtxCandidates.clear(); - - registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); - - for (const auto& d3body : decay3bodys) { - auto t0 = d3body.track0_as(); - auto t1 = d3body.track1_as(); - auto t2 = d3body.track2_as(); - auto collision = d3body.collision_as(); - - initCCDBfromRunNumber(collision.runNumber()); - fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, t2.tofNSigmaDe()); - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced, "Produce DCA fitter decay3body tables with reduced data", false); - - - void processRun3Reduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) - { - VtxCandidates.clear(); - - auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); - auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); - - for (const auto& decay3body : decay3bodys) { - int bin_Radius = xAxis->FindBin(decay3body.svRadius()); - int bin_Phi = yAxis->FindBin(decay3body.momPhi()); - registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); - registry.fill(HIST("hDecay3BodyPosZ"), decay3body.svPosZ()); - } - - Binning3BodyDCAFitter binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhiDegree}, true}; - doMixed3Body(decay3bodys, binningOnRadiusPhi); - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixing, "Produce mixing background directly from mixed decay3bodys based on DCAFitter Info", false); - - void processRun3Reduced3bodyMixingKFInfo(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) - { - VtxCandidates.clear(); - - auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); - auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); - - for (const auto& decay3body : decay3bodys) { - int bin_Radius = xAxis->FindBin(decay3body.radius()); - int bin_Phi = yAxis->FindBin(decay3body.phi()); - registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); - registry.fill(HIST("hDecay3BodyPosZ"), decay3body.posz()); - } - - Binning3BodyKFInfo binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}, true}; - doMixed3Body(decay3bodys, binningOnRadiusPhi); - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixingKFInfo, "Produce mixing background directly from mixed decay3bodys based on KF Info", false); - - //------------------------------------------------------------------ - void processRun3withKFParticle(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) - { - for (const auto& collision : collisions) { - - auto bc = collision.bc_as(); - initCCDB(bc); - LOG(debug) << "CCDB initialised."; - - // Zorro event counting - bool isZorroSelected = false; - if (kfparticleConfigurations.cfgSkimmedProcessing) { - isZorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); - if (isZorroSelected) { - registry.fill(HIST("Counters/hEventCounterZorro"), 0.); - } else { - if (kfparticleConfigurations.cfgOnlyKeepInterestedTrigger) { - continue; - } - } - } - - // event selection - registry.fill(HIST("Counters/hEventCounterKFParticle"), 0.5); - if (kfparticleConfigurations.doSel8selection && !collision.sel8()) { - continue; - } - registry.fill(HIST("Counters/hEventCounterKFParticle"), 1.5); - if (kfparticleConfigurations.doPosZselection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { - continue; - } - registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); - registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); - - if (isZorroSelected) { - registry.fill(HIST("Counters/hEventCounterZorro"), 1.); - } - - // slice Decay3Body table by collision - const uint64_t collIdx = collision.globalIndex(); - auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perCollision, collIdx); - for (auto& vtx3body : Decay3BodyTable_thisCollision) { - auto trackPos = vtx3body.template track0_as(); - auto trackNeg = vtx3body.template track1_as(); - auto trackBach = vtx3body.template track2_as(); - buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, getTOFnSigma(collision, trackBach, false /*isEventMixing*/)); - LOG(debug) << "End of processKFParticle."; - } - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticle, "Produce KFParticle decay3body tables", false); - - void processRun3withKFParticleStrangenessTracking(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const& tracks, aod::Decay3Bodys const& decay3bodys, aod::Tracked3Bodys const& tracked3bodys, aod::BCsWithTimestamps const& bcs) - { - fTrackedClSizeVector.clear(); - fTrackedClSizeVector.resize(decay3bodys.size(), 0); - for (const auto& tvtx3body : tracked3bodys) { - fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); - } - processRun3withKFParticle(collisions, tracks, decay3bodys, bcs); - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleStrangenessTracking, "Produce KFParticle strangeness tracked decay3body tables", false); - - void processRun3withKFParticleReduced(aod::RedCollisions const& collisions, aod::RedIUTracks const&, aod::RedDecay3Bodys const& decay3bodys) - { - int lastRunNumber = -1; - - for (const auto& collision : collisions) { - // set magnetic field only when run number changes - if (collision.runNumber() != lastRunNumber) { - initCCDBfromRunNumber(collision.runNumber()); - lastRunNumber = collision.runNumber(); // Update the last run number - LOG(debug) << "CCDB initialized for run " << lastRunNumber; - } - - // event selection - registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); - registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); - - // slice Decay3Body table by collision - const uint64_t collIdx = collision.globalIndex(); - auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perReducedCollision, collIdx); - for (auto& vtx3body : Decay3BodyTable_thisCollision) { - auto trackPos = vtx3body.template track0_as(); - auto trackNeg = vtx3body.template track1_as(); - auto trackBach = vtx3body.template track2_as(); - buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, trackBach.tofNSigmaDe()); - } - LOG(debug) << "End of processKFParticleDerived."; - } - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced, "Produce KFParticle decay3body tables from derived decay3body data", false); - - void processRun3withKFParticleReduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) - { - // Define a 2D array to count 3bodies per bin (radius, phi, posZ) - std::vector> bin3bodyCounts(16, std::vector(36, 0)); - - // Function to find bin index (returns -1 if out of range) - auto findBin = [](float value, const std::vector& binEdges) -> int { - for (size_t i = 0; i < binEdges.size() - 1; ++i) { - if (value > binEdges[i] && value <= binEdges[i + 1]) { - return i; - } - } - return -1; // Out of range - }; - - int counter = 0; - // Loop over all collisions to count them in bins - for (auto& decay3body : decay3bodys) { - counter++; - float radius = decay3body.radius(); - float phi = decay3body.phi(); - float posZ = decay3body.posz(); - - registry.fill(HIST("QA/EM/hRadius"), radius); - registry.fill(HIST("QA/EM/hPhi"), phi); - registry.fill(HIST("QA/EM/hPosZ"), posZ); - - // float degToRad = TMath::Pi()/180; - - // Determine bin indices - int radiusBin = findBin(radius, {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}); - int phiBin = findBin(phi, {-180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}); - if (radiusBin >= 0 && phiBin >= 0) { // && posZBin >= 0) { - bin3bodyCounts[radiusBin][phiBin]++; //[posZBin]++; - } - } - LOG(info) << "3body counter: " << counter; - - // Print out the number of 3-body decays per bin - LOG(info) << "3body count per bin (radius, phi, posZ):"; - for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { - for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { - LOG(info) << "Bin (" << i << ", " << j << "): " << bin3bodyCounts[i][j] << " 3bodies"; - } - } - // Fill 3D histogram with numbers per bin - for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { - for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { - registry.fill(HIST("QA/EM/h3bodyBinCounts"), i, j, bin3bodyCounts[i][j]); - } - } - LOG(info) << "Integral of h3bodyBinCounts: " << registry.get(HIST("QA/EM/h3bodyBinCounts"))->Integral(); - - Binning3Body binningOnRadPhi{{kfparticleConfigurations.bins3BodyRadius, kfparticleConfigurations.bins3BodyPhi}, true}; - - // Strictly upper index policy for decay3body objects binned by radius, phi and z position - for (auto& [decay3body1, decay3body2] : selfPairCombinations(binningOnRadPhi, kfparticleConfigurations.nEvtMixing, -1, decay3bodys)) { - auto trackPos1 = decay3body1.template track0_as(); - auto trackNeg1 = decay3body1.template track1_as(); - auto trackBach1 = decay3body1.template track2_as(); - auto trackPos2 = decay3body2.template track0_as(); - auto trackNeg2 = decay3body2.template track1_as(); - auto trackBach2 = decay3body2.template track2_as(); - - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 0.5); - - // collision vertex selections - auto collision1 = decay3body1.template collision_as(); - auto collision2 = decay3body2.template collision_as(); - initCCDBfromRunNumber(collision2.runNumber()); - initCCDBfromRunNumber(collision1.runNumber()); - - if (decay3body1.collisionId() == decay3body2.collisionId()) { // only combine if from different event - continue; - } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 1.5); - if (kfparticleConfigurations.selectVtxZ3bodyMixing && std::abs(collision1.posZ() - collision2.posZ()) > kfparticleConfigurations.VtxZBin3bodyMixing) { // only combine if collision similar in VtxZ - continue; - } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 2.5); - - // ---------- selections ---------- - if ((trackBach1.sign() > 0 && !(trackBach2.sign() > 0)) || (trackBach1.sign() < 0 && !(trackBach2.sign() < 0)) || trackBach1.globalIndex() == trackBach2.globalIndex()) { // only combine if trackBach2 has correct sign and is not same as trackBach1 - continue; - } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); - - // ---------- do candidate analysis ---------- - bool isMatter1 = false; - if (trackBach1.sign() > 0) { - isMatter1 = true; - } - if (kfparticleConfigurations.mixingType == 0) { // mix deuteron - buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); - buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); - } else if (kfparticleConfigurations.mixingType == 1) { // mix proton - if (isMatter1 == true) { - buildVtx3BodyDataTableKFParticle(collision1, trackPos2, trackNeg1, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); - buildVtx3BodyDataTableKFParticle(collision2, trackPos1, trackNeg2, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); - } else if (isMatter1 == false) { - buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); - buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); - } - } - } // end decay3body combinations loop - } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced3bodyMixing, "Produce KFParticle mixed decay3body tables from derived decay3body data", false); -}; - - - - - -// build link from decay3body -> vtx3body -struct decay3bodyDataLinkBuilder { - Produces VtxDataLink; - - void init(InitContext const&) {} - - template - void buildDecay3BodyLabel(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) - { - std::vector lIndices; - lIndices.reserve(decay3bodytable.size()); - for (int ii = 0; ii < decay3bodytable.size(); ii++) - lIndices[ii] = -1; - for (const auto& vtxdata : vtxdatatable) { - if (vtxdata.decay3bodyId() != -1) { - lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); - } - } - for (int ii = 0; ii < decay3bodytable.size(); ii++) { - VtxDataLink(lIndices[ii]); - } - } - - void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) - { - buildDecay3BodyLabel(decay3bodytable, vtxdatatable); - } - PROCESS_SWITCH(decay3bodyDataLinkBuilder, processStandard, "Produce label from decay3body to vtx3body", true); - - void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) - { - buildDecay3BodyLabel(decay3bodytable, vtxdatatable); - } - PROCESS_SWITCH(decay3bodyDataLinkBuilder, processReduced, "Produce label from reducedDecay3body to vtx3body", false); -}; - -struct kfdecay3bodyDataLinkBuilder { - Produces kfvtxdataLink; - - void init(InitContext const&) {} - - template - void buildDataLink(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) - { - std::vector lIndices; - lIndices.reserve(decay3bodytable.size()); - for (int ii = 0; ii < decay3bodytable.size(); ii++) - lIndices[ii] = -1; - for (auto& vtxdata : vtxdatatable) { - if (vtxdata.decay3bodyId() != -1) { - lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); - } - } - for (int ii = 0; ii < decay3bodytable.size(); ii++) { - kfvtxdataLink(lIndices[ii]); - } - } - - void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) - { - buildDataLink(decay3bodytable, vtxdatatable); // build Decay3Body -> KFDecay3BodyData link table - } - PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processStandard, "Build data link table.", true); - - void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) - { - buildDataLink(decay3bodytable, vtxdatatable); // build ReducedDecay3Body -> KFDecay3BodyData link table - } - PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processReduced, "Build data link table for reduced data.", false); -}; - -struct decay3bodyLabelBuilder { - - Produces vtxlabels; - Produces vtxfulllabels; - - HistogramRegistry registry{"registry", {}}; - - void init(InitContext const&) - { - if (doprocessDoNotBuildLabels == false) { - auto hLabelCounter = registry.add("hLabelCounter", "hLabelCounter", HistType::kTH1D, {{3, 0.0f, 3.0f}}); - hLabelCounter->GetXaxis()->SetBinLabel(1, "Total"); - hLabelCounter->GetXaxis()->SetBinLabel(2, "Have Same MotherTrack"); - hLabelCounter->GetXaxis()->SetBinLabel(3, "True H3L"); - - registry.add("hHypertritonMCPt", "hHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); - registry.add("hAntiHypertritonMCPt", "hAntiHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); - registry.add("hHypertritonMCMass", "hHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); - registry.add("hAntiHypertritonMCMass", "hAntiHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); - registry.add("hHypertritonMCLifetime", "hHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); - registry.add("hAntiHypertritonMCLifetime", "hAntiHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); - } - } - - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - - void processDoNotBuildLabels(aod::Decay3BodyDataLink const&) // is it possible to have none parameter? - { - // dummy process function - should not be required in the future - }; - PROCESS_SWITCH(decay3bodyLabelBuilder, processDoNotBuildLabels, "Do not produce MC label tables", true); - - void processBuildLabels(aod::Decay3BodysLinked const& decay3bodys, aod::Vtx3BodyDatas const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const&) - { - std::vector lIndices; - lIndices.reserve(vtx3bodydatas.size()); - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - lIndices[ii] = -1; - } - - for (const auto& decay3body : decay3bodys) { - - int lLabel = -1; - int lPDG = -1; - float lPt = -1; - double MClifetime = -1; - bool is3bodyDecay = false; - int lGlobalIndex = -1; - - auto lTrack0 = decay3body.track0_as(); - auto lTrack1 = decay3body.track1_as(); - auto lTrack2 = decay3body.track2_as(); - registry.fill(HIST("hLabelCounter"), 0.5); - - // Association check - // There might be smarter ways of doing this in the future - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - vtxfulllabels(-1); - continue; - } - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - vtxfulllabels(-1); - continue; - } - - for (const auto& lMother0 : lMCTrack0.mothers_as()) { - for (const auto& lMother1 : lMCTrack1.mothers_as()) { - for (const auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lGlobalIndex = lMother1.globalIndex(); - lPt = lMother1.pt(); - lPDG = lMother1.pdgCode(); - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); // only for hypertriton - is3bodyDecay = true; // vtxs with the same mother - } - } - } - } // end association check - if (!is3bodyDecay) { - vtxfulllabels(-1); - continue; - } - registry.fill(HIST("hLabelCounter"), 1.5); - - // Intended for hypertriton cross-checks only - if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { - lLabel = lGlobalIndex; - double hypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hHypertritonMCPt"), lPt); - registry.fill(HIST("hHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); - } - if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { - lLabel = lGlobalIndex; - double antiHypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hAntiHypertritonMCPt"), lPt); - registry.fill(HIST("hAntiHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); - } - - // Construct label table, only vtx which corresponds to true mother and true daughters with a specified order is labeled - // for matter: track0->p, track1->pi, track2->bachelor - // for antimatter: track0->pi, track1->p, track2->bachelor - vtxfulllabels(lLabel); - if (decay3body.vtx3BodyDataId() != -1) { - lIndices[decay3body.vtx3BodyDataId()] = lLabel; - } - } - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - vtxlabels(lIndices[ii]); - } - } - PROCESS_SWITCH(decay3bodyLabelBuilder, processBuildLabels, "Produce MC label tables", false); -}; - -struct decay3bodyInitializer { - Spawns vtx3bodydatas; - void init(InitContext const&) {} -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx b/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx index f8d3d04856a..0fe65459765 100644 --- a/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx +++ b/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx @@ -35,6 +35,7 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" #include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/RecoDecay.h" #include "TableHelper.h" #include "Tools/KFparticle/KFUtilities.h" @@ -78,7 +79,6 @@ struct reduced3bodyCreator { Produces reducedDecay3Bodys; Produces reduced3BodyInfo; Produces reducedFullTracksPIDIU; - Produces dcaFitterSVInfo; Service ccdb; Zorro zorro; @@ -114,6 +114,9 @@ struct reduced3bodyCreator { float d_bz; o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + // tracked cluster size + std::vector fTrackedClSizeVector; + HistogramRegistry registry{"registry", {}}; void init(InitContext&) @@ -297,7 +300,7 @@ struct reduced3bodyCreator { LOG(debug) << "Hypertriton vertex constructed."; } - void process(ColwithEvTimesMultsCents const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) + void process(ColwithEvTimesMultsCents const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::Tracked3Bodys const& tracked3bodys, aod::BCsWithTimestamps const&) { std::vector triggeredCollisions(collisions.size(), false); @@ -340,7 +343,14 @@ struct reduced3bodyCreator { int lastCollisionID = -1; // collisionId of last analysed decay3body. Table is sorted. - // Creat reduced table + // get tracked cluster size info + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); + } + + // Create reduced table for (const auto& d3body : decay3bodys) { auto collision = d3body.template collision_as(); @@ -398,7 +408,7 @@ struct reduced3bodyCreator { const auto trackStartIndex = reducedFullTracksPIDIU.lastIndex(); reducedDecay3Bodys(collisionIndex, trackStartIndex - 2, trackStartIndex - 1, trackStartIndex); - // -------- save reduced decay3body info table -------- + // -------- get decay3body info with KF -------- // get trackParCov daughters auto trackParCovPos = getTrackParCov(daughter0); auto trackParCovNeg = getTrackParCov(daughter1); @@ -417,19 +427,19 @@ struct reduced3bodyCreator { KFParticle KFHt; fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt); // calculate radius and phi - auto radius = std::sqrt(KFHt.GetX() * KFHt.GetX() + KFHt.GetY() * KFHt.GetY()); - float phi, sigma; - KFHt.GetPhi(phi, sigma); - // fill 3body info table - reduced3BodyInfo(radius, phi, KFHt.GetZ()); + auto radius = std::hypot(KFHt.GetX(), KFHt.GetY()); + auto phi = RecoDecay::phi(KFHt.GetPx(), KFHt.GetPy()); - // -------- save dcaFitter secondary vertex info table -------- + // -------- get decay3body info with DCA fitter -------- auto Track0 = getTrackParCov(daughter0); auto Track1 = getTrackParCov(daughter1); auto Track2 = getTrackParCov(daughter2); int n3bodyVtx = fitter3body.process(Track0, Track1, Track2); + float phiVtx, rVtx, zVtx; if (n3bodyVtx == 0) { // discard this pair - dcaFitterSVInfo(-999, -999, -999); + phiVtx = -999.; + rVtx = -999.; + zVtx = -999.; } else { const auto& vtxXYZ = fitter3body.getPCACandidate(); @@ -441,10 +451,13 @@ struct reduced3bodyCreator { propagatedTrack1.getPxPyPzGlo(p1); propagatedTrack2.getPxPyPzGlo(p2); std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; - float phiVtx = std::atan2(p3B[1], p3B[0]); - float rVtx = std::hypot(vtxXYZ[0], vtxXYZ[1]); - dcaFitterSVInfo(rVtx, phiVtx, vtxXYZ[2]); + phiVtx = std::atan2(p3B[1], p3B[0]); + rVtx = std::hypot(vtxXYZ[0], vtxXYZ[1]); + zVtx = vtxXYZ[2]; } + + // fill 3body info table (KF and DCA fitter info) + reduced3BodyInfo(radius, phi, KFHt.GetZ(), rVtx, phiVtx, zVtx, fTrackedClSizeVector[d3body.globalIndex()]); } // end decay3body loop registry.fill(HIST("hEventCounter"), 3.5, reducedCollisions.lastIndex() + 1); diff --git a/PWGLF/TableProducer/Nuspex/threebodyKFTask.cxx b/PWGLF/TableProducer/Nuspex/threebodyKFTask.cxx deleted file mode 100644 index 1fed55805c2..00000000000 --- a/PWGLF/TableProducer/Nuspex/threebodyKFTask.cxx +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \brief Analysis task for KFVtx3BodyDatas (3body candidates reconstructed with KF) -/// \author Carolina Reetz --> partly copied from threebodyRecoTask.cxx -// ======================== - -#include -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/Vtx3BodyTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/PhysicsConstants.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -using MCLabeledTracksIU = soa::Join; - -struct threebodyKFTask { - - Produces outputMCTable; - std::vector filledMothers; - std::vector isGoodCollision; - - // Configurables - Configurable bachelorPdgCode{"bachelorPdgCode", 1000010020, "pdgCode of bachelor daughter"}; - Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother"}; - - ConfigurableAxis m2PrPiBins{"m2PrPiBins", {60, 1., 3.3}, "Binning for m2(p,pi) axis"}; - ConfigurableAxis m2PiDeBins{"m2PiDeBins", {120, 4.0, 8.0}, "Binning for m2(pi,d) axis"}; - - // collision filter and preslice - Filter collisionFilter = (aod::evsel::sel8 == true && nabs(aod::collision::posZ) < 10.f); - Preslice perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; - - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(InitContext const&) - { - const AxisSpec axisM2PrPi{m2PrPiBins, "#it{m}^{2}(p,#pi^{-}) ((GeV/#it{c}^{2})^{2})"}; - const AxisSpec axisM2PiDe{m2PiDeBins, "#it{m}^{2}(#pi^{+},#bar{d}) ((GeV/#it{c}^{2})^{2})"}; - - registry.add("hCentFT0C", "hCentFT0C", HistType::kTH1F, {{100, 0.0f, 100.0f, "FT0C Centrality"}}); - - // mass spectrum of reco candidates - registry.add("hMassHypertriton", "Mass hypertriton", HistType::kTH1F, {{80, 2.96f, 3.04f, "#it{m}(p,#pi^{-},d) (GeV/#it{c}^{2})"}}); - registry.add("hMassAntiHypertriton", "Mass anti-hypertriton", HistType::kTH1F, {{80, 2.96f, 3.04f, "#it{m}(#bar{p},#pi^{+},#bar{d}) (GeV/#it{c}^{2})"}}); - // Dalitz diagrams of reco candidates - registry.add("hDalitzHypertriton", "Dalitz diagram", HistType::kTH2F, {axisM2PrPi, axisM2PiDe})->GetYaxis()->SetTitle("#it{m}^{2}(#pi^{-},d) ((GeV/#it{c}^{2})^{2})"); - registry.add("hDalitzAntiHypertriton", "Dalitz diagram", HistType::kTH2F, {axisM2PrPi, axisM2PiDe})->GetXaxis()->SetTitle("#it{m}^{2}(#bar{p},#pi^{+}) ((GeV/#it{c}^{2})^{2})"); - - // bachelor histgrams - registry.add("hAverageITSClusterSizeBachelor", "Average ITS cluster size bachelor track", HistType::kTH1F, {{15, 0.5, 15.5, "#langle ITS cluster size #rangle"}}); - registry.add("hdEdxBachelor", "TPC dE/dx bachelor track", HistType::kTH1F, {{200, 0.0f, 200.0f, "Average ITS cluster size"}}); - registry.add("hPIDTrackingBachelor", "Tracking PID bachelor track", HistType::kTH1F, {{20, 0.5, 20.5, "Tracking PID identifier"}}); - - // for gen information of reco candidates - auto LabelHist = registry.add("hLabelCounter", "Reco MC candidate counter", HistType::kTH1F, {{3, 0.0f, 3.0f}}); - LabelHist->GetXaxis()->SetBinLabel(1, "Total"); - LabelHist->GetXaxis()->SetBinLabel(2, "Have Same MotherTrack"); - LabelHist->GetXaxis()->SetBinLabel(3, "True H3L/Anti-H3L"); - registry.add("hTrueHypertritonMCPt", "pT gen. of reco. H3L", HistType::kTH1F, {{100, -10.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}}); - registry.add("hTrueHypertritonMCMass", "mass gen. of reco. H3L", HistType::kTH1F, {{40, 2.96f, 3.04f, "#it{m}(p,#pi^{-},d) (GeV/#it{c}^{2})"}}); - registry.add("hTrueHypMassWithMuReco", "mass gen. of reco. H3L", HistType::kTH1F, {{40, 2.96f, 3.04f, "#it{m}(p,#pi^{-},d) (GeV/#it{c}^{2})"}}); - registry.add("hTrueHypertritonMCCTau", "#it{c}#tau gen. of reco. H3L", HistType::kTH1F, {{50, 0.0f, 50.0f, "#it{c}#tau(cm)"}}); - registry.add("hTrueHypertritonMCMassPrPi", "inv. mass gen. of reco. V0 pair (H3L)", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{m}(p,#pi^{-}) (GeV/#it{c}^{2})"}}); - - // for gen information of non reco candidates - registry.add("hTrueHypertritonMCMassPrPi_nonReco", "inv. mass gen. of non-reco. V0 pair (H3L)", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{m}(p,#pi^{-}) (GeV/#it{c}^{2})"}}); - registry.add("hTrueHypertritonMCPtPion_nonReco", "Pion #it{p}_{T} gen. of non-reco. H3L", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{p}_{T}(#pi) (GeV/#it{c})"}}); - registry.add("hTrueHypertritonMCPtProton_nonReco", "Proton #it{p}_{T} gen. of non-reco. H3L", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{p}_{T}(p) (GeV/#it{c})"}}); - } - - // helper function to check if a mother track is a true H3L/Anti-H3L - template - int checkH3LTruth(MCTrack3B const& mcParticlePr, MCTrack3B const& mcParticlePi, MCTrack3B const& mcParticleDe, bool& isMuonReco) - { - if (abs(mcParticlePr.pdgCode()) != 2212 || abs(mcParticleDe.pdgCode()) != 1000010020) { - return -1; - } - // check proton and deuteron mother - int prDeMomID = -1; - for (const auto& motherPr : mcParticlePr.template mothers_as()) { - for (const auto& motherDe : mcParticleDe.template mothers_as()) { - if (motherPr.globalIndex() == motherDe.globalIndex() && std::abs(motherPr.pdgCode()) == 1010010030) { - prDeMomID = motherPr.globalIndex(); - break; - } - } - } - if (prDeMomID == -1) { - return -1; - } - if (std::abs(mcParticlePi.pdgCode()) != 211 && std::abs(mcParticlePi.pdgCode()) != 13) { - return -1; - } - // check if the pion track is a muon coming from a pi -> mu + vu decay, if yes, take the mother pi - auto mcParticlePiTmp = mcParticlePi; - if (std::abs(mcParticlePiTmp.pdgCode()) == 13) { - for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { - if (std::abs(motherPi.pdgCode()) == 211) { - mcParticlePiTmp = motherPi; - isMuonReco = true; - break; - } - } - } - // now loop over the pion mother - for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { - if (motherPi.globalIndex() == prDeMomID) { - return motherPi.globalIndex(); - } - } - return -1; - } - - template - void fillQAPlots(TCand const& vtx3body) - { - // Mass plot - if (vtx3body.track2sign() > 0) { // hypertriton - registry.fill(HIST("hMassHypertriton"), vtx3body.mass()); - } else if (vtx3body.track2sign() < 0) { // anti-hypertriton - registry.fill(HIST("hMassAntiHypertriton"), vtx3body.mass()); - } - - // Dalitz plot - auto m2prpi = RecoDecay::m2(array{array{vtx3body.pxtrack0(), vtx3body.pytrack0(), vtx3body.pztrack0()}, array{vtx3body.pxtrack1(), vtx3body.pytrack1(), vtx3body.pztrack1()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - auto m2pide = RecoDecay::m2(array{array{vtx3body.pxtrack1(), vtx3body.pytrack1(), vtx3body.pztrack1()}, array{vtx3body.pxtrack2(), vtx3body.pytrack2(), vtx3body.pztrack2()}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - if (std::abs(vtx3body.mass() - o2::constants::physics::MassHyperTriton) <= 0.005) { - if (vtx3body.track2sign() > 0) { // hypertriton - registry.fill(HIST("hDalitzHypertriton"), m2prpi, m2pide); - } else if (vtx3body.track2sign() < 0) { // anti-hypertriton - registry.fill(HIST("hDalitzAntiHypertriton"), m2prpi, m2pide); - } - } - - // ITS cluster sizes - registry.fill(HIST("hAverageITSClusterSizeBachelor"), vtx3body.itsclussizedeuteron()); - registry.fill(HIST("hdEdxBachelor"), vtx3body.tpcdedxdeuteron()); - registry.fill(HIST("hPIDTrackingBachelor"), vtx3body.pidtrackingdeuteron()); - } - - //------------------------------------------------------------------ - // process real data analysis - void processData(soa::Filtered>::iterator const& collision, - aod::KFVtx3BodyDatas const& vtx3bodydatas) - { - registry.fill(HIST("hCentFT0C"), collision.centFT0C()); - - for (auto& vtx3bodydata : vtx3bodydatas) { - // QA histograms - fillQAPlots(vtx3bodydata); - } - } - PROCESS_SWITCH(threebodyKFTask, processData, "Data analysis", true); - - //------------------------------------------------------------------ - // process mc analysis - void processMC(soa::Join const& collisions, - aod::KFVtx3BodyDatas const& vtx3bodydatas, - aod::McParticles const& particlesMC, - MCLabeledTracksIU const&, - aod::McCollisions const& mcCollisions) - { - filledMothers.clear(); - isGoodCollision.resize(mcCollisions.size(), false); - - // loop over collisions - for (const auto& collision : collisions) { - // event selection - if (!collision.sel8() || std::abs(collision.posZ()) > 10.f) { - continue; - } - // reco collision survived event selection filter --> fill value for MC collision if collision is "true" MC collision - if (collision.mcCollisionId() >= 0) { - isGoodCollision[collision.mcCollisionId()] = true; - } - - // fill MC table with reco MC candidate information and gen information if matched to MC particle - auto Decay3BodyTable_thisCollision = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - for (auto& vtx3bodydata : Decay3BodyTable_thisCollision) { - registry.fill(HIST("hLabelCounter"), 0.5); - - // fill QA histograms for all reco candidates - fillQAPlots(vtx3bodydata); - - auto track0 = vtx3bodydata.track0_as(); - auto track1 = vtx3bodydata.track1_as(); - auto track2 = vtx3bodydata.track2_as(); - - if (!track0.has_mcParticle() || !track1.has_mcParticle() || !track2.has_mcParticle()) { - continue; - } - - auto mcTrack0 = track0.mcParticle_as(); - auto mcTrack1 = track1.mcParticle_as(); - auto mcTrack2 = track2.mcParticle_as(); - - float genPosPt = mcTrack0.pt(); - float genPosP = mcTrack0.p(); - int daughter0PDGcode = mcTrack0.pdgCode(); - float genNegPt = mcTrack1.pt(); - float genNegP = mcTrack1.p(); - int daughter1PDGcode = mcTrack1.pdgCode(); - float genBachPt = mcTrack2.pt(); - float genBachP = mcTrack2.p(); - int daughter2PDGcode = mcTrack2.pdgCode(); - bool isBachPrimary = mcTrack2.isPhysicalPrimary(); - - double MClifetime = -1.; - bool isTrueH3L = false; - bool isTrueAntiH3L = false; - float genPhi = -1.; - float genEta = -1.; - float genRap = -1.; - float genP = -1.; - float genPt = -1.; - std::array genDecVtx{-1.f}; - bool isMuonReco = false; - auto& mcTrackPr = vtx3bodydata.sign() > 0 ? mcTrack0 : mcTrack1; - auto& mcTrackPi = vtx3bodydata.sign() > 0 ? mcTrack1 : mcTrack0; - auto& mcTrackDe = mcTrack2; - int motherID = checkH3LTruth(mcTrackPr, mcTrackPi, mcTrackDe, isMuonReco); - if (motherID > 0) { - auto mcTrackHyp = particlesMC.rawIteratorAt(motherID); - genPhi = mcTrackHyp.phi(); - genEta = mcTrackHyp.eta(); - genPt = mcTrackHyp.pt(); - int chargeFactor = mcTrackHyp.pdgCode() > 0 ? 1 : -1; - isTrueH3L = chargeFactor > 0; - isTrueAntiH3L = chargeFactor < 0; - MClifetime = RecoDecay::sqrtSumOfSquares(mcTrackPr.vx() - mcTrackHyp.vx(), mcTrackPr.vy() - mcTrackHyp.vy(), mcTrackPr.vz() - mcTrackHyp.vz()) * o2::constants::physics::MassHyperTriton / mcTrackHyp.p(); - double MCMass = RecoDecay::m(array{array{mcTrackPr.px(), mcTrackPr.py(), mcTrackPr.pz()}, array{mcTrackPi.px(), mcTrackPi.py(), mcTrackPi.pz()}, array{mcTrackDe.px(), mcTrackDe.py(), mcTrackDe.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - float MCmassPrPi = RecoDecay::m(array{array{mcTrackPr.px(), mcTrackPr.py(), mcTrackPr.pz()}, array{mcTrackPi.px(), mcTrackPi.py(), mcTrackPi.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hTrueHypertritonMCPt"), mcTrackHyp.pt() * chargeFactor); - registry.fill(HIST("hTrueHypertritonMCCTau"), MClifetime); - registry.fill(HIST("hTrueHypertritonMCMass"), MCMass); - registry.fill(HIST("hTrueHypertritonMCMassPrPi"), MCmassPrPi); - if (isMuonReco) { - registry.fill(HIST("hTrueHypMassWithMuReco"), MCMass); - } - filledMothers.push_back(mcTrackHyp.globalIndex()); - } - outputMCTable( // filled for each reconstructed candidate (in KFVtx3BodyDatas) - vtx3bodydata.mass(), - vtx3bodydata.x(), vtx3bodydata.y(), vtx3bodydata.z(), - vtx3bodydata.xerr(), vtx3bodydata.yerr(), vtx3bodydata.zerr(), - vtx3bodydata.px(), vtx3bodydata.py(), vtx3bodydata.pz(), vtx3bodydata.pt(), - vtx3bodydata.pxerr(), vtx3bodydata.pyerr(), vtx3bodydata.pzerr(), vtx3bodydata.pterr(), - vtx3bodydata.sign(), - vtx3bodydata.dcavtxtopvkf(), vtx3bodydata.dcaxyvtxtopvkf(), - vtx3bodydata.vtxcospakf(), vtx3bodydata.vtxcosxypakf(), - vtx3bodydata.vtxcospakftopo(), vtx3bodydata.vtxcosxypakftopo(), - vtx3bodydata.decaylkf(), vtx3bodydata.decaylxykf(), vtx3bodydata.decayldeltal(), - vtx3bodydata.chi2geondf(), vtx3bodydata.chi2topondf(), - vtx3bodydata.ctaukftopo(), - vtx3bodydata.trackedclsize(), - vtx3bodydata.massv0(), vtx3bodydata.chi2massv0(), - vtx3bodydata.cospav0(), - vtx3bodydata.pxtrack0(), vtx3bodydata.pytrack0(), vtx3bodydata.pztrack0(), // proton - vtx3bodydata.pxtrack1(), vtx3bodydata.pytrack1(), vtx3bodydata.pztrack1(), // pion - vtx3bodydata.pxtrack2(), vtx3bodydata.pytrack2(), vtx3bodydata.pztrack2(), // deuteron - vtx3bodydata.tpcinnerparamtrack0(), vtx3bodydata.tpcinnerparamtrack1(), vtx3bodydata.tpcinnerparamtrack2(), // proton, pion, deuteron - vtx3bodydata.tpcncltrack0(), vtx3bodydata.tpcncltrack1(), vtx3bodydata.tpcncltrack1(), // proton, pion, deuteron - vtx3bodydata.tpcchi2ncldeuteron(), - vtx3bodydata.deltaphideuteron(), vtx3bodydata.deltaphiproton(), - vtx3bodydata.dcatrack0topvkf(), vtx3bodydata.dcatrack1topvkf(), vtx3bodydata.dcatrack2topvkf(), // proton, pion, deuteron - vtx3bodydata.dcaxytrack0topvkf(), vtx3bodydata.dcaxytrack1topvkf(), vtx3bodydata.dcaxytrack2topvkf(), // proton, pion, deuteron - vtx3bodydata.dcaxytrack0tosvkf(), vtx3bodydata.dcaxytrack1tosvkf(), vtx3bodydata.dcaxytrack2tosvkf(), // proton, pion, deuteron - vtx3bodydata.dcatrack0totrack1kf(), vtx3bodydata.dcatrack0totrack2kf(), vtx3bodydata.dcatrack1totrack2kf(), - vtx3bodydata.dcavtxdaughterskf(), - vtx3bodydata.dcaxytrackpostopv(), vtx3bodydata.dcaxytracknegtopv(), vtx3bodydata.dcaxytrackbachtopv(), - vtx3bodydata.dcatrackpostopv(), vtx3bodydata.dcatracknegtopv(), vtx3bodydata.dcatrackbachtopv(), - vtx3bodydata.track0sign(), vtx3bodydata.track1sign(), vtx3bodydata.track2sign(), // proton, pion, deuteron - vtx3bodydata.tpcnsigmaproton(), vtx3bodydata.tpcnsigmapion(), vtx3bodydata.tpcnsigmadeuteron(), vtx3bodydata.tpcnsigmapionbach(), - vtx3bodydata.tpcdedxproton(), vtx3bodydata.tpcdedxpion(), vtx3bodydata.tpcdedxdeuteron(), - vtx3bodydata.tofnsigmadeuteron(), - vtx3bodydata.itsclussizedeuteron(), - vtx3bodydata.pidtrackingdeuteron(), - // MC info (-1 if not matched to MC particle) - genP, - genPt, - genDecVtx[0], genDecVtx[1], genDecVtx[2], - MClifetime, - genPhi, - genEta, - genRap, - genPosP, genPosPt, genNegP, genNegPt, genBachP, genBachPt, - isTrueH3L, isTrueAntiH3L, - daughter0PDGcode, daughter1PDGcode, daughter2PDGcode, isBachPrimary, - true, // is reconstructed - true); // reco event passed event selection - } // end vtx3bodydatas loop - } // end collision loop - - // generated MC particle analysis - // fill MC table with gen information for all generated but not reconstructed particles - for (auto& mcparticle : particlesMC) { - - double genMCmassPrPi = -1.; - bool isTrueGenH3L = false; - bool isTrueGenAntiH3L = false; - float genPBach = -1.; - float genPtBach = -1.; - float genPPos = -1.; - float genPtPos = -1.; - float genPNeg = -1.; - float genPtNeg = -1.; - int posDauPdgCode = -1; - int negDauPdgCode = -1; - int bachDauPdgCode = -1; - - // check if mcparticle was reconstructed and already filled in the table - if (std::find(filledMothers.begin(), filledMothers.end(), mcparticle.globalIndex()) != std::end(filledMothers)) { - continue; - } - - // set flag if corresponding reco collision survived event selection - bool survEvSel = isGoodCollision[mcparticle.mcCollisionId()]; - - // check if MC particle is hypertriton with 3-body decay - if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { - continue; - } - bool haveProton = false, havePion = false, haveBachelor = false; - bool haveAntiProton = false, haveAntiPion = false, haveAntiBachelor = false; - for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == 2212) - haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) - havePion = true; - if (mcparticleDaughter.pdgCode() == -211) - haveAntiPion = true; - if (mcparticleDaughter.pdgCode() == bachelorPdgCode) - haveBachelor = true; - if (mcparticleDaughter.pdgCode() == -bachelorPdgCode) - haveAntiBachelor = true; - } - - // check if particle or anti-particle - if (haveProton && haveAntiPion && haveBachelor && mcparticle.pdgCode() > 0) { - isTrueGenH3L = true; - // get proton and pion daughter - std::array protonMom{0.f}; - std::array piMinusMom{0.f}; - for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == 2212) { - protonMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; - genPPos = mcparticleDaughter.p(); - genPtPos = mcparticleDaughter.pt(); - posDauPdgCode = mcparticleDaughter.pdgCode(); - } else if (mcparticleDaughter.pdgCode() == -211) { - piMinusMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; - genPNeg = mcparticleDaughter.p(); - genPtNeg = mcparticleDaughter.pt(); - negDauPdgCode = mcparticleDaughter.pdgCode(); - } - } - genMCmassPrPi = RecoDecay::m(array{protonMom, piMinusMom}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - registry.fill(HIST("hTrueHypertritonMCMassPrPi_nonReco"), genMCmassPrPi); - registry.fill(HIST("hTrueHypertritonMCPtProton_nonReco"), RecoDecay::sqrtSumOfSquares(protonMom[0], protonMom[1])); - registry.fill(HIST("hTrueHypertritonMCPtPion_nonReco"), RecoDecay::sqrtSumOfSquares(piMinusMom[0], piMinusMom[1])); - } else if (haveAntiProton && havePion && haveAntiBachelor && mcparticle.pdgCode() < 0) { - isTrueGenAntiH3L = true; - // get anti-proton and pion daughter - std::array antiProtonMom{0.f}; - std::array piPlusMom{0.f}; - for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == -2212) { - antiProtonMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; - genPNeg = mcparticleDaughter.p(); - genPtNeg = mcparticleDaughter.pt(); - negDauPdgCode = mcparticleDaughter.pdgCode(); - } else if (mcparticleDaughter.pdgCode() == 211) { - piPlusMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; - genPPos = mcparticleDaughter.p(); - genPtPos = mcparticleDaughter.pt(); - posDauPdgCode = mcparticleDaughter.pdgCode(); - } - } - genMCmassPrPi = RecoDecay::m(array{antiProtonMom, piPlusMom}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - registry.fill(HIST("hTrueHypertritonMCMassPrPi_nonReco"), genMCmassPrPi); - registry.fill(HIST("hTrueHypertritonMCPtProton_nonReco"), RecoDecay::sqrtSumOfSquares(antiProtonMom[0], antiProtonMom[1])); - registry.fill(HIST("hTrueHypertritonMCPtPion_nonReco"), RecoDecay::sqrtSumOfSquares(piPlusMom[0], piPlusMom[1])); - } else { - continue; // stop if particle is no true H3L or Anti-H3L - } - - // get gen decay vertex and calculate ctau - std::array genDecayVtx{0.f}; - for (auto& mcDaughter : mcparticle.daughters_as()) { - if (std::abs(mcDaughter.pdgCode()) == bachelorPdgCode) { - genDecayVtx = {mcDaughter.vx(), mcDaughter.vy(), mcDaughter.vz()}; - genPBach = mcDaughter.p(); - genPtBach = mcDaughter.pt(); - bachDauPdgCode = mcDaughter.pdgCode(); - } - } - double genMClifetime = RecoDecay::sqrtSumOfSquares(genDecayVtx[0] - mcparticle.vx(), genDecayVtx[1] - mcparticle.vy(), genDecayVtx[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - outputMCTable( // reco information (-1) - -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, - -1, -1, - -1, -1, - -1, -1, - -1, -1, -1, - -1, -1, - -1, - -1, - -1, -1, - -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, - -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, - -1, - -1, - -1, - // gen information - mcparticle.p(), - mcparticle.pt(), - genDecayVtx[0], genDecayVtx[1], genDecayVtx[2], - genMClifetime, - mcparticle.phi(), - mcparticle.eta(), - mcparticle.y(), - genPPos, genPtPos, genPNeg, genPtNeg, genPBach, genPtBach, - isTrueGenH3L, isTrueGenAntiH3L, - posDauPdgCode, negDauPdgCode, bachDauPdgCode, - false, // isBachPrimary - false, // is reconstructed - survEvSel); - } // end mcparticles loop - } - PROCESS_SWITCH(threebodyKFTask, processMC, "MC analysis", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx b/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx deleted file mode 100644 index 36af287f95e..00000000000 --- a/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx +++ /dev/null @@ -1,909 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \file threebodyRecoTask.cxx -/// \brief Analysis task for 3-body decay process (now mainly for hypertriton) -/// \author Yuanzhe Wang - -#include -#include -#include -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/Vtx3BodyTables.h" -#include "PWGLF/DataModel/Reduced3BodyTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/PhysicsConstants.h" -#include "CCDB/BasicCCDBManager.h" - -#include "EventFiltering/Zorro.h" -#include "EventFiltering/ZorroSummary.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using ReducedCols = soa::Join; -using FullTracksExtIU = soa::Join; -using MCLabeledTracksIU = soa::Join; - -std::vector triggerLabels = { - "fTriggerEventF1Proton", "fTrackedOmega", "fTrackedXi", "fOmegaLargeRadius", - "fDoubleOmega", "fOmegaHighMult", "fSingleXiYN", "fQuadrupleXi", "fDoubleXi", - "fhadronOmega", "fOmegaXi", "fTripleXi", "fOmega", "fGammaVeryLowPtEMCAL", - "fGammaVeryLowPtDCAL", "fGammaHighPtEMCAL", "fGammaLowPtEMCAL", "fGammaVeryHighPtDCAL", - "fGammaVeryHighPtEMCAL", "fGammaLowPtDCAL", "fJetNeutralLowPt", "fJetNeutralHighPt", - "fGammaHighPtDCAL", "fJetFullLowPt", "fJetFullHighPt", "fEMCALReadout", "fPCMandEE", - "fPHOSnbar", "fPCMHighPtPhoton", "fPHOSPhoton", "fLD", "fPPPHI", "fPD", "fLLL", "fPLL", - "fPPL", "fPPP", "fLeadingPtTrack", "fHighFt0cFv0Flat", "fHighFt0cFv0Mult", "fHighFt0Flat", - "fHighFt0Mult", "fHighMultFv0", "fHighTrackMult", "fHfSingleNonPromptCharm3P", - "fHfSingleNonPromptCharm2P", "fHfSingleCharm3P", "fHfPhotonCharm3P", "fHfHighPt2P", - "fHfSigmaC0K0", "fHfDoubleCharm2P", "fHfBeauty3P", "fHfFemto3P", "fHfFemto2P", - "fHfHighPt3P", "fHfSigmaCPPK", "fHfDoubleCharm3P", "fHfDoubleCharmMix", - "fHfPhotonCharm2P", "fHfV0Charm2P", "fHfBeauty4P", "fHfV0Charm3P", "fHfSingleCharm2P", - "fHfCharmBarToXiBach", "fSingleMuHigh", "fSingleMuLow", "fLMeeHMR", "fDiMuon", - "fDiElectron", "fLMeeIMR", "fSingleE", "fTrackHighPt", "fTrackLowPt", "fJetChHighPt", - "fJetChLowPt", "fUDdiffLarge", "fUDdiffSmall", "fITSextremeIonisation", - "fITSmildIonisation", "fH3L3Body", "fHe", "fH2"}; - -struct Candidate3body { - // Index - int mcmotherId; - int track0Id; - int track1Id; - int track2Id; - // Collision - float colCentFT0C; - // sv and candidate - bool isMatter; - float invmass; - float ct; - float cosPA; - float dcadaughters; - float dcacandtopv; - float vtxradius; - // daughter tracks - TLorentzVector lcand; - TLorentzVector lproton; - TLorentzVector lpion; - TLorentzVector lbachelor; - uint8_t dautpcNclusters[3]; // 0 - proton, 1 - pion, 2 - bachelor - uint32_t dauitsclussize[3]; // 0 - proton, 1 - pion, 2 - bachelor - float daudcaxytopv[3]; // 0 - proton, 1 - pion, 2 - bachelor - float daudcatopv[3]; // 0 - proton, 1 - pion, 2 - bachelor - float dautpcNsigma[3]; // 0 - proton, 1 - pion, 2 - bachelor - float dauinnermostR[3]; // 0 - proton, 1 - pion, 2 - bachelor !!! TracksIU required !!! - float bachelortofNsigma; - bool isBachPrimary = false; - // MC infomartion - TLorentzVector lgencand = {0, 0, 0, 0}; - float genct = -1; - float genrapidity = -999; - bool isSignal = false; - bool isReco = false; - int pdgCode = -1; - bool survivedEventSelection = false; -}; - -struct ThreebodyRecoTask { - - Produces outputDataTable; - Produces outputMCTable; - std::vector candidates3body; - std::vector filledMothers; - std::vector isGoodCollision; - - Service ccdb; - Zorro zorro; - OutputObj zorroSummary{"zorroSummary"}; - - //------------------------------------------------------------------ - PresliceUnsorted perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; - - // Configurable for trigger selection - Configurable triggerList{"triggerList", "fTriggerEventF1Proton, fTrackedOmega, fTrackedXi, fOmegaLargeRadius, fDoubleOmega, fOmegaHighMult, fSingleXiYN, fQuadrupleXi, fDoubleXi, fhadronOmega, fOmegaXi, fTripleXi, fOmega, fGammaVeryLowPtEMCAL, fGammaVeryLowPtDCAL, fGammaHighPtEMCAL, fGammaLowPtEMCAL, fGammaVeryHighPtDCAL, fGammaVeryHighPtEMCAL, fGammaLowPtDCAL, fJetNeutralLowPt, fJetNeutralHighPt, fGammaHighPtDCAL, fJetFullLowPt, fJetFullHighPt, fEMCALReadout, fPCMandEE, fPHOSnbar, fPCMHighPtPhoton, fPHOSPhoton, fLD, fPPPHI, fPD, fLLL, fPLL, fPPL, fPPP, fLeadingPtTrack, fHighFt0cFv0Flat, fHighFt0cFv0Mult, fHighFt0Flat, fHighFt0Mult, fHighMultFv0, fHighTrackMult, fHfSingleNonPromptCharm3P, fHfSingleNonPromptCharm2P, fHfSingleCharm3P, fHfPhotonCharm3P, fHfHighPt2P, fHfSigmaC0K0, fHfDoubleCharm2P, fHfBeauty3P, fHfFemto3P, fHfFemto2P, fHfHighPt3P, fHfSigmaCPPK, fHfDoubleCharm3P, fHfDoubleCharmMix, fHfPhotonCharm2P, fHfV0Charm2P, fHfBeauty4P, fHfV0Charm3P, fHfSingleCharm2P, fHfCharmBarToXiBach, fSingleMuHigh, fSingleMuLow, fLMeeHMR, fDiMuon, fDiElectron, fLMeeIMR, fSingleE, fTrackHighPt, fTrackLowPt, fJetChHighPt, fJetChLowPt, fUDdiffLarge, fUDdiffSmall, fITSextremeIonisation, fITSmildIonisation, fH3L3Body, fHe, fH2", "List of triggers used to select events"}; - Configurable cfgOnlyKeepInterestedTrigger{"cfgOnlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; - Configurable bcTolerance{"bcTolerance", 100, "Tolerance for BC in Zorro"}; - // Configuration to enable like-sign analysis - Configurable cfgLikeSignAnalysis{"cfgLikeSignAnalysis", false, "Enable like-sign analysis"}; - // Selection criteria - Configurable vtxcospa{"vtxcospa", 0.99, "Vtx CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable dcavtxdau{"dcavtxdau", 1.0, "DCA Vtx Daughters"}; // loose cut - Configurable dcapiontopv{"dcapiontopv", .05, "DCA Pion To PV"}; - Configurable etacut{"etacut", 0.9, "etacut"}; - Configurable rapiditycut{"rapiditycut", 1, "rapiditycut"}; - Configurable tofPIDNSigmaMin{"tofPIDNSigmaMin", -5, "tofPIDNSigmaMin"}; - Configurable tofPIDNSigmaMax{"tofPIDNSigmaMax", 5, "tofPIDNSigmaMax"}; - Configurable tpcPIDNSigmaCut{"tpcPIDNSigmaCut", 5, "tpcPIDNSigmaCut"}; - Configurable eventSel8Cut{"eventSel8Cut", true, "flag to enable event sel8 selection"}; - Configurable mcEventCut{"mcEventCut", true, "flag to enable mc event selection: kIsTriggerTVX and kNoTimeFrameBorder"}; - Configurable eventPosZCut{"eventPosZCut", true, "flag to enable event posZ selection"}; - Configurable lifetimecut{"lifetimecut", 40., "lifetimecut"}; // ct - Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; - Configurable maxProtonPt{"maxProtonPt", 5, "maxProtonPt"}; - Configurable minPionPt{"minPionPt", 0.1, "minPionPt"}; - Configurable maxPionPt{"maxPionPt", 1.2, "maxPionPt"}; - Configurable minDeuteronPt{"minDeuteronPt", 0.6, "minDeuteronPt"}; - Configurable maxDeuteronPt{"maxDeuteronPt", 10, "maxDeuteronPt"}; - Configurable minDeuteronPUseTOF{"minDeuteronPUseTOF", 1, "minDeuteronPt Enable TOF PID"}; - Configurable h3LMassLowerlimit{"h3LMassLowerlimit", 2.96, "Hypertriton mass lower limit"}; - Configurable h3LMassUpperlimit{"h3LMassUpperlimit", 3.04, "Hypertriton mass upper limit"}; - Configurable mintpcNClsproton{"mintpcNClsproton", 90, "min tpc Nclusters for proton"}; - Configurable mintpcNClspion{"mintpcNClspion", 70, "min tpc Nclusters for pion"}; - Configurable mintpcNClsdeuteron{"mintpcNClsdeuteron", 100, "min tpc Nclusters for deuteron"}; - - Configurable mcsigma{"mcsigma", 0.0015, "sigma of mc invariant mass fit"}; // obtained from MC - Configurable bachelorPdgCode{"bachelorPdgCode", 1000010020, "pdgCode of bachelor daughter"}; - Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother track"}; - - // 3sigma region for Dalitz plot - float lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; - float uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; - - // CCDB options - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable pidPath{"pidPath", "", "Path to the PID response object"}; - - // Zorro counting - Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; - - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - {"hCentFT0C", "hCentFT0C", {HistType::kTH1F, {{100, 0.0f, 100.0f, "FT0C Centrality"}}}}, - {"hCandidatesCounter", "hCandidatesCounter", {HistType::kTH1F, {{12, 0.0f, 12.0f}}}}, - {"hMassHypertriton", "hMassHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f}}}}, - {"hMassAntiHypertriton", "hMassAntiHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f}}}}, - {"hMassHypertritonTotal", "hMassHypertritonTotal", {HistType::kTH1F, {{300, 2.9f, 3.2f}}}}, - {"hTOFPIDDeuteron", "hTOFPIDDeuteron", {HistType::kTH1F, {{2000, -100.0f, 100.0f}}}}, - {"hProtonTPCBB", "hProtonTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hPionTPCBB", "hPionTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDeuteronTPCBB", "hDeuteronTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hProtonTPCVsPt", "hProtonTPCVsPt", {HistType::kTH2F, {{50, 0.0f, 5.0f, "#it{p}_{T} (GeV/c)"}, {240, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hPionTPCVsPt", "hPionTPCVsPt", {HistType::kTH2F, {{20, 0.0f, 2.0f, "#it{p}_{T} (GeV/c)"}, {240, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDeuteronTPCVsPt", "hDeuteronTPCVsPt", {HistType::kTH2F, {{80, 0.0f, 8.0f, "#it{p}_{T} (GeV/c)"}, {240, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDeuteronTOFVsPBeforeTOFCut", "hDeuteronTOFVsPBeforeTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronTOFVsPAtferTOFCut", "hDeuteronTOFVsPAtferTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - - {"hDalitz", "hDalitz", {HistType::kTH2F, {{120, 7.85, 8.45, "M^{2}(dp) (GeV^{2}/c^{4})"}, {60, 1.1, 1.4, "M^{2}(p#pi) (GeV^{2}/c^{4})"}}}}, - }, - }; - - //------------------------------------------------------------------ - // Fill stats histograms - enum Vtxstep { kCandAll = 0, - kCandDauEta, - kCandDauPt, - kCandTPCNcls, - kCandTPCPID, - kCandTOFPID, - kCandDcaToPV, - kCandRapidity, - kCandct, - kCandCosPA, - kCandDcaDau, - kCandInvMass, - kNCandSteps }; - - struct { - std::array candstats; - std::array truecandstats; - } statisticsRegistry; - - void resetHistos() - { - for (int ii = 0; ii < kNCandSteps; ii++) { - statisticsRegistry.candstats[ii] = 0; - statisticsRegistry.truecandstats[ii] = 0; - } - } - void fillCandCounter(int kn, bool istrue = false) - { - statisticsRegistry.candstats[kn]++; - if (istrue) { - statisticsRegistry.truecandstats[kn]++; - } - } - void fillHistos() - { - for (int ii = 0; ii < kNCandSteps; ii++) { - registry.fill(HIST("hCandidatesCounter"), ii, statisticsRegistry.candstats[ii]); - if (doprocessMC == true) { - registry.fill(HIST("hTrueHypertritonCounter"), ii, statisticsRegistry.truecandstats[ii]); - } - } - } - - int mRunNumber; - - void init(InitContext const&) - { - zorroSummary.setObject(zorro.getZorroSummary()); - - mRunNumber = 0; - - ccdb->setURL(ccdbUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(1, "total"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(2, "sel8"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(3, "vertexZ"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(4, "Zorro H3L 3body event"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(5, "has Candidate"); - - // Check for selection criteria !!! TracksIU required !!! - registry.add("hDiffRVtxProton", "hDiffRVtxProton", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of proton - registry.add("hDiffRVtxPion", "hDiffRVtxPion", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of pion - registry.add("hDiffRVtxDeuteron", "hDiffRVtxDeuteron", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of deuteron - registry.add("hDiffDaughterR", "hDiffDaughterR", HistType::kTH1F, {{10000, -100, 100}}); // difference between minR of pion&proton and R of deuteron(bachelor) - - // Check triggers - auto hEventTriggerCount = registry.add("hEventTriggerCount", "hEventTriggerCount", HistType::kTH1F, {{static_cast(triggerLabels.size() + 1), 0, static_cast(triggerLabels.size() + 1)}}); - for (size_t i = 0; i < triggerLabels.size(); i++) { - hEventTriggerCount->GetXaxis()->SetBinLabel(i + 1, triggerLabels[i].c_str()); - } - hEventTriggerCount->GetXaxis()->SetBinLabel(triggerLabels.size() + 1, "NoTrigger"); - - if (cfgLikeSignAnalysis) { - registry.add("hInvMassCorrectSign", "hInvMassCorrectSign", HistType::kTH1F, {{80, 2.96f, 3.04f}}); // check if there are contamination of possible signals which are caused by unexpected PID - } - - if (doprocessMC == true) { - registry.add("hTrueHypertritonCounter", "hTrueHypertritonCounter", HistType::kTH1F, {{12, 0.0f, 12.0f}}); - auto hGeneratedHypertritonCounter = registry.add("hGeneratedHypertritonCounter", "hGeneratedHypertritonCounter", HistType::kTH1F, {{2, 0.0f, 2.0f}}); - hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(1, "Total"); - hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(2, "3-body decay"); - registry.add("hPtGeneratedHypertriton", "hPtGeneratedHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); - registry.add("hctGeneratedHypertriton", "hctGeneratedHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); - registry.add("hEtaGeneratedHypertriton", "hEtaGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - registry.add("hRapidityGeneratedHypertriton", "hRapidityGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - registry.add("hPtGeneratedAntiHypertriton", "hPtGeneratedAntiHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); - registry.add("hctGeneratedAntiHypertriton", "hctGeneratedAntiHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); - registry.add("hEtaGeneratedAntiHypertriton", "hEtaGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - registry.add("hRapidityGeneratedAntiHypertriton", "hRapidityGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - } - - TString candCounterbinLabel[kNCandSteps] = {"Total", "TrackEta", "DauPt", "TPCNcls", "TPCPID", "d TOFPID", "PionDcatoPV", "MomRapidity", "Lifetime", "VtxCosPA", "VtxDcaDau", "InvMass"}; - for (int i{0}; i < kNCandSteps; i++) { - registry.get(HIST("hCandidatesCounter"))->GetXaxis()->SetBinLabel(i + 1, candCounterbinLabel[i]); - if (doprocessMC == true) { - registry.get(HIST("hTrueHypertritonCounter"))->GetXaxis()->SetBinLabel(i + 1, candCounterbinLabel[i]); - } - } - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - - if (cfgSkimmedProcessing) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); - zorro.populateHistRegistry(registry, bc.runNumber()); - } - - LOGF(info, "Initializing CCDB for run %d", bc.runNumber()); - mRunNumber = bc.runNumber(); - } - - //------------------------------------------------------------------ - // Check if the mcparticle is hypertriton which decays into 3 daughters - template - bool is3bodyDecayed(TMCParticle const& particle) - { - if (std::abs(particle.pdgCode()) != motherPdgCode) { - return false; - } - bool haveProton = false, havePion = false, haveBachelor = false; - bool haveAntiProton = false, haveAntiPion = false, haveAntiBachelor = false; - for (const auto& mcparticleDaughter : particle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == PDG_t::kProton) - haveProton = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) - havePion = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kPiMinus) - haveAntiPion = true; - if (mcparticleDaughter.pdgCode() == bachelorPdgCode) - haveBachelor = true; - if (mcparticleDaughter.pdgCode() == -bachelorPdgCode) - haveAntiBachelor = true; - } - if (haveProton && haveAntiPion && haveBachelor && particle.pdgCode() > 0) { - return true; - } else if (haveAntiProton && havePion && haveAntiBachelor && particle.pdgCode() < 0) { - return true; - } - return false; - } - - //------------------------------------------------------------------ - // Event Selection - template - bool eventSelection(TCollision const& collision) - { - auto bc = collision.template bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - if (eventSel8Cut && !collision.sel8()) { - return false; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (eventPosZCut && std::abs(collision.posZ()) > 10.f) { // 10cm - return false; - } - registry.fill(HIST("hEventCounter"), 2.5); - registry.fill(HIST("hCentFT0C"), collision.centFT0C()); - - if (cfgSkimmedProcessing) { - bool zorroSelected = zorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting - if (zorroSelected) { - registry.fill(HIST("hEventCounter"), 3.5); - } else { - if (cfgOnlyKeepInterestedTrigger) { - return false; - } - } - } - - return true; - } - - //------------------------------------------------------------------ - // Fill candidate table - template - void fillCand(TCollisionTable const& collision, TCandTable const& candData, TTrackTable const& trackProton, TTrackTable const& trackPion, TTrackTable const& trackDeuteron, bool isMatter, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, bool isBachPrimary = false) - { - double cospa = candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()); - double ct = candData.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassHyperTriton; - - Candidate3body cand3body; - cand3body.isMatter = isMatter; - if (isMatter == true) { - cand3body.lproton.SetXYZM(candData.pxtrack0(), candData.pytrack0(), candData.pztrack0(), o2::constants::physics::MassProton); - cand3body.lpion.SetXYZM(candData.pxtrack1(), candData.pytrack1(), candData.pztrack1(), o2::constants::physics::MassPionCharged); - } else { - cand3body.lproton.SetXYZM(candData.pxtrack1(), candData.pytrack1(), candData.pztrack1(), o2::constants::physics::MassPionCharged); - cand3body.lpion.SetXYZM(candData.pxtrack0(), candData.pytrack0(), candData.pztrack0(), o2::constants::physics::MassProton); - } - - cand3body.mcmotherId = lLabel; - cand3body.track0Id = candData.track0Id(); - cand3body.track1Id = candData.track1Id(); - cand3body.track2Id = candData.track2Id(); - cand3body.colCentFT0C = collision.centFT0C(); - cand3body.invmass = cand3body.isMatter ? candData.mHypertriton() : candData.mAntiHypertriton(); - cand3body.lcand.SetXYZM(candData.px(), candData.py(), candData.pz(), o2::constants::physics::MassHyperTriton); - cand3body.ct = ct; - cand3body.cosPA = cospa; - cand3body.dcadaughters = candData.dcaVtxdaughters(); - cand3body.dcacandtopv = candData.dcavtxtopv(collision.posX(), collision.posY(), collision.posZ()); - cand3body.vtxradius = candData.vtxradius(); - cand3body.lbachelor.SetXYZM(candData.pxtrack2(), candData.pytrack2(), candData.pztrack2(), o2::constants::physics::MassDeuteron); - cand3body.dautpcNclusters[0] = trackProton.tpcNClsFound(); - cand3body.dautpcNclusters[1] = trackPion.tpcNClsFound(); - cand3body.dautpcNclusters[2] = trackDeuteron.tpcNClsFound(); - cand3body.dauitsclussize[0] = trackProton.itsClusterSizes(); - cand3body.dauitsclussize[1] = trackPion.itsClusterSizes(); - cand3body.dauitsclussize[2] = trackDeuteron.itsClusterSizes(); - cand3body.dautpcNsigma[0] = trackProton.tpcNSigmaPr(); - cand3body.dautpcNsigma[1] = trackPion.tpcNSigmaPi(); - cand3body.dautpcNsigma[2] = trackDeuteron.tpcNSigmaDe(); - cand3body.daudcaxytopv[0] = cand3body.isMatter ? candData.dcaXYtrack0topv() : candData.dcaXYtrack1topv(); - cand3body.daudcaxytopv[1] = cand3body.isMatter ? candData.dcaXYtrack1topv() : candData.dcaXYtrack0topv(); - cand3body.daudcaxytopv[2] = candData.dcaXYtrack2topv(); - cand3body.daudcatopv[0] = cand3body.isMatter ? candData.dcatrack0topv() : candData.dcatrack1topv(); - cand3body.daudcatopv[1] = cand3body.isMatter ? candData.dcatrack1topv() : candData.dcatrack0topv(); - cand3body.daudcatopv[2] = candData.dcatrack2topv(); - cand3body.dauinnermostR[0] = trackProton.x(); - cand3body.dauinnermostR[1] = trackPion.x(); - cand3body.dauinnermostR[2] = trackDeuteron.x(); - - cand3body.bachelortofNsigma = candData.tofNSigmaBachDe(); - cand3body.isBachPrimary = isBachPrimary; - if (isTrueCand) { - cand3body.mcmotherId = lLabel; - cand3body.lgencand = lmother; - cand3body.genct = mcLifetime; - cand3body.genrapidity = lmother.Rapidity(); - cand3body.isSignal = true; - cand3body.isReco = true; - cand3body.pdgCode = cand3body.isMatter ? motherPdgCode : -motherPdgCode; - cand3body.survivedEventSelection = true; - filledMothers.push_back(lLabel); - } - - candidates3body.push_back(cand3body); - - registry.fill(HIST("hProtonTPCBB"), trackProton.sign() * trackProton.p(), trackProton.tpcSignal()); - registry.fill(HIST("hPionTPCBB"), trackPion.sign() * trackPion.p(), trackPion.tpcSignal()); - registry.fill(HIST("hDeuteronTPCBB"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tpcSignal()); - registry.fill(HIST("hProtonTPCVsPt"), trackProton.pt(), trackProton.tpcNSigmaPr()); - registry.fill(HIST("hPionTPCVsPt"), trackProton.pt(), trackPion.tpcNSigmaPi()); - registry.fill(HIST("hDeuteronTPCVsPt"), trackDeuteron.pt(), trackDeuteron.tpcNSigmaDe()); - registry.fill(HIST("hTOFPIDDeuteron"), candData.tofNSigmaBachDe()); - registry.fill(HIST("hDiffRVtxProton"), trackProton.x() - candData.vtxradius()); - registry.fill(HIST("hDiffRVtxPion"), trackPion.x() - candData.vtxradius()); - registry.fill(HIST("hDiffRVtxDeuteron"), trackDeuteron.x() - candData.vtxradius()); - float diffTrackR = trackDeuteron.x() - std::min(trackProton.x(), trackPion.x()); - registry.fill(HIST("hDiffDaughterR"), diffTrackR); - } - - //------------------------------------------------------------------ - // Selections for candidates - template - bool selectCand(TCollisionTable const& collision, TCandTable const& candData, TTrackTable const& trackProton, TTrackTable const& trackPion, TTrackTable const& trackDeuteron, bool isMatter, bool isTrueCand = false) - { - fillCandCounter(kCandAll, isTrueCand); - - // Selection on daughters - if (std::abs(trackProton.eta()) > etacut || std::abs(trackPion.eta()) > etacut || std::abs(trackDeuteron.eta()) > etacut) { - return false; - } - fillCandCounter(kCandDauEta, isTrueCand); - - if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { - return false; - } - fillCandCounter(kCandDauPt, isTrueCand); - - if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { - return false; - } - fillCandCounter(kCandTPCNcls, isTrueCand); - - if (std::abs(trackProton.tpcNSigmaPr()) > tpcPIDNSigmaCut || std::abs(trackPion.tpcNSigmaPi()) > tpcPIDNSigmaCut || std::abs(trackDeuteron.tpcNSigmaDe()) > tpcPIDNSigmaCut) { - return false; - } - fillCandCounter(kCandTPCPID, isTrueCand); - - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - if ((candData.tofNSigmaBachDe() < tofPIDNSigmaMin || candData.tofNSigmaBachDe() > tofPIDNSigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { - return false; - } - fillCandCounter(kCandTOFPID, isTrueCand); - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - - double dcapion = isMatter ? candData.dcatrack1topv() : candData.dcatrack0topv(); - if (std::abs(dcapion) < dcapiontopv) { - return false; - } - fillCandCounter(kCandDcaToPV, isTrueCand); - - // Selection on candidate hypertriton - if (std::abs(candData.yHypertriton()) > rapiditycut) { - return false; - } - fillCandCounter(kCandRapidity, isTrueCand); - - double ct = candData.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassHyperTriton; - if (ct > lifetimecut) { - return false; - } - fillCandCounter(kCandct, isTrueCand); - - double cospa = candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()); - if (cospa < vtxcospa) { - return false; - } - fillCandCounter(kCandCosPA, isTrueCand); - - if (candData.dcaVtxdaughters() > dcavtxdau) { - return false; - } - fillCandCounter(kCandDcaDau, isTrueCand); - - if ((isMatter && candData.mHypertriton() > h3LMassLowerlimit && candData.mHypertriton() < h3LMassUpperlimit)) { - // Hypertriton - registry.fill(HIST("hMassHypertriton"), candData.mHypertriton()); - registry.fill(HIST("hMassHypertritonTotal"), candData.mHypertriton()); - if (candData.mHypertriton() > lowersignallimit && candData.mHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); - } - } else if ((!isMatter && candData.mAntiHypertriton() > h3LMassLowerlimit && candData.mAntiHypertriton() < h3LMassUpperlimit)) { - // AntiHypertriton - registry.fill(HIST("hMassAntiHypertriton"), candData.mAntiHypertriton()); - registry.fill(HIST("hMassHypertritonTotal"), candData.mAntiHypertriton()); - if (candData.mAntiHypertriton() > lowersignallimit && candData.mAntiHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); - } - } else { - return false; - } - fillCandCounter(kCandInvMass, isTrueCand); - - return true; - } - - //------------------------------------------------------------------ - // Analysis process for a single candidate - template - void candidateAnalysis(TCollisionTable const& collision, TCandTable const& candData, bool& ifHasCandidate, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, double isBachPrimary = false) - { - auto track0 = candData.template track0_as(); - auto track1 = candData.template track1_as(); - auto track2 = candData.template track2_as(); - - bool isMatter = track2.sign() > 0; // true if the candidate is hypertriton (p pi- d) - - auto& trackProton = isMatter ? track0 : track1; - auto& trackPion = isMatter ? track1 : track0; - auto& trackDeuteron = track2; - - if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { - ifHasCandidate = true; - fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); - } - } - - //------------------------------------------------------------------ - // Analysis process for like-sign candidates : (p pi- anti-d) or (anti-p pi+ d) - template - void likeSignAnalysis(TCollisionTable const& collision, TCandTable const& candData, bool& ifHasCandidate, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, double isBachPrimary = false) - { - auto track0 = candData.template track0_as(); - auto track1 = candData.template track1_as(); - auto track2 = candData.template track2_as(); - - bool isMatter = track2.sign() < 0; // true if seach for background consists of (p pi- anti-d) - - // Assume proton has an oppisite charge with deuteron - auto& trackProton = isMatter ? track0 : track1; - auto& trackPion = isMatter ? track1 : track0; - auto& trackDeuteron = track2; - - if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { - ifHasCandidate = true; - fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); - // QA for if signals have the possibility to be reconginzed as a like-sign background - if (isMatter) { - registry.fill(HIST("hInvMassCorrectSign"), candData.mHypertriton()); - } else { - registry.fill(HIST("hInvMassCorrectSign"), candData.mAntiHypertriton()); - } - } - } - - //------------------------------------------------------------------ - // Analysis process for reduced data - template - void reducedAnalysis(TCollisionTable const& collision, TCandTable const& candData, TTracks tracks, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, double isBachPrimary = false) - { - auto track0 = tracks.rawIteratorAt(candData.track0Id()); - auto track1 = tracks.rawIteratorAt(candData.track1Id()); - auto track2 = tracks.rawIteratorAt(candData.track2Id()); - - bool isMatter = track2.sign() > 0; // true if the candidate is hypertriton (p pi- d) - - auto& trackProton = isMatter ? track0 : track1; - auto& trackPion = isMatter ? track1 : track0; - auto& trackDeuteron = track2; - - if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { - fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); - } - } - - //------------------------------------------------------------------ - // Analysis process for reduced data with like-sign candidates - template - void reducedLikeSignAnalysis(TCollisionTable const& collision, TCandTable const& candData, TTracks tracks, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, bool isBachPrimary = false) - { - auto track0 = tracks.rawIteratorAt(candData.track0Id()); - auto track1 = tracks.rawIteratorAt(candData.track1Id()); - auto track2 = tracks.rawIteratorAt(candData.track2Id()); - - bool isMatter = track2.sign() < 0; // true if seach for background consists of (p pi- anti-d) - - // Assume proton has an oppisite charge with deuteron - auto& trackProton = isMatter ? track0 : track1; - auto& trackPion = isMatter ? track1 : track0; - auto& trackDeuteron = track2; - - if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { - fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); - // QA for if signals have the possibility to be reconginzed as a like-sign background - if (isMatter) { - registry.fill(HIST("hInvMassCorrectSign"), candData.mHypertriton()); - } else { - registry.fill(HIST("hInvMassCorrectSign"), candData.mAntiHypertriton()); - } - } - } - - //------------------------------------------------------------------ - void fillOutputDataTable(Candidate3body const& cand3body) - { - outputDataTable(cand3body.colCentFT0C, - cand3body.isMatter, cand3body.invmass, cand3body.lcand.P(), cand3body.lcand.Pt(), cand3body.ct, - cand3body.cosPA, cand3body.dcadaughters, cand3body.dcacandtopv, cand3body.vtxradius, - cand3body.lproton.Pt(), cand3body.lproton.Eta(), cand3body.lproton.Phi(), cand3body.dauinnermostR[0], - cand3body.lpion.Pt(), cand3body.lpion.Eta(), cand3body.lpion.Phi(), cand3body.dauinnermostR[1], - cand3body.lbachelor.Pt(), cand3body.lbachelor.Eta(), cand3body.lbachelor.Phi(), cand3body.dauinnermostR[2], - cand3body.dautpcNclusters[0], cand3body.dautpcNclusters[1], cand3body.dautpcNclusters[2], - cand3body.dauitsclussize[0], cand3body.dauitsclussize[1], cand3body.dauitsclussize[2], - cand3body.dautpcNsigma[0], cand3body.dautpcNsigma[1], cand3body.dautpcNsigma[2], cand3body.bachelortofNsigma, - cand3body.daudcaxytopv[0], cand3body.daudcaxytopv[1], cand3body.daudcaxytopv[2], - cand3body.daudcatopv[0], cand3body.daudcatopv[1], cand3body.daudcatopv[2]); - } - - //------------------------------------------------------------------ - // collect information for generated hypertriton (should be called after event selection) - void getGeneratedH3LInfo(aod::McParticles const& particlesMC) - { - for (const auto& mcparticle : particlesMC) { - if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { - continue; - } - registry.fill(HIST("hGeneratedHypertritonCounter"), 0.5); - - bool haveProton = false, havePionPlus = false, haveDeuteron = false; - bool haveAntiProton = false, havePionMinus = false, haveAntiDeuteron = false; - double mcLifetime = -1; - for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == PDG_t::kProton) - haveProton = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) - havePionPlus = true; - if (mcparticleDaughter.pdgCode() == -PDG_t::kPiPlus) - havePionMinus = true; - if (mcparticleDaughter.pdgCode() == bachelorPdgCode) { - haveDeuteron = true; - mcLifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - } - if (mcparticleDaughter.pdgCode() == -bachelorPdgCode) { - haveAntiDeuteron = true; - mcLifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - } - } - if (haveProton && havePionMinus && haveDeuteron && mcparticle.pdgCode() == motherPdgCode) { - registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); - registry.fill(HIST("hPtGeneratedHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedHypertriton"), mcLifetime); - registry.fill(HIST("hEtaGeneratedHypertriton"), mcparticle.eta()); - registry.fill(HIST("hRapidityGeneratedHypertriton"), mcparticle.y()); - } else if (haveAntiProton && havePionPlus && haveAntiDeuteron && mcparticle.pdgCode() == -motherPdgCode) { - registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); - registry.fill(HIST("hPtGeneratedAntiHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedAntiHypertriton"), mcLifetime); - registry.fill(HIST("hEtaGeneratedAntiHypertriton"), mcparticle.eta()); - registry.fill(HIST("hRapidityGeneratedAntiHypertriton"), mcparticle.y()); - } - } - } - - //------------------------------------------------------------------ - // process real data analysis - void processData(soa::Join const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const&, aod::BCsWithTimestamps const&) - { - for (const auto& collision : collisions) { - candidates3body.clear(); - - if (!eventSelection(collision)) { - continue; - } - - bool ifHasCandidate = false; - auto d3BodyCands = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - for (const auto& vtx : d3BodyCands) { - if (cfgLikeSignAnalysis) { - likeSignAnalysis(collision, vtx, ifHasCandidate); - } else { - candidateAnalysis(collision, vtx, ifHasCandidate); - } - } - - if (ifHasCandidate) { - auto bc = collision.bc_as(); - auto triggerSelection = zorro.getTriggerOfInterestResults(bc.globalBC(), bcTolerance); - for (size_t i = 0; i < triggerSelection.size(); i++) { - if (triggerSelection[i]) { - registry.fill(HIST("hEventTriggerCount"), i + 0.5); - } - } - if (zorro.isNotSelectedByAny(bc.globalBC(), bcTolerance)) { - registry.fill(HIST("hEventTriggerCount"), triggerLabels.size() + 0.5); - } - registry.fill(HIST("hEventCounter"), 4.5); - } - fillHistos(); - resetHistos(); - - for (const auto& cand3body : candidates3body) { - fillOutputDataTable(cand3body); - } - } - } - PROCESS_SWITCH(ThreebodyRecoTask, processData, "Real data reconstruction", true); - - //------------------------------------------------------------------ - // process reduced data analysis - void processReducedData(ReducedCols const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, aod::RedIUTracks const& tracks) - { - candidates3body.clear(); - - registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); - - for (const auto& vtx : vtx3bodydatas) { - const auto& collision = collisions.iteratorAt(vtx.collisionId()); - if (cfgLikeSignAnalysis) { - reducedLikeSignAnalysis(collision, vtx, tracks); - } else { - reducedAnalysis(collision, vtx, tracks); - } - for (const auto& cand3body : candidates3body) { - fillOutputDataTable(cand3body); - } - candidates3body.clear(); - } - fillHistos(); - resetHistos(); - } - PROCESS_SWITCH(ThreebodyRecoTask, processReducedData, "Reduced data reconstruction", false); - - //------------------------------------------------------------------ - // process mc analysis - void processMC(soa::Join const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, aod::McParticles const& particlesMC, MCLabeledTracksIU const& /*tracks*/, aod::McCollisions const& mcCollisions) - { - filledMothers.clear(); - getGeneratedH3LInfo(particlesMC); - isGoodCollision.resize(mcCollisions.size(), false); - - for (const auto& collision : collisions) { - candidates3body.clear(); - registry.fill(HIST("hEventCounter"), 0.5); - if (mcEventCut && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (eventPosZCut && std::abs(collision.posZ()) > 10.f) { // 10cm - continue; - } - registry.fill(HIST("hEventCounter"), 2.5); - registry.fill(HIST("hCentFT0C"), collision.centFT0C()); - - if (collision.mcCollisionId() >= 0) { - isGoodCollision[collision.mcCollisionId()] = true; - } - - bool ifHasCandidate = false; - auto vtxsThisCol = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - - for (const auto& vtx : vtxsThisCol) { - bool isBachPrimary = false; - int lLabel = -1; - int lPDG = -1; - double mcLifetime = -1; - TLorentzVector lmother; - bool isTrueCand = false; - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); - if (track0.has_mcParticle() && track1.has_mcParticle() && track2.has_mcParticle()) { - auto lMCTrack0 = track0.mcParticle_as(); - auto lMCTrack1 = track1.mcParticle_as(); - auto lMCTrack2 = track2.mcParticle_as(); - - if (lMCTrack2.isPhysicalPrimary()) { - isBachPrimary = true; - } - - if (lMCTrack0.has_mothers() && lMCTrack1.has_mothers() && lMCTrack2.has_mothers()) { - for (const auto& lMother0 : lMCTrack0.mothers_as()) { - for (const auto& lMother1 : lMCTrack1.mothers_as()) { - for (const auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lLabel = lMother0.globalIndex(); - lPDG = lMother0.pdgCode(); - if ((lPDG == motherPdgCode && lMCTrack0.pdgCode() == PDG_t::kProton && lMCTrack1.pdgCode() == PDG_t::kPiMinus && lMCTrack2.pdgCode() == bachelorPdgCode) || - (lPDG == -motherPdgCode && lMCTrack0.pdgCode() == PDG_t::kPiPlus && lMCTrack1.pdgCode() == PDG_t::kProtonBar && lMCTrack2.pdgCode() == -bachelorPdgCode)) { - isTrueCand = true; - mcLifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); - lmother.SetXYZM(lMother0.px(), lMother0.py(), lMother0.pz(), o2::constants::physics::MassHyperTriton); - } - } - } - } - } - } - } - - candidateAnalysis(collision, vtx, ifHasCandidate, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); - } - - if (ifHasCandidate) - registry.fill(HIST("hEventCounter"), 4.5); - fillHistos(); - resetHistos(); - - for (const auto& cand3body : candidates3body) { - outputMCTable(cand3body.colCentFT0C, - cand3body.isMatter, cand3body.invmass, cand3body.lcand.P(), cand3body.lcand.Pt(), cand3body.ct, - cand3body.cosPA, cand3body.dcadaughters, cand3body.dcacandtopv, cand3body.vtxradius, - cand3body.lproton.Pt(), cand3body.lproton.Eta(), cand3body.lproton.Phi(), cand3body.dauinnermostR[0], - cand3body.lpion.Pt(), cand3body.lpion.Eta(), cand3body.lpion.Phi(), cand3body.dauinnermostR[1], - cand3body.lbachelor.Pt(), cand3body.lbachelor.Eta(), cand3body.lbachelor.Phi(), cand3body.dauinnermostR[2], - cand3body.dautpcNclusters[0], cand3body.dautpcNclusters[1], cand3body.dautpcNclusters[2], - cand3body.dauitsclussize[0], cand3body.dauitsclussize[1], cand3body.dauitsclussize[2], - cand3body.dautpcNsigma[0], cand3body.dautpcNsigma[1], cand3body.dautpcNsigma[2], cand3body.bachelortofNsigma, - cand3body.daudcaxytopv[0], cand3body.daudcaxytopv[1], cand3body.daudcaxytopv[2], - cand3body.daudcatopv[0], cand3body.daudcatopv[1], cand3body.daudcatopv[2], - cand3body.isBachPrimary, - cand3body.lgencand.P(), cand3body.lgencand.Pt(), cand3body.genct, cand3body.lgencand.Phi(), cand3body.lgencand.Eta(), cand3body.lgencand.Rapidity(), - cand3body.isSignal, cand3body.isReco, cand3body.pdgCode, cand3body.survivedEventSelection); - } - } - - // now we fill only the signal candidates that were not reconstructed - for (const auto& mcparticle : particlesMC) { - if (!is3bodyDecayed(mcparticle)) { - continue; - } - if (std::find(filledMothers.begin(), filledMothers.end(), mcparticle.globalIndex()) != std::end(filledMothers)) { - continue; - } - bool isSurEvSelection = isGoodCollision[mcparticle.mcCollisionId()]; - std::array posSV{0.f}; - for (const auto& mcDaughter : mcparticle.daughters_as()) { - if (std::abs(mcDaughter.pdgCode()) == bachelorPdgCode) { - posSV = {mcDaughter.vx(), mcDaughter.vy(), mcDaughter.vz()}; - } - } - double mcLifetime = RecoDecay::sqrtSumOfSquares(posSV[0] - mcparticle.vx(), posSV[1] - mcparticle.vy(), posSV[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - outputMCTable(-1, - -1, -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, - -1, -1, -1, - false, - mcparticle.p(), mcparticle.pt(), mcLifetime, mcparticle.phi(), mcparticle.eta(), mcparticle.y(), - true, false, mcparticle.pdgCode(), isSurEvSelection); - } - } - PROCESS_SWITCH(ThreebodyRecoTask, processMC, "MC reconstruction", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/Utils/decay3bodyBuilderHelper.h b/PWGLF/Utils/decay3bodyBuilderHelper.h index 225b01b1088..1588acb1717 100644 --- a/PWGLF/Utils/decay3bodyBuilderHelper.h +++ b/PWGLF/Utils/decay3bodyBuilderHelper.h @@ -19,8 +19,10 @@ #include "Framework/AnalysisDataModel.h" #include "ReconstructionDataFormats/Track.h" #include "DetectorsBase/GeometryManager.h" +#include "DetectorsVertexing/SVertexHypothesis.h" #include "CommonConstants/PhysicsConstants.h" #include "Common/Core/trackUtilities.h" +#include "Common/Core/RecoDecay.h" #include "Tools/KFparticle/KFUtilities.h" #ifndef HomogeneousField @@ -45,26 +47,29 @@ struct decay3bodyCandidate { // indexing int collisionID = -1; int decay3bodyID = -1; - int trackPosID = -1; - int trackNegID = -1; - int trackBachID = -1; + int protonID = -1; + int pionID = -1; + int deuteronID = -1; // daughter properties - std::array trackPosMom = {0.0f, 0.0f, 0.0f}; - std::array trackNegMom = {0.0f, 0.0f, 0.0f}; - std::array trackBachMom = {0.0f, 0.0f, 0.0f}; - std::array trackPosPos = {0.0f, 0.0f, 0.0f}; - std::array trackNegPos = {0.0f, 0.0f, 0.0f}; - std::array trackBachPos = {0.0f, 0.0f, 0.0f}; - std::array trackDCAxyToPV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach - std::array trackDCAzToPV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach - std::array tpcNsigma = {0.0f, 0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp - float tofNsigmaDeuteron = 0.0f; - float averageITSClusSizeDeuteron = 0.0f; + std::array momProton = {0.0f, 0.0f, 0.0f}; + std::array momPion = {0.0f, 0.0f, 0.0f}; + std::array momDeuteron = {0.0f, 0.0f, 0.0f}; + std::array posProton = {0.0f, 0.0f, 0.0f}; + std::array posPion = {0.0f, 0.0f, 0.0f}; + std::array posDeuteron = {0.0f, 0.0f, 0.0f}; + std::array trackDCAxyToPV = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array trackDCAzToPV = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array tpcNsigma = {0.0f, 0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + double tofNsigmaDeuteron = 0.0f; + std::array averageITSClSize = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array tpcNCl = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron int pidForTrackingDeuteron = 0; // vertex properties - int charge = -1; + float mass; + float massV0; + int sign; float momentum[3]; float position[3]; // std::array momentum = {0.0f, 0.0f, 0.0f}; @@ -73,23 +78,23 @@ struct decay3bodyCandidate { // float dcaxyToPV = 0.0f; float chi2 = 0.0f; float trackedClSize = 0.0f; - float daughterDCAatSV = 0.0f; // quadratic sum of DCA between daughters at SV - std::array daughterDCAtoSV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach + float daughterDCAatSV = 0.0f; // quadratic sum of DCA between daughters at SV + std::array daughterDCAtoSV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach // covariance matrix - float trackPosCov[21] = {0.0f}; - float trackNegCov[21] = {0.0f}; - float trackBachCov[21] = {0.0f}; + float covProton[21] = {0.0f}; + float covPion[21] = {0.0f}; + float covDeuteron[21] = {0.0f}; float covariance[21] = {0.0f}; }; //_______________________________________________________________________ // builder helper class -class Decay3BodyBuilderHelper +class decay3bodyBuilderHelper { public: decay3bodyBuilderHelper() - { + { fitter3body.setPropagateToPCA(true); fitter3body.setMaxR(200.); //->maxRIni3body fitter3body.setMinParamChange(1e-3); @@ -97,6 +102,7 @@ class Decay3BodyBuilderHelper fitter3body.setMaxDZIni(1e9); fitter3body.setMaxDXYIni(4.0f); fitter3body.setMaxChi2(1e9); + fitter3body.setUseAbsDCA(true); fitterV0.setPropagateToPCA(true); fitterV0.setMaxR(200.); @@ -104,7 +110,7 @@ class Decay3BodyBuilderHelper fitterV0.setMinRelChi2Change(0.9); fitterV0.setMaxDZIni(1e9); fitterV0.setMaxChi2(1e9); - fitterV0.setUseAbsDCA(d_UseAbsDCA); + fitterV0.setUseAbsDCA(true); // LUT has to be loaded later lut = nullptr; @@ -121,7 +127,7 @@ class Decay3BodyBuilderHelper decay3bodyCandidate decay3body; // storage for Decay3body candidate properties o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; - std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda + o2::vertexing::SVertexHypothesis mV0Hyps; // 0 - Lambda, 1 - AntiLambda // decay3body candidate criteria struct { @@ -129,20 +135,20 @@ class Decay3BodyBuilderHelper float maxEtaDaughters; int minTPCNClProton; int minTPCNClPion; - int minTPCNClBach; + int minTPCNClDeuteron; float minDCAProtonToPV; float minDCAPionToPV; - float minDCABachToPV; + float minDCADeuteronToPV; float minPtProton; float minPtPion; - float minPtBach; + float minPtDeuteron; float maxPtProton; float maxPtPion; - float maxPtBach; + float maxPtDeuteron; float maxTPCnSigma; - float minTOFnSigmaDeuteron; - float maxTOFnSigmaDeuteron; - float minPBachUseTOF; + double minTOFnSigmaDeuteron; + double maxTOFnSigmaDeuteron; + float minPDeuteronUseTOF; float maxDCADauAtSV; // candidate float maxRapidity; @@ -174,13 +180,12 @@ class Decay3BodyBuilderHelper // build Decay3body from three tracks, including V0 building. template bool buildDecay3BodyCandidate(TCollision const& collision, - TTrack const& trackPos, - TTrack const& trackNeg, - TTrack const& trackBach, - int decay3bodyIndex, - float tofNsigmaDeuteron, + TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, + int decay3bodyIndex, + double tofNsigmaDeuteron, float trackedClSize, - int bachelorcharge = 1, bool useKFParticle = false, bool kfSetTopologicalConstraint = false, bool useSelections = true, @@ -193,104 +198,74 @@ class Decay3BodyBuilderHelper float pvX = collision.posX(); float pvY = collision.posY(); float pvZ = collision.posZ(); - bool isMatter = trackBach.sign() > 0 ? true : false; - auto trackParCovPos = getTrackParCov(trackPos); - auto trackParCovNeg = getTrackParCov(trackNeg); - auto trackParCovBach = getTrackParCov(trackBach); + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); decay3body.collisionID = collisionIndex; decay3body.decay3bodyID = decay3bodyIndex; - decay3body.trackPosID = trackPos.globalIndex(); - decay3body.trackNegID = trackNeg.globalIndex(); - decay3body.trackBachID = trackBach.globalIndex(); + decay3body.protonID = trackProton.globalIndex(); + decay3body.pionID = trackPion.globalIndex(); + decay3body.deuteronID = trackDeuteron.globalIndex(); //_______________________________________________________________________ // track selections - if constexpr (useSelections) { + if (useSelections) { // proton track quality - if (isMatter && trackPos.tpcNCls() < decay3bodyselections.minTPCNClProton) { - decay3body = {}; - return false; - } else if (!isMatter && trackNeg.tpcNCls() < decay3bodyselections.minTPCNClProton) { + if (trackProton.tpcNClsFound() < decay3bodyselections.minTPCNClProton) { decay3body = {}; return false; } // pion track quality if (useTPCforPion) { - if (isMatter && trackNeg.tpcNCls() < decay3bodyselections.minTPCNClPion) { - decay3body = {}; - return false; - } else if (!isMatter && trackPos.tpcNCls() < decay3bodyselections.minTPCNClPion) { + if (trackPion.tpcNClsFound() < decay3bodyselections.minTPCNClPion) { decay3body = {}; return false; } } - // bachelor track quality - if (trackBach.tpcNCls() < decay3bodyselections.minTPCNClBach) { - decay3body = {}; - return false; - } - - // track signs - if (trackPos.sign() != +1 || trackNeg.sign() != -1) { + // deuteron track quality + if (trackDeuteron.tpcNClsFound() < decay3bodyselections.minTPCNClDeuteron) { decay3body = {}; return false; } // track eta - if (std::fabs(trackPos.eta()) > decay3bodyselections.maxEtaDaughters) { + if (std::fabs(trackProton.eta()) > decay3bodyselections.maxEtaDaughters) { decay3body = {}; return false; } - if (std::fabs(trackNeg.eta()) > decay3bodyselections.maxEtaDaughters) { + if (std::fabs(trackPion.eta()) > decay3bodyselections.maxEtaDaughters) { decay3body = {}; return false; } - if (std::fabs(trackBach.eta()) > decay3bodyselections.maxEtaDaughters) { + if (std::fabs(trackDeuteron.eta()) > decay3bodyselections.maxEtaDaughters) { decay3body = {}; return false; } // TPC only - if (!acceptTPCOnly && !trackPos.hasITS()) { + if (!acceptTPCOnly && (!trackProton.hasITS() || !trackPion.hasITS() || !trackDeuteron.hasITS())) { decay3body = {}; return false; } - if (!acceptTPCOnly && !trackNeg.hasITS()) { + + // daughter TPC PID + if (std::fabs(trackProton.tpcNSigmaPr()) > decay3bodyselections.maxTPCnSigma) { decay3body = {}; return false; } - if (!acceptTPCOnly && !trackBach.hasITS()) { + if (useTPCforPion && std::fabs(trackPion.tpcNSigmaPi()) > decay3bodyselections.maxTPCnSigma) { decay3body = {}; return false; } - - // daughter TPC PID - if (isMatter) { - if (std::fabs(trackPos.tpcNsigmaPr()) > decay3bodyselections.maxTPCnSigma) { - decay3body = {}; - return false; - } else if(useTPCforPion && std::fabs(trackNeg.tpcNsigmaPi()) > decay3bodyselections.maxTPCnSigma) { - decay3body = {}; - return false; - } - } else if (!isMatter) { - if (std::fabs(trackNeg.tpcNsigmaPr()) > decay3bodyselections.maxTPCnSigma) { - decay3body = {}; - return false; - } else if (useTPCforPion && std::fabs(trackPos.tpcNsigmaPi()) > decay3bodyselections.maxTPCnSigma) { - decay3body = {}; - return false; - } - } - if (std::fabs(trackBach.tpcNsigmaDeuteron()) > decay3bodyselections.maxTPCnSigma) { + if (std::fabs(trackDeuteron.tpcNSigmaDe()) > decay3bodyselections.maxTPCnSigma) { decay3body = {}; return false; } // deuteron TOF PID - if ((tofNsigmaDeuteron < decay3bodyselections.minTOFnSigmaDeuteron || tofNsigmaDeuteron > decay3bodyselections.maxTOFnSigmaDeuteron) && trackBach.p() > decay3bodyselections.minPBachUseTOF) { + if ((tofNsigmaDeuteron < decay3bodyselections.minTOFnSigmaDeuteron || tofNsigmaDeuteron > decay3bodyselections.maxTOFnSigmaDeuteron) && trackDeuteron.p() > decay3bodyselections.minPDeuteronUseTOF) { decay3body = {}; return false; } @@ -300,47 +275,41 @@ class Decay3BodyBuilderHelper // daughter track DCA to PV associated with decay3body o2::dataformats::VertexBase mPV; o2::dataformats::DCA mDcaInfoCov; - auto trackParCovPosCopy = trackParCovPos; - auto trackParCovNegCopy = trackParCovNeg; - auto trackParCovBachCopy = trackParCovBach; + auto trackParCovProtonCopy = trackParCovProton; + auto trackParCovPionCopy = trackParCovPion; + auto trackParCovDeuteronCopy = trackParCovDeuteron; mPV.setPos({pvX, pvY, pvZ}); mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - // positive track - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPosCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); + // proton track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovProtonCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); decay3body.trackDCAxyToPV[0] = mDcaInfoCov.getY(); decay3body.trackDCAzToPV[0] = mDcaInfoCov.getZ(); - auto trackPosDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[0] * decay3body.trackDCAxyToPV[0] + decay3body.trackDCAzToPV[0] * decay3body.trackDCAzToPV[0]); - if constexpr (useSelections) { - if (isMatter && trackPosDCAToPV < decay3bodyselections.minDCAProtonToPV) { - decay3body = {}; - return false; - } else if (!isMatter && trackPosDCAToPV < decay3bodyselections.minDCAPionToPV) { + auto trackProtonDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[0] * decay3body.trackDCAxyToPV[0] + decay3body.trackDCAzToPV[0] * decay3body.trackDCAzToPV[0]); + if (useSelections) { + if (trackProtonDCAToPV < decay3bodyselections.minDCAProtonToPV) { decay3body = {}; return false; } } - // negative track - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParNegPosCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); + // pion track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPionCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); decay3body.trackDCAxyToPV[1] = mDcaInfoCov.getY(); decay3body.trackDCAzToPV[1] = mDcaInfoCov.getZ(); - auto trackNegDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[1] * decay3body.trackDCAxyToPV[1] + decay3body.trackDCAzToPV[1] * decay3body.trackDCAzToPV[1]); - if constexpr (useSelections) { - if (isMatter && trackNegDCAToPV < decay3bodyselections.minDCAPionToPV) { - decay3body = {}; - return false; - } else if (!isMatter && trackNegDCAToPV < decay3bodyselections.minDCAProtonToPV) { + auto trackPionDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[1] * decay3body.trackDCAxyToPV[1] + decay3body.trackDCAzToPV[1] * decay3body.trackDCAzToPV[1]); + if (useSelections) { + if (trackPionDCAToPV < decay3bodyselections.minDCAPionToPV) { decay3body = {}; return false; } } - // bachelor track - o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovBachCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); + // deuteron track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovDeuteronCopy, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); decay3body.trackDCAxyToPV[2] = mDcaInfoCov.getY(); decay3body.trackDCAzToPV[2] = mDcaInfoCov.getZ(); - auto trackBachDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[2] * decay3body.trackDCAxyToPV[2] + decay3body.trackDCAzToPV[2] * decay3body.trackDCAzToPV[2]); - if constexpr (useSelections) { - if (trackBachDCAToPV < decay3bodyselections.minDCABachToPV) { + auto trackDeuteronDCAToPV = std::sqrt(decay3body.trackDCAxyToPV[2] * decay3body.trackDCAxyToPV[2] + decay3body.trackDCAzToPV[2] * decay3body.trackDCAzToPV[2]); + if (useSelections) { + if (trackDeuteronDCAToPV < decay3bodyselections.minDCADeuteronToPV) { decay3body = {}; return false; } @@ -349,69 +318,63 @@ class Decay3BodyBuilderHelper //_______________________________________________________________________ // fit 3body vertex if (!useKFParticle) { - fitVertexWithDCAFitter(collision, trackParCovPos, trackParCovNeg, trackParCovBach, bachelorcharge, calculateCovariance); + fitVertexWithDCAFitter(trackProton, trackPion, trackDeuteron, calculateCovariance); } else { - fitVertexWithKF(collision, trackParCovPos, trackParCovNeg, trackParCovBach, bachelorcharge, kfSetTopologicalConstraint, calculateCovariance); + fitVertexWithKF(collision, trackProton, trackPion, trackDeuteron, kfSetTopologicalConstraint, calculateCovariance); } //_______________________________________________________________________ // get vertex information // daughter pT - auto trackPosPt = std::sqrt(decay3body.trackPosMom[0] * decay3body.trackPosMom[0] + decay3body.trackPosMom[1] * decay3body.trackPosMom[1]); - auto trackNegPt = std::sqrt(decay3body.trackNegMom[0] * decay3body.trackNegMom[0] + decay3body.trackNegMom[1] * decay3body.trackNegMom[1]); - auto trackBachPt = std::sqrt(decay3body.trackBachMom[0] * decay3body.trackBachMom[0] + decay3body.trackBachMom[1] * decay3body.trackBachMom[1]); + auto trackProtonPt = std::sqrt(decay3body.momProton[0] * decay3body.momProton[0] + decay3body.momProton[1] * decay3body.momProton[1]); + auto trackPionPt = std::sqrt(decay3body.momPion[0] * decay3body.momPion[0] + decay3body.momPion[1] * decay3body.momPion[1]); + auto trackDeuteronPt = std::sqrt(decay3body.momDeuteron[0] * decay3body.momDeuteron[0] + decay3body.momDeuteron[1] * decay3body.momDeuteron[1]); // DCA between daughters at SV decay3body.daughterDCAatSV = std::hypot( - std::hypot(decay3body.trackPosPos[0] - decay3body.trackNegPos[0], - decay3body.trackPosPos[1] - decay3body.trackNegPos[1], - decay3body.trackPosPos[2] - decay3body.trackNegPos[2]), - std::hypot(decay3body.trackPosPos[0] - decay3body.trackBachPos[0], - decay3body.trackPosPos[1] - decay3body.trackBachPos[1], - decay3body.trackPosPos[2] - decay3body.trackBachPos[2]), - std::hypot(decay3body.trackNegPos[0] - decay3body.trackBachPos[0], - decay3body.trackNegPos[1] - decay3body.trackBachPos[1], - decay3body.trackNegPos[2] - decay3body.trackBachPos[2])); - + std::hypot(decay3body.posProton[0] - decay3body.posPion[0], + decay3body.posProton[1] - decay3body.posPion[1], + decay3body.posProton[2] - decay3body.posPion[2]), + std::hypot(decay3body.posProton[0] - decay3body.posDeuteron[0], + decay3body.posProton[1] - decay3body.posDeuteron[1], + decay3body.posProton[2] - decay3body.posDeuteron[2]), + std::hypot(decay3body.posPion[0] - decay3body.posProton[0], + decay3body.posPion[1] - decay3body.posProton[1], + decay3body.posPion[2] - decay3body.posProton[2])); + // daughter DCA to SV - // positive daughter + // proton daughter decay3body.daughterDCAtoSV[0] = std::hypot( - decay3body.trackPosPos[0] - decay3body.position[0], - decay3body.trackPosPos[1] - decay3body.position[1], - decay3body.trackPosPos[2] - decay3body.position[2]); - // negative daughter + decay3body.posProton[0] - decay3body.position[0], + decay3body.posProton[1] - decay3body.position[1], + decay3body.posProton[2] - decay3body.position[2]); + // pion daughter decay3body.daughterDCAtoSV[1] = std::hypot( - decay3body.trackNegPos[0] - decay3body.position[0], - decay3body.trackNegPos[1] - decay3body.position[1], - decay3body.trackNegPos[2] - decay3body.position[2]); - // bachelor daughter + decay3body.posPion[0] - decay3body.position[0], + decay3body.posPion[1] - decay3body.position[1], + decay3body.posPion[2] - decay3body.position[2]); + // deuteron daughter decay3body.daughterDCAtoSV[2] = std::hypot( - decay3body.trackBachPos[0] - decay3body.position[0], - decay3body.trackBachPos[1] - decay3body.position[1], - decay3body.trackBachPos[2] - decay3body.position[2]); - + decay3body.posDeuteron[0] - decay3body.position[0], + decay3body.posDeuteron[1] - decay3body.position[1], + decay3body.posDeuteron[2] - decay3body.position[2]); + //_____________________________________________________ // selections after vertex fit - if constexpr (useSelections) { + if (useSelections) { // daughter pT // proton - if (isMatter && (trackPosPt < decay3bodyselections.minPtProton || trackPosPt > decay3bodyselections.maxPtProton)) { - decay3body = {}; - return false; - } else if (!isMatter && (trackNegPt < decay3bodyselections.minPtProton || trackNegPt > decay3bodyselections.maxPtProton)) { + if (trackProtonPt < decay3bodyselections.minPtProton || trackProtonPt > decay3bodyselections.maxPtProton) { decay3body = {}; return false; } // pion - if (isMatter && (trackNegPt < decay3bodyselections.minPtPion || trackNegPt > decay3bodyselections.maxPtPion)) { - decay3body = {}; - return false; - } else if (!isMatter && (trackPosPt < decay3bodyselections.minPtPion || trackPosPt > decay3bodyselections.maxPtPion)) { + if (trackPionPt < decay3bodyselections.minPtPion || trackPionPt > decay3bodyselections.maxPtPion) { decay3body = {}; return false; } - // bachelor - if (trackBachPt < decay3bodyselections.minPtBach || trackBachPt > decay3bodyselections.maxPtBach) { + // deuteron + if (trackDeuteronPt < decay3bodyselections.minPtDeuteron || trackDeuteronPt > decay3bodyselections.maxPtDeuteron) { decay3body = {}; return false; } @@ -467,38 +430,50 @@ class Decay3BodyBuilderHelper //_______________________________________________________________________ // SVertexer selections in case of event mixing if (isEventMixing) { - applySVertexerCuts(collision, trackParCovPos, trackParCovNeg, trackParCovBach, /*applyV0Cut = */true); + applySVertexerCuts(collision, trackProton, trackPion, trackDeuteron, /*applyV0Cut = */ true); } //_______________________________________________________________________ // fill remaining candidate information // daughter PID - if (isMatter) { - decay3body.tpcNsigma[0] = trackPos.tpcNsigmaPr(); - decay3body.tpcNsigma[1] = trackNeg.tpcNsigmaPi(); - } else if (!isMatter) { - decay3body.tpcNsigma[0] = trackNeg.tpcNsigmaPr(); - decay3body.tpcNsigma[1] = trackPos.tpcNsigmaPi(); - } - decay3body.tpcNsigma[2] = trackBach.tpcNsigmaDeuteron(); - decay3body.tpcNsigma[3] = trackBach.tpcNsigmaPi(); + decay3body.tpcNsigma[0] = trackProton.tpcNSigmaPr(); + decay3body.tpcNsigma[1] = trackPion.tpcNSigmaPi(); + decay3body.tpcNsigma[2] = trackDeuteron.tpcNSigmaDe(); + decay3body.tpcNsigma[3] = trackDeuteron.tpcNSigmaPi(); // recalculated bachelor TOF PID decay3body.tofNsigmaDeuteron = tofNsigmaDeuteron; - // average ITS cluster size of deuteron track - double averageClusterSizeDeuteron(0); - int nCls(0); + // average ITS cluster size of daughter tracks + double averageClusterSizeProton(0), averageClusterSizePion(0), averageClusterSizeDeuteron(0); + int nClsProton(0), nClsPion(0), nClsDeuteron(0); for (int i = 0; i < 7; i++) { - int clusterSize = trackBach.itsClsSizeInLayer(i); - averageClusterSizeDeuteron += static_cast(clusterSize); - if (clusterSize > 0) - nCls++; - } - averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nCls); - decay3body.averageITSClusSizeDeuteron = averageITSClusSizeDeuteron; + int clusterSizePr = trackProton.itsClsSizeInLayer(i); + int clusterSizePi = trackPion.itsClsSizeInLayer(i); + int clusterSizeDe = trackDeuteron.itsClsSizeInLayer(i); + averageClusterSizeProton += static_cast(clusterSizePr); + averageClusterSizePion += static_cast(clusterSizePi); + averageClusterSizeDeuteron += static_cast(clusterSizeDe); + if (clusterSizePr > 0) + nClsProton++; + if (clusterSizePi > 0) + nClsPion++; + if (clusterSizeDe > 0) + nClsDeuteron++; + } + averageClusterSizeProton = averageClusterSizeProton / static_cast(nClsProton); + averageClusterSizePion = averageClusterSizePion / static_cast(nClsPion); + averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nClsDeuteron); + decay3body.averageITSClSize[0] = averageClusterSizeProton; + decay3body.averageITSClSize[1] = averageClusterSizePion; + decay3body.averageITSClSize[2] = averageClusterSizeDeuteron; + + // number of TPC clusters + decay3body.tpcNCl[0] = trackProton.tpcNClsFound(); + decay3body.tpcNCl[1] = trackPion.tpcNClsFound(); + decay3body.tpcNCl[2] = trackDeuteron.tpcNClsFound(); // PID for tracking of deuteron track - decay3body.pidForTrackingDeuteron = trackBach.pidForTracking(); + decay3body.pidForTrackingDeuteron = trackDeuteron.pidForTracking(); // tracked cluster size decay3body.trackedClSize = trackedClSize; @@ -506,41 +481,42 @@ class Decay3BodyBuilderHelper return true; } - //_______________________________________________________________________ - // build Decay3body from V0 and bachelor - // template <> - // bool buildDecay3BodyCandidate() - // { - // return true; - // } - //___________________________________________________________________________________ // functionality to fit 3body vertex with KFParticle and fill vertex information - template + template void fitVertexWithKF(TCollision const& collision, - TTrackParCov const& trackParCovPos, - TTrackParCov const& trackParCovNeg, - TTrackParCov const& trackParCovBach, - int bachelorcharge = 1, + TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, bool kfSetTopologicalConstraint = true, bool calculateCovariance = true) { - bool isMatter = trackParCovBach.sign() > 0 ? true : false; + // get TrackParCov daughters + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); // initialise KF primary vertex - KPFVertex kfpVertex = createKFPVertexFromCollision(collision); + KFVertex kfpVertex = createKFPVertexFromCollision(collision); KFParticle kfpv(kfpVertex); // create KFParticle objects KFParticle kfpProton, kfpPion, kfpDeuteron; - if (isMatter) { - kfpProton = createKFParticleFromTrackParCov(trackParCovPos, trackParCovPos.sign(), constants::physics::MassProton); - kfpPion = createKFParticleFromTrackParCov(trackParCovNeg, trackParCovNeg.sign(), constants::physics::MassPionCharged); - } else if (!isMatter) { - kfpProton = createKFParticleFromTrackParCov(trackParCovNeg, trackParCovNeg.sign(), constants::physics::MassProton); - kfpPion = createKFParticleFromTrackParCov(trackParCovPos, trackParCovPos.sign(), constants::physics::MassPionCharged); + kfpProton = createKFParticleFromTrackParCov(trackParCovProton, trackProton.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovPion, trackPion.sign(), constants::physics::MassPionCharged); + kfpDeuteron = createKFParticleFromTrackParCov(trackParCovDeuteron, trackDeuteron.sign(), constants::physics::MassDeuteron); + + // construct V0 vertex + KFParticle KFV0; + int nDaughtersV0 = 2; + const KFParticle* DaughtersV0[2] = {&kfpProton, &kfpPion}; + KFV0.SetConstructMethod(2); + try { + KFV0.Construct(DaughtersV0, nDaughtersV0); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create V0 vertex." << e.what(); + return; } - kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, trackParCovBach.sign(), constants::physics::MassDeuteron); // construct vertex KFParticle KFH3L; @@ -568,57 +544,46 @@ class Decay3BodyBuilderHelper decay3body.momentum[1] = KFH3L.GetPy(); decay3body.momentum[2] = KFH3L.GetPz(); - // get charge - decay3body.charge = KFH3L.GetQ(); + // get sign + decay3body.sign = KFH3L.GetQ() / std::abs(KFH3L.GetQ()); // transport all daughter tracks to hypertriton vertex kfpProton.TransportToPoint(decay3body.position); kfpPion.TransportToPoint(decay3body.position); kfpDeuteron.TransportToPoint(decay3body.position); - // daughter momenta and positions - if (isMatter) { - decay3body.trackPosMom[0] = kfpProton.GetPx(); - decay3body.trackPosMom[1] = kfpProton.GetPy(); - decay3body.trackPosMom[2] = kfpProton.GetPz(); - decay3body.trackNegMom[0] = kfpPion.GetPx(); - decay3body.trackNegMom[1] = kfpPion.GetPy(); - decay3body.trackNegMom[2] = kfpPion.GetPz(); - decay3body.trackPosPos[0] = kfpProton.GetX(); - decay3body.trackPosPos[1] = kfpProton.GetY(); - decay3body.trackPosPos[2] = kfpProton.GetZ(); - decay3body.trackNegPos[0] = kfpPion.GetX(); - decay3body.trackNegPos[1] = kfpPion.GetY(); - decay3body.trackNegPos[2] = kfpPion.GetZ(); - } else { - decay3body.trackPosMom[0] = kfpPion.GetPx(); - decay3body.trackPosMom[1] = kfpPion.GetPy(); - decay3body.trackPosMom[2] = kfpPion.GetPz(); - decay3body.trackNegMom[0] = kfpProton.GetPx(); - decay3body.trackNegMom[1] = kfpProton.GetPy(); - decay3body.trackNegMom[2] = kfpProton.GetPz(); - decay3body.trackPosPos[0] = kfpPion.GetX(); - decay3body.trackPosPos[1] = kfpPion.GetY(); - decay3body.trackPosPos[2] = kfpPion.GetZ(); - decay3body.trackNegPos[0] = kfpProton.GetX(); - decay3body.trackNegPos[1] = kfpProton.GetY(); - decay3body.trackNegPos[2] = kfpProton.GetZ(); - } - decay3body.trackBachMom[0] = kfpDeuteron.GetPx(); - decay3body.trackBachMom[1] = kfpDeuteron.GetPy(); - decay3body.trackBachMom[2] = kfpDeuteron.GetPz(); - decay3body.trackBachPos[0] = kfpDeuteron.GetX(); - decay3body.trackBachPos[1] = kfpDeuteron.GetY(); - decay3body.trackBachPos[2] = kfpDeuteron.GetZ(); - for (int i = 0; i < 3; i++) { - trackBachMom[i] *= bachelorcharge; - } + // daughter positions + decay3body.posProton[0] = kfpProton.GetX(); + decay3body.posProton[1] = kfpProton.GetY(); + decay3body.posProton[2] = kfpProton.GetZ(); + decay3body.posPion[0] = kfpPion.GetX(); + decay3body.posPion[1] = kfpPion.GetY(); + decay3body.posPion[2] = kfpPion.GetZ(); + decay3body.posDeuteron[0] = kfpDeuteron.GetX(); + decay3body.posDeuteron[1] = kfpDeuteron.GetY(); + decay3body.posDeuteron[2] = kfpDeuteron.GetZ(); + + // daughter momenta + decay3body.momProton[0] = kfpProton.GetPx(); + decay3body.momProton[1] = kfpProton.GetPy(); + decay3body.momProton[2] = kfpProton.GetPz(); + decay3body.momPion[0] = kfpPion.GetPx(); + decay3body.momPion[1] = kfpPion.GetPy(); + decay3body.momPion[2] = kfpPion.GetPz(); + decay3body.momDeuteron[0] = kfpDeuteron.GetPx(); + decay3body.momDeuteron[1] = kfpDeuteron.GetPy(); + decay3body.momDeuteron[2] = kfpDeuteron.GetPz(); // candidate mass float mass, massErr; KFH3L.GetMass(mass, massErr); decay3body.mass = mass; - + + // V0 mass + float massV0, massV0Err; + KFV0.GetMass(massV0, massV0Err); + decay3body.massV0 = massV0; + // vertex chi2 decay3body.chi2 = KFH3L.GetChi2() / KFH3L.GetNDF(); @@ -632,9 +597,9 @@ class Decay3BodyBuilderHelper } // daughter track covariance matrices for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) - decay3body.trackPosCov[i] = kfpProton.GetCovariance(i); - decay3body.trackNegCov[i] = kfpPion.GetCovariance(i); - decay3body.trackBachCov[i] = kfpDeuteron.GetCovariance(i); + decay3body.covProton[i] = kfpProton.GetCovariance(i); + decay3body.covPion[i] = kfpPion.GetCovariance(i); + decay3body.covDeuteron[i] = kfpDeuteron.GetCovariance(i); } } @@ -643,18 +608,19 @@ class Decay3BodyBuilderHelper //_______________________________________________________________________ // functionality to fit 3body vertex with DCAFitter - template - void fitVertexWithDCAFitter(TCollision const& collision, - TTrackParCov const& trackParCovPos, - TTrackParCov const& trackParCovNeg, - TTrackParCov const& trackParCovBach - int bachelorcharge = 1, + template + void fitVertexWithDCAFitter(TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, bool calculateCovariance = true) { - bool isMatter = trackParCovBach.sign() > 0 ? true : false; + // get TrackParCov daughters + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); // fit the vertex - int n3bodyVtx = fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); + int n3bodyVtx = fitter3body.process(trackParCovProton, trackParCovPion, trackParCovDeuteron); if (n3bodyVtx == 0) { // discard this pair return; } @@ -666,38 +632,39 @@ class Decay3BodyBuilderHelper } // get daughter momenta - const auto& propagatedTrackPos = fitter3body.getTrack(0); - const auto& propagatedTrackNeg = fitter3body.getTrack(1); - const auto& propagatedTrackBach = fitter3body.getTrack(2); - propagatedTrackPos.getPxPyPzGlo(trackPosMom); - propagatedTrackNeg.getPxPyPzGlo(trackNegMom); - propagatedTrackBach.getPxPyPzGlo(trackBachMom); - for (int i = 0; i < 3; i++) { - trackBachMom[i] *= bachelorcharge; - } + const auto& propagatedTrackProton = fitter3body.getTrack(0); + const auto& propagatedTrackPion = fitter3body.getTrack(1); + const auto& propagatedTrackDeuteron = fitter3body.getTrack(2); + propagatedTrackProton.getPxPyPzGlo(decay3body.momProton); + propagatedTrackPion.getPxPyPzGlo(decay3body.momPion); + propagatedTrackDeuteron.getPxPyPzGlo(decay3body.momDeuteron); + propagatedTrackProton.getXYZGlo(decay3body.posProton); + propagatedTrackPion.getXYZGlo(decay3body.posPion); + propagatedTrackDeuteron.getXYZGlo(decay3body.posDeuteron); + + // get daughter positions at vertex // calculate candidate momentum - decay3body.momentum[0] = trackPosMom[0] + trackNegMom[0] + trackBachMom[0]; - decay3body.momentum[1] = trackPosMom[1] + trackNegMom[1] + trackBachMom[1]; - decay3body.momentum[2] = trackPosMom[2] + trackNegMom[2] + trackBachMom[2]; + decay3body.momentum[0] = decay3body.momProton[0] + decay3body.momPion[0] + decay3body.momDeuteron[0]; + decay3body.momentum[1] = decay3body.momProton[1] + decay3body.momPion[1] + decay3body.momDeuteron[1]; + decay3body.momentum[2] = decay3body.momProton[2] + decay3body.momPion[2] + decay3body.momDeuteron[2]; + + // candidate and V0 mass + decay3body.mass = RecoDecay::m( + std::array{std::array{decay3body.momProton[0], decay3body.momProton[1], decay3body.momProton[2]}, + std::array{decay3body.momPion[0], decay3body.momPion[1], decay3body.momPion[2]}, + std::array{decay3body.momDeuteron[0], decay3body.momDeuteron[1], decay3body.momDeuteron[2]}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + decay3body.massV0 = RecoDecay::m( + std::array{std::array{decay3body.momProton[0], decay3body.momProton[1], decay3body.momProton[2]}, + std::array{decay3body.momPion[0], decay3body.momPion[1], decay3body.momPion[2]}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - // candidate mass - if (isMatter) { - decay3body.mass = RecoDecay::m( - std::array{std::array{trackPosMom[0], trackPosMom[1], trackPosMom[2]}, - std::array{trackNegMom[0], trackNegMom[1], trackNegMom[2]}, - std::array{trackBachMom[0], trackBachMom[1], trackBachMom[2]}}, - std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - } else { - decay3body.mass = RecoDecay::m( - std::array{std::array{trackPosMom[0], trackPosMom[1], trackPosMom[2]}, - std::array{trackNegMom[0], trackNegMom[1], trackNegMom[2]}, - std::array{trackBachMom[0], trackBachMom[1], trackBachMom[2]}}, - std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); - } - // vertex chi2 at PCA - decay3body.chi2 = fitter3body.getChhi2AtPCACandidate(): + decay3body.chi2 = fitter3body.getChi2AtPCACandidate(); + + // candidate sign + decay3body.sign = trackDeuteron.sign(); // caluclate covariance matrices if (calculateCovariance) { @@ -710,21 +677,21 @@ class Decay3BodyBuilderHelper decay3body.covariance[4] = covVtxV(2, 1); decay3body.covariance[5] = covVtxV(2, 2); // daughter covariance matrices - std::array covTpos = {0.}; - std::array covTneg = {0.}; - std::array covTbach = {0.}; - propagatedTrackPos.getCovXYZPxPyPzGlo(covTpos); - propagatedTrackNeg.getCovXYZPxPyPzGlo(covTneg); - propagatedTrackBach.getCovXYZPxPyPzGlo(covTbach); + std::array covTproton = {0.}; + std::array covTpion = {0.}; + std::array covTdeuteron = {0.}; + propagatedTrackProton.getCovXYZPxPyPzGlo(covTproton); + propagatedTrackPion.getCovXYZPxPyPzGlo(covTpion); + propagatedTrackDeuteron.getCovXYZPxPyPzGlo(covTdeuteron); for (int i = 0; i < 21; i++) { - decay3body.trackPosCov[i] = covTpos[i]; - decay3body.trackNegCov[i] = covTneg[i]; - decay3body.trackBachCov[i] = covTbach[i]; + decay3body.covProton[i] = covTproton[i]; + decay3body.covPion[i] = covTpion[i]; + decay3body.covDeuteron[i] = covTdeuteron[i]; } // candidate momentum covairance matrix constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component for (int i = 0; i < 6; i++) { - decay3body.covariance[MomInd[i]] = covTpos[MomInd[i]] + covTneg[MomInd[i]] + covTbach[MomInd[i]]; + decay3body.covariance[MomInd[i]] = covTproton[MomInd[i]] + covTpion[MomInd[i]] + covTdeuteron[MomInd[i]]; } /// WARNING: position-momentum covariances are not calculated in the DCAFitter - remain zero } @@ -734,18 +701,22 @@ class Decay3BodyBuilderHelper //_______________________________________________________________________ // functionality to apply SVertexer cuts in case of event mixing - template - void applySVertexerCuts(TCollisions const& collision, - TTrackParCov const& trackParCovPos, - TTrackParCov const& trackParCovNeg, - TTrackParCov const& trackParCovBach, + template + void applySVertexerCuts(TCollision const& collision, + TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, bool applyV0Cut = true) { + // get TrackParCov daughters + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); + const float pidCutsLambda[o2::vertexing::SVertexHypothesis::NPIDParams] = {0., 20, 0., 5.0, 0.0, 1.09004e-03, 2.62291e-04, 8.93179e-03, 2.83121}; // Lambda - mV0Hyps[0].set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, fitter3body.getBz()); - mV0Hyps[1].set(o2::track::PID::Lambda, o2::track::PID::Pion, o2::track::PID::Proton, pidCutsLambda, fitter3body.getBz()); + mV0Hyps.set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, fitter3body.getBz()); - int nV0 = fitterV0.process(trackParCovPos, trackParCovNeg); + int nV0 = fitterV0.process(trackParCovProton, trackParCovPion); if (nV0 == 0) { return; } @@ -760,17 +731,17 @@ class Decay3BodyBuilderHelper return; } - const auto& trPProp = fitterV0.getTrack(0, cand); - const auto& trNProp = fitterV0.getTrack(1, cand); - std::array pP{}, pN{}; - trPProp.getPxPyPzGlo(pP); - trNProp.getPxPyPzGlo(pN); - std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; + const auto& trProtonProp = fitterV0.getTrack(0, cand); + const auto& trPionProp = fitterV0.getTrack(1, cand); + std::array pProtonV0{}, pPionV0{}; + trProtonProp.getPxPyPzGlo(pProtonV0); + trPionProp.getPxPyPzGlo(pPionV0); + std::array pV0 = {pProtonV0[0] + pPionV0[0], pProtonV0[1] + pPionV0[1], pProtonV0[2] + pPionV0[2]}; // Cut for Virtual V0 float dxv0 = v0pos[0] - mMeanVertex.getX(), dyv0 = v0pos[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; float rv0 = std::sqrt(r2v0); float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; - if (applyV0Cut && pt2V0 <= svertexerselections.mMinPt2V0) { + if (applyV0Cut && pt2V0 <= svertexerselections.minPt2V0) { return; } if (applyV0Cut && pV0[2] * pV0[2] / pt2V0 > svertexerselections.maxTgl2V0) { // tgLambda cut @@ -779,14 +750,11 @@ class Decay3BodyBuilderHelper float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); // apply mass selections - 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]; + float p2Proton = pProtonV0[0] * pProtonV0[0] + pProtonV0[1] * pProtonV0[1] + pProtonV0[2] * pProtonV0[2], p2Pion = pPionV0[0] * pPionV0[0] + pPionV0[1] * pPionV0[1] + pPionV0[2] * pPionV0[2]; bool good3bodyV0Hyp = false; - for (int ipid = 0; ipid < 2; ipid++) { - float massForLambdaHyp = mV0Hyps[ipid].calcMass(p2Pos, p2Neg, p2V0); - if (massForLambdaHyp - mV0Hyps[ipid].getMassV0Hyp() < mV0Hyps[ipid].getMargin(ptV0)) { - good3bodyV0Hyp = true; - break; - } + float massForLambdaHyp = mV0Hyps.calcMass(p2Proton, p2Pion, p2V0); + if (massForLambdaHyp - mV0Hyps.getMassV0Hyp() < mV0Hyps.getMargin(ptV0)) { + good3bodyV0Hyp = true; } if (applyV0Cut && !good3bodyV0Hyp) { return; @@ -802,14 +770,17 @@ class Decay3BodyBuilderHelper return; } // Check: CosPA Cut of Virtual V0 may not be used since the V0 may be based on another PV - float dx = v0pos[0] - collision.posX(), dy = v0pos[1] - collision.posY(), dz = v0pos[2] - collision.posZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; + float dx = v0pos[0] - collision.posX(); + float dy = v0pos[1] - collision.posY(); + float dz = v0pos[2] - collision.posZ(); + float prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; float v0CosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); if (applyV0Cut && v0CosPA < svertexerselections.minCosPA3bodyV0) { return; } // 3body vertex - int n3bodyVtx = fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); + int n3bodyVtx = fitter3body.process(trackParCovProton, trackParCovPion, trackParCovDeuteron); if (n3bodyVtx == 0) { // discard this pair return; } @@ -819,17 +790,14 @@ class Decay3BodyBuilderHelper pos[i] = vertexXYZ[i]; } - std::array p0 = {0.}, p1 = {0.}, p2{0.}; - const auto& propagatedTrackPos = fitter3body.getTrack(0); - const auto& propagatedTrackNeg = fitter3body.getTrack(1); - const auto& propagatedTrackBach = fitter3body.getTrack(2); - propagatedTrackPos.getPxPyPzGlo(p0); - propagatedTrackNeg.getPxPyPzGlo(p1); - propagatedTrackBach.getPxPyPzGlo(p2); - for (int i = 0; i < 3; i++) { - p2[i] *= bachelorcharge; - } - std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; + std::array pProton = {0.}, pPion = {0.}, pDeuteron{0.}; + const auto& propagatedTrackProton = fitter3body.getTrack(0); + const auto& propagatedTrackPion = fitter3body.getTrack(1); + const auto& propagatedTrackDeuteron = fitter3body.getTrack(2); + propagatedTrackProton.getPxPyPzGlo(pProton); + propagatedTrackPion.getPxPyPzGlo(pPion); + propagatedTrackDeuteron.getPxPyPzGlo(pDeuteron); + std::array p3B = {pProton[0] + pPion[0] + pDeuteron[0], pProton[1] + pPion[1] + pDeuteron[1], pProton[2] + pPion[2] + pDeuteron[2]}; float r3body = std::hypot(pos[0], pos[1]); if (r3body < 0.5) { @@ -851,8 +819,7 @@ class Decay3BodyBuilderHelper } // H3L DCA Check - const auto& vertexXYZ = fitter3body.getPCACandidatePos(); - auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, t2.sign()); + auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, trackDeuteron.sign()); o2::dataformats::DCA dca; if (!track3B.propagateToDCA({{collision.posX(), collision.posY(), collision.posZ()}, {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}}, fitter3body.getBz(), &dca, 5.) || std::abs(dca.getY()) > svertexerselections.maxDCAXY3Body || std::abs(dca.getZ()) > svertexerselections.maxDCAZ3Body) { @@ -861,16 +828,16 @@ class Decay3BodyBuilderHelper return; } + private: // internal helper to calculate DCA (3D) of a straight line to a given PV analytically float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) { return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); } - }; } // namespace pwglf } // namespace o2 -#endif // PWGLF_UTILS_DECAY3BODYBUILDERHELPER_H_ \ No newline at end of file +#endif // PWGLF_UTILS_DECAY3BODYBUILDERHELPER_H_000,0 From acf65ee7746db7a64e8f046e78c538ececcf63d5 Mon Sep 17 00:00:00 2001 From: creetz16 Date: Fri, 23 May 2025 14:49:49 +0200 Subject: [PATCH 4/7] Add index table, fix magnetic field setting, add mixing of opposite B field d3bodys, fix GetTOFNsigma function call --- PWGLF/DataModel/Vtx3BodyTables.h | 19 + PWGLF/TableProducer/Nuspex/CMakeLists.txt | 7 +- .../Nuspex/decay3bodybuilder.cxx | 296 ++-- .../Nuspex/hypertriton3bodyfinder.cxx | 1197 ----------------- PWGLF/Tasks/Nuspex/CMakeLists.txt | 10 - PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx | 908 ------------- .../Tasks/Nuspex/hypertriton3bodyanalysis.cxx | 797 ----------- PWGLF/Utils/decay3bodyBuilderHelper.h | 7 +- 8 files changed, 160 insertions(+), 3081 deletions(-) delete mode 100644 PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx delete mode 100644 PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx delete mode 100644 PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx diff --git a/PWGLF/DataModel/Vtx3BodyTables.h b/PWGLF/DataModel/Vtx3BodyTables.h index fbccd926806..6526dd6a391 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -26,6 +26,13 @@ namespace o2::aod { namespace vtx3body { +// indices +DECLARE_SOA_INDEX_COLUMN_FULL(TrackPr, trackPr, int, Tracks, "_pr"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(TrackPi, trackPi, int, Tracks, "_pi"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(TrackDe, trackDe, int, Tracks, "_de"); //! +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN(Decay3Body, decay3body); //! + // General 3 body Vtx properties DECLARE_SOA_COLUMN(Mass, mass, float); //! candidate mass (with H3L or Anti-H3L mass hypothesis depending on deuteron charge) DECLARE_SOA_COLUMN(Sign, sign, float); //! candidate sign @@ -177,6 +184,13 @@ DECLARE_SOA_DYNAMIC_COLUMN(TrackDePhi, trackDePhi, //! daughter2 phi [](float pxTrackDe, float pyTrackDe) -> float { return RecoDecay::phi(pxTrackDe, pyTrackDe); }); } // namespace vtx3body +// index table +DECLARE_SOA_TABLE(Decay3BodyIndices, "AOD", "3BodyINDEX", //! + o2::soa::Index<>, + vtx3body::Decay3BodyId, + vtx3body::TrackPrId, vtx3body::TrackPiId, vtx3body::TrackDeId, + vtx3body::CollisionId); + // reconstructed candidate table for analysis DECLARE_SOA_TABLE(Vtx3BodyDatas, "AOD", "VTX3BODYDATA", //! o2::soa::Index<>, @@ -285,6 +299,11 @@ DECLARE_SOA_TABLE(McVtx3BodyDatas, "AOD", "MC3BODYDATA", //! vtx3body::TrackDePt, vtx3body::TrackDeEta, vtx3body::TrackDePhi); + +// Define joins +using Vtx3BodyDatasCovs = soa::Join; +using Vtx3BodyDatasCovsIndexed = soa::Join; + } // namespace o2::aod #endif // PWGLF_DATAMODEL_VTX3BODYTABLES_H_ diff --git a/PWGLF/TableProducer/Nuspex/CMakeLists.txt b/PWGLF/TableProducer/Nuspex/CMakeLists.txt index efe21601521..95238e8aa32 100644 --- a/PWGLF/TableProducer/Nuspex/CMakeLists.txt +++ b/PWGLF/TableProducer/Nuspex/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(decay3bodybuilder SOURCES decay3bodybuilder.cxx - PUBLIC_LINK_LIBRARIES KFParticle::KFParticle O2Physics::AnalysisCore O2::TOFBase O2Physics::EventFilteringUtils O2::DetectorsVertexing + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2::TOFBase O2Physics::EventFilteringUtils O2::DetectorsVertexing COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hyhefour-builder @@ -29,11 +29,6 @@ o2physics_add_dpl_workflow(lnn-reco-task PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(hypertriton3bodyfinder - SOURCES hypertriton3bodyfinder.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(nucleustreecreator SOURCES LFTreeCreatorNuclei.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index b81ce4eaa30..b6ccb0ffa95 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -70,6 +70,7 @@ using namespace o2::framework::expressions; static constexpr int nParameters = 1; static const std::vector tableNames{ + "Decay3BodyIndices", "Vtx3BodyDatas", "Vtx3BodyCovs", "McVtx3BodyDatas"}; @@ -78,6 +79,7 @@ static constexpr int nTablesConst = 5; static const std::vector parameterNames{"enable"}; static const int defaultParameters[nTablesConst][nParameters]{ + {0}, // Decay3BodyIndices {0}, // Vtx3BodyDatas {0}, // Vtx3BodyCovs {0} // McVtx3BodyDatas @@ -95,12 +97,14 @@ struct decay3bodyBuilder { o2::pwglf::decay3bodyBuilderHelper helper; // table index : match order above - enum tableIndex { kVtx3BodyDatas = 0, + enum tableIndex { kDecay3BodyIndices = 0, + kVtx3BodyDatas, kVtx3BodyCovs, kMcVtx3BodyDatas, nTables }; struct : ProducesGroup { + Produces decay3bodyindices; Produces vtx3bodydatas; Produces vtx3bodycovs; Produces mcvtx3bodydatas; @@ -138,7 +142,6 @@ struct decay3bodyBuilder { struct : ConfigurableGroup { std::string prefix = "decay3bodyBuilderOpts"; // building options - Configurable isEventMixing{"isEventMixing", false, "Use event mixing"}; Configurable useKFParticle{"useKFParticle", false, "Use KFParticle for decay3body building"}; Configurable kfSetTopologicalConstraint{"kfSetTopologicalConstraint", false, "Set topological vertex constraint in case of KFParticle reconstruction"}; Configurable useSelections{"useSelections", true, "Apply selections during decay3body building"}; @@ -242,18 +245,17 @@ struct decay3bodyBuilder { Service ccdb; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; std::unordered_map ccdbCache; // Maps runNumber -> d_bz - std::unordered_map> grpMagCache; // Maps runNumber -> grpmap o2::base::MatLayerCylSet* lut = nullptr; // histogram registry HistogramRegistry registry{"Registry", {}, OutputObjHandlingPolicy::AnalysisObject}; // bachelor TOF PID - o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init based on the hypothesis + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init based on the hypothesis + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPIDLabeled; // to be updated in Init based on the hypothesis o2::pid::tof::TOFResoParamsV2 mRespParamsV2; // 3body mixing - bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc using Binning3BodyKF = ColumnBinningPolicy; using Binning3BodyDCAfitter = ColumnBinningPolicy; @@ -301,6 +303,7 @@ struct decay3bodyBuilder { // set bachelor PID bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + bachelorTOFPIDLabeled.SetPidType(o2::track::PID::Deuteron); // set decay3body parameters in the helper helper.decay3bodyselections.maxEtaDaughters = decay3bodyBuilderOpts.maxEtaDaughters; @@ -469,10 +472,6 @@ struct decay3bodyBuilder { registry.add("EM/hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}); registry.add("EM/hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {mixingOpts.bins3BodyPosZ}); } - - if (doprocessRealDataReduced == true || doprocessRealDataReduced3bodyMixing == true) { - doUpdateGRPMagField = true; - } } template @@ -518,7 +517,6 @@ struct decay3bodyBuilder { LOG(info) << "Loading material look-up table for timestamp: " << timestamp; lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); o2::base::Propagator::Instance()->setMatLUT(lut); - helper.lut = lut; } // mark run as configured @@ -583,26 +581,19 @@ struct decay3bodyBuilder { } bachelorTOFPID.SetParams(mRespParamsV2); + bachelorTOFPIDLabeled.SetParams(mRespParamsV2); return true; } - void initCCDBfromRunNumber(int runNumber) + float getMagFieldFromRunNumber(int runNumber) { - // set magnetic field only when run number changes - if (mRunNumber == runNumber) { - LOG(debug) << "CCDB initialized for run " << mRunNumber; - return; - } - mRunNumber = runNumber; // Update the last run number - + float magField; // Check if the CCDB data for this run is already cached if (ccdbCache.find(runNumber) != ccdbCache.end()) { LOG(debug) << "CCDB data already cached for run " << runNumber; - d_bz = ccdbCache[runNumber]; - if (doUpdateGRPMagField == true) { - o2::base::Propagator::initFieldFromGRP(grpMagCache[runNumber].get()); - } + magField = ccdbCache[runNumber]; + // if not, retrieve it from CCDB } else { std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(ccdbConfigurations.grpmagPath, runNumber)); if (!grpmag) { @@ -610,43 +601,40 @@ struct decay3bodyBuilder { } o2::base::Propagator::initFieldFromGRP(grpmag.get()); // Fetch magnetic field from ccdb for current collision - d_bz = o2::base::Propagator::Instance()->getNominalBz(); + magField = o2::base::Propagator::Instance()->getNominalBz(); LOG(info) << "Retrieved GRP for run number " << runNumber << " with magnetic field of " << d_bz << " kZG"; - ccdbCache[runNumber] = d_bz; - grpMagCache[runNumber] = grpmag; + // cache magnetic field info + ccdbCache[runNumber] = magField; + } + return magField; + } + + void initFittersWithMagField(int runNumber, float magField) + { + // set magnetic field only when run number changes + if (mRunNumber == runNumber) { + LOG(debug) << "CCDB initialized for run " << mRunNumber; + return; } + mRunNumber = runNumber; // Update the last run number + + // update propagator + o2::base::Propagator::Instance()->setNominalBz(magField); // Set magnetic field for KF vertexing /// TODO: KF field has to be set in the helper class where KF is used!! --> really? #ifdef HomogeneousField - KFParticle::SetField(d_bz); + KFParticle::SetField(magField); #endif // Set field for DCAfitter - helper.fitterV0.setBz(d_bz); - helper.fitter3body.setBz(d_bz); + helper.fitterV0.setBz(magField); + helper.fitter3body.setBz(magField); if (useMatCorrType == 2) { - // setMatLUT only after magfield has been initalized + // setMatLUT only after magfield has been initalized (setMatLUT has implicit and problematic init field call if not) o2::base::Propagator::Instance()->setMatLUT(lut); } - - // cache magnetic field info - ccdbCache[runNumber] = d_bz; - } - - // ______________________________________________________________ - // function to calculate correct TOF nSigma for deuteron track - template - double getTOFnSigma(TCollision const& collision, TTrack const& track) - { - // TOF PID of deuteron - double tofNsigmaDeuteron = -999; - if (track.has_collision() && track.hasTOF()) { - auto originalcol = track.template collision_as(); - tofNsigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); - } - return tofNsigmaDeuteron; } // ______________________________________________________________ @@ -736,7 +724,7 @@ struct decay3bodyBuilder { // initialise CCDB from run number saved in reduced collisions table when running over reduced data if constexpr (!soa::is_table) { // only do if running over reduced data (otherwise CCDB is initialised in process function) if (collision.runNumber() != lastRunNumber) { - initCCDBfromRunNumber(collision.runNumber()); + initFittersWithMagField(collision.runNumber(), getMagFieldFromRunNumber(collision.runNumber())); lastRunNumber = collision.runNumber(); // Update the last run number LOG(debug) << "CCDB initialized for run " << lastRunNumber; } @@ -765,10 +753,14 @@ struct decay3bodyBuilder { // get deuteron TOF PID float tofNSigmaDeuteron; - if constexpr (!soa::is_table) { + if constexpr (!soa::is_table) { // running over derived data tofNSigmaDeuteron = trackDeuteron.tofNSigmaDe(); - } else if constexpr (soa::is_table) { - tofNSigmaDeuteron = getTOFnSigma(collision, trackDeuteron); + } else if constexpr (soa::is_table) { // running over AO2Ds + if constexpr (soa::is_table) { // running over MC (track table with labels) + tofNSigmaDeuteron = getTOFnSigma(collision, trackDeuteron); + } else { // running over real data + tofNSigmaDeuteron = getTOFnSigma(collision, trackDeuteron); + } } /// build Decay3body candidate @@ -785,7 +777,7 @@ struct decay3bodyBuilder { decay3bodyBuilderOpts.useTPCforPion, decay3bodyBuilderOpts.acceptTPCOnly, decay3bodyBuilderOpts.calculateCovariance, - decay3bodyBuilderOpts.isEventMixing)) { + false /*isEventMixing*/)) { continue; } nDecay3Bodys++; @@ -999,6 +991,20 @@ struct decay3bodyBuilder { auto trackNeg1 = decay3body1.template track1_as(); auto trackDeuteron1 = decay3body1.template track2_as(); + // assign tracks + auto trackProton0 = trackPos0; + auto trackPion0 = trackNeg0; + auto trackProton1 = trackPos1; + auto trackPion1 = trackNeg1; + if (trackDeuteron0.sign() < 0) { + trackProton0 = trackNeg0; + trackPion0 = trackPos0; + } + if (trackDeuteron1.sign() < 0) { + trackProton1 = trackNeg1; + trackPion1 = trackPos1; + } + registry.fill(HIST("h3bodyCombinationCounter"), 0.5); // only combine if from different event @@ -1010,8 +1016,10 @@ struct decay3bodyBuilder { // collision vertex selection auto collision0 = decay3body0.template collision_as(); auto collision1 = decay3body1.template collision_as(); - initCCDBfromRunNumber(collision0.runNumber()); - initCCDBfromRunNumber(collision1.runNumber()); + + // get b_z value for each collision (from CCDB or cache) and cache it for that run number + float magFieldCol0 = getMagFieldFromRunNumber(collision0.runNumber()); + float magFieldCol1 = getMagFieldFromRunNumber(collision1.runNumber()); // only combine if collision similar in VtxZ if (mixingOpts.selectPVPosZ3bodyMixing && std::abs(collision0.posZ() - collision1.posZ()) > mixingOpts.maxDeltaPVPosZ3bodyMixing) { @@ -1019,126 +1027,73 @@ struct decay3bodyBuilder { } registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 2.5); - // selections - if ((trackDeuteron0.sign() > 0 && !(trackDeuteron1.sign() > 0)) || (trackDeuteron0.sign() < 0 && !(trackDeuteron1.sign() < 0)) || trackDeuteron0.globalIndex() == trackDeuteron1.globalIndex()) { // only combine if trackDeuteron1 has correct sign and is not same as trackDeuteron0 - continue; + // Charge selections + // same magnetic fields --> mix matter with matter + if (std::signbit(magFieldCol0) == std::signbit(magFieldCol1)) { + if (trackDeuteron0.sign() != trackDeuteron1.sign()) { + continue; + } } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); - - // assign tracks - auto trackProton0 = trackPos0; - auto trackPion0 = trackNeg0; - auto trackProton1 = trackPos1; - auto trackPion1 = trackNeg1; - if (trackDeuteron0.sign() < 0) { - trackProton0 = trackNeg0; - trackPion0 = trackPos0; + // opposite magnetic fields --> mix matter with anti-matter + if (std::signbit(magFieldCol0) != std::signbit(magFieldCol1)) { + if (trackDeuteron0.sign() == trackDeuteron1.sign()) { + continue; + } } - if (trackDeuteron1.sign() < 0) { - trackProton1 = trackNeg1; - trackPion1 = trackPos1; + + // don't mix 3body with itself + if ((trackDeuteron0.globalIndex() == trackDeuteron1.globalIndex()) || (trackProton0.globalIndex() == trackProton1.globalIndex()) || (trackPion0.globalIndex() == trackPion1.globalIndex())) { + continue; } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); // candidate analysis // mix deuteron if (mixingOpts.mixingType == 0) { - if (helper.buildDecay3BodyCandidate(collision0, trackProton0, trackPion0, trackDeuteron1, - -1 /*decay3bodyIndex*/, - trackDeuteron1.tofNSigmaDe(), - 0 /*trackedClSize*/, - decay3bodyBuilderOpts.useKFParticle, - decay3bodyBuilderOpts.kfSetTopologicalConstraint, - decay3bodyBuilderOpts.useSelections, - decay3bodyBuilderOpts.useTPCforPion, - decay3bodyBuilderOpts.acceptTPCOnly, - decay3bodyBuilderOpts.calculateCovariance, - true /*isEventMixing*/)) { - // fill analysis tables with built candidate - fillAnalysisTables(); - } - if (helper.buildDecay3BodyCandidate(collision0, trackProton1, trackPion1, trackDeuteron0, - -1 /*decay3bodyIndex*/, - trackDeuteron0.tofNSigmaDe(), - 0 /*trackedClSize*/, - decay3bodyBuilderOpts.useKFParticle, - decay3bodyBuilderOpts.kfSetTopologicalConstraint, - decay3bodyBuilderOpts.useSelections, - decay3bodyBuilderOpts.useTPCforPion, - decay3bodyBuilderOpts.acceptTPCOnly, - decay3bodyBuilderOpts.calculateCovariance, - true /*isEventMixing*/)) { - // fill analysis tables with built candidate - fillAnalysisTables(); - } - // mix proton - } else if (mixingOpts.mixingType == 1) { - if (helper.buildDecay3BodyCandidate(collision0, trackProton1, trackPion0, trackDeuteron0, - -1 /*decay3bodyIndex*/, - trackDeuteron0.tofNSigmaDe(), - 0 /*trackedClSize*/, - decay3bodyBuilderOpts.useKFParticle, - decay3bodyBuilderOpts.kfSetTopologicalConstraint, - decay3bodyBuilderOpts.useSelections, - decay3bodyBuilderOpts.useTPCforPion, - decay3bodyBuilderOpts.acceptTPCOnly, - decay3bodyBuilderOpts.calculateCovariance, - true /*isEventMixing*/)) { - // fill analysis tables with built candidate - fillAnalysisTables(); - } - if (helper.buildDecay3BodyCandidate(collision0, trackProton0, trackPion1, trackDeuteron1, - -1 /*decay3bodyIndex*/, - trackDeuteron1.tofNSigmaDe(), - 0 /*trackedClSize*/, - decay3bodyBuilderOpts.useKFParticle, - decay3bodyBuilderOpts.kfSetTopologicalConstraint, - decay3bodyBuilderOpts.useSelections, - decay3bodyBuilderOpts.useTPCforPion, - decay3bodyBuilderOpts.acceptTPCOnly, - decay3bodyBuilderOpts.calculateCovariance, - true /*isEventMixing*/)) { - // fill analysis tables with built candidate - fillAnalysisTables(); - } - // mix pion - } else if (mixingOpts.mixingType == 2) { - if (helper.buildDecay3BodyCandidate(collision0, trackProton0, trackPion1, trackDeuteron0, - -1 /*decay3bodyIndex*/, - trackDeuteron0.tofNSigmaDe(), - 0 /*trackedClSize*/, - decay3bodyBuilderOpts.useKFParticle, - decay3bodyBuilderOpts.kfSetTopologicalConstraint, - decay3bodyBuilderOpts.useSelections, - decay3bodyBuilderOpts.useTPCforPion, - decay3bodyBuilderOpts.acceptTPCOnly, - decay3bodyBuilderOpts.calculateCovariance, - true /*isEventMixing*/)) { - // fill analysis tables with built candidate - fillAnalysisTables(); - } - if (helper.buildDecay3BodyCandidate(collision0, trackProton1, trackPion0, trackDeuteron1, - -1 /*decay3bodyIndex*/, - trackDeuteron1.tofNSigmaDe(), - 0 /*trackedClSize*/, - decay3bodyBuilderOpts.useKFParticle, - decay3bodyBuilderOpts.kfSetTopologicalConstraint, - decay3bodyBuilderOpts.useSelections, - decay3bodyBuilderOpts.useTPCforPion, - decay3bodyBuilderOpts.acceptTPCOnly, - decay3bodyBuilderOpts.calculateCovariance, - true /*isEventMixing*/)) { - // fill analysis tables with built candidate - fillAnalysisTables(); - } + doMixing(collision0, trackProton0, trackPion0, trackDeuteron1, magFieldCol0); + doMixing(collision1, trackProton1, trackPion1, trackDeuteron0, magFieldCol1); + } + // mix proton + if (mixingOpts.mixingType == 1) { + doMixing(collision0, trackProton1, trackPion0, trackDeuteron0, magFieldCol0); + doMixing(collision1, trackProton0, trackPion1, trackDeuteron1, magFieldCol1); + } + // mix pion + if (mixingOpts.mixingType == 2) { + doMixing(collision0, trackProton0, trackPion1, trackDeuteron0, magFieldCol0); + doMixing(collision1, trackProton1, trackPion0, trackDeuteron1, magFieldCol1); } } // end decay3body combinations loop } + // ______________________________________________________________ + // function to calculate correct TOF nSigma for deuteron track + template + double getTOFnSigma(TCollision const& collision, TTrack const& track) + { + // TOF PID of deuteron + if (track.has_collision() && track.hasTOF()) { + auto originalcol = track.template collision_as(); + if constexpr (isMC) { + return bachelorTOFPIDLabeled.GetTOFNSigma(track, originalcol, collision); + } else { + return bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); + } + } + return -999; + } + // ______________________________________________________________ // function to fill analysis tables void fillAnalysisTables() { // generate analysis tables + if (mEnabledTables[kDecay3BodyIndices]) { + products.decay3bodyindices(helper.decay3body.decay3bodyID, + helper.decay3body.protonID, helper.decay3body.pionID, helper.decay3body.deuteronID, + helper.decay3body.collisionID); + registry.fill(HIST("hTableBuildingStatistics"), kDecay3BodyIndices); + } if (mEnabledTables[kVtx3BodyDatas]) { products.vtx3bodydatas(helper.decay3body.sign, helper.decay3body.mass, helper.decay3body.massV0, @@ -1202,6 +1157,32 @@ struct decay3bodyBuilder { } } + // ______________________________________________________________ + // function to build mixed 3body candidate from selected tracks + template + void doMixing(TCollision const& collision, TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackDeuteron, float magField) + { + // set vertexers and propagator with correct mag field of this collision (only if run number changed compared to previous candidate build) + initFittersWithMagField(collision.runNumber(), magField); + if (helper.buildDecay3BodyCandidate(collision, trackProton, trackPion, trackDeuteron, + -1 /*decay3bodyIndex*/, + trackDeuteron.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.calculateCovariance, + true /*isEventMixing*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + return; + } else { + return; + } + } + // ______________________________________________________________ // function to check if a reconstructed mother is a true H3L/Anti-H3L (returns -1 if not) template @@ -1262,6 +1243,7 @@ struct decay3bodyBuilder { mcInfo.daughterPrPdgCode = -1, mcInfo.daughterPiPdgCode = -1, mcInfo.daughterDePdgCode = -1; mcInfo.isDeuteronPrimary = false; mcInfo.survivedEventSel = false; + return; } // ______________________________________________________________ diff --git a/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx b/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx deleted file mode 100644 index 40019d82533..00000000000 --- a/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx +++ /dev/null @@ -1,1197 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// This 3-body method is not recommended due to high cost of computing resources -// author: yuanzhe.wang@cern.ch - -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "DCAFitter/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/Vtx3BodyTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "EventFiltering/filterTables.h" - -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -using FullTracksExtIU = soa::Join; -using MCLabeledTracksIU = soa::Join; - -template -bool is3bodyDecayedH3L(TMCParticle const& particle) -{ - if (particle.pdgCode() != 1010010030 && particle.pdgCode() != -1010010030) { - return false; - } - bool haveProton = false, havePionPlus = false, haveDeuteron = false; - bool haveAntiProton = false, havePionMinus = false, haveAntiDeuteron = false; - for (auto& mcparticleDaughter : particle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == 2212) - haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) - havePionPlus = true; - if (mcparticleDaughter.pdgCode() == -211) - havePionMinus = true; - if (mcparticleDaughter.pdgCode() == 1000010020) - haveDeuteron = true; - if (mcparticleDaughter.pdgCode() == -1000010020) - haveAntiDeuteron = true; - } - if (haveProton && havePionMinus && haveDeuteron && particle.pdgCode() == 1010010030) { - return true; - } else if (haveAntiProton && havePionPlus && haveAntiDeuteron && particle.pdgCode() == -1010010030) { - return true; - } - return false; -} - -namespace o2::aod -{ -namespace v0goodpostrack -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, Tracks, "_GoodTrack"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace v0goodpostrack -DECLARE_SOA_TABLE(V0GoodPosTracks, "AOD", "V0GOODPOSTRACKS", o2::soa::Index<>, v0goodpostrack::GoodTrackId, v0goodpostrack::CollisionId); -namespace v0goodnegtrack -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, Tracks, "_GoodTrack"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace v0goodnegtrack -DECLARE_SOA_TABLE(V0GoodNegTracks, "AOD", "V0GOODNEGTRACKS", o2::soa::Index<>, v0goodnegtrack::GoodTrackId, v0goodnegtrack::CollisionId); -namespace v0goodtrack -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, Tracks, "_GoodTrack"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace v0goodtrack -DECLARE_SOA_TABLE(V0GoodTracks, "AOD", "V0GOODTRACKS", o2::soa::Index<>, v0goodtrack::GoodTrackId, v0goodtrack::CollisionId); -} // namespace o2::aod - -struct trackprefilter { - HistogramRegistry registry{ - "registry", - { - {"hCrossedRows", "hCrossedRows", {HistType::kTH1F, {{50, 0.0f, 200.0f}}}}, - {"hGoodTrackCount", "hGoodTrackCount", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - {"hGoodPosTrackCount", "hGoodPosTrackCount", {HistType::kTH1F, {{1, 0.0f, 1.0f}}}}, - {"hGoodNegTrackCount", "hGoodNegTrackCount", {HistType::kTH1F, {{1, 0.0f, 1.0f}}}}, - {"h3bodyCounter", "h3bodyCounter", {HistType::kTH1F, {{6, 0.0f, 6.0f}}}}, - }, - }; - - // change the dca cut for helium3 - Configurable mintpcNCls{"mintpcNCls", 70, "min tpc Nclusters"}; - Configurable tpcrefit{"tpcrefit", 0, "demand TPC refit"}; - - Produces v0GoodPosTracks; - Produces v0GoodNegTracks; - Produces v0GoodTracks; - - // Fix: Add PID and pt cuts to tracks - void processDefault(aod::Collision const& /*collision*/, - FullTracksExtIU const& tracks) - { - for (auto& t0 : tracks) { - registry.fill(HIST("hGoodTrackCount"), 0.5); - registry.fill(HIST("hCrossedRows"), t0.tpcNClsCrossedRows()); - if (tpcrefit) { - if (!(t0.trackType() & o2::aod::track::TPCrefit)) { - continue; // TPC refit - } - } - registry.fill(HIST("hGoodTrackCount"), 1.5); - if (t0.tpcNClsFound() < mintpcNCls) { - continue; - } - registry.fill(HIST("hGoodTrackCount"), 2.5); - if (t0.signed1Pt() > 0.0f) { - v0GoodPosTracks(t0.globalIndex(), t0.collisionId()); - registry.fill(HIST("hGoodPosTrackCount"), 0.5); - registry.fill(HIST("hGoodTrackCount"), 3.5); - } - if (t0.signed1Pt() < 0.0f) { - v0GoodNegTracks(t0.globalIndex(), t0.collisionId()); - registry.fill(HIST("hGoodNegTrackCount"), 0.5); - registry.fill(HIST("hGoodTrackCount"), 3.5); - } - v0GoodTracks(t0.globalIndex(), t0.collisionId()); - } - } - PROCESS_SWITCH(trackprefilter, processDefault, "Default process function", true); - - // process function for MC d3body check - // void processCheck(aod::Collision const& collision, aod::Decay3Bodys const& decay3bodys, - void processCheck(aod::Decay3Bodys const& decay3bodys, - MCLabeledTracksIU const& /*tracks*/, aod::McParticles const& /*particlesMC*/) - { - for (auto& d3body : decay3bodys) { - registry.fill(HIST("h3bodyCounter"), 0.5); - auto lTrack0 = d3body.track0_as(); - auto lTrack1 = d3body.track1_as(); - auto lTrack2 = d3body.track2_as(); - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 1.5); - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 2.5); - - int lPDG = -1; - bool is3bodyDecay = false; - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lPDG = lMother1.pdgCode(); - if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { - is3bodyDecay = true; // vtxs with the same mother - } - if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { - is3bodyDecay = true; // vtxs with the same mother - } - } - } - } - } // end association check - - if (!is3bodyDecay || std::abs(lPDG) != 1010010030) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 3.5); - if (lTrack0.collisionId() != lTrack1.collisionId() || lTrack0.collisionId() != lTrack2.collisionId()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 4.5); - - if (lTrack0.collisionId() != d3body.collisionId()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 5.5); - - // LOG(info) << "; Track0ID: " << lTrack0.globalIndex() << "; Track1ID:" << lTrack1.globalIndex() << "; Track2ID:" << lTrack2.globalIndex(); - v0GoodPosTracks(lTrack0.globalIndex(), lTrack0.collisionId()); - v0GoodNegTracks(lTrack1.globalIndex(), lTrack1.collisionId()); - v0GoodTracks(lTrack2.globalIndex(), lTrack2.collisionId()); - } - } - PROCESS_SWITCH(trackprefilter, processCheck, "Check specific paired tracks", false); -}; - -struct hypertriton3bodyFinder { - - Produces vtx3bodydata; - Service ccdb; - - // Configurables - Configurable UseCFFilter{"UseCFFilter", true, "Reject event without CF LD trigger"}; - Configurable RejectBkgInMC{"RejectBkgInMC", false, "Reject fake 3-body pairs in MC check"}; - - Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - - // Selection criteria - Configurable minRToMeanVertex = {"minRToMeanVertex", 0.5, ""}; ///< min radial distance of V0 from beam line (mean vertex) - // Configurable causalityRTolerance = {"causalityRTolerance", 1., ""}; ///< V0 radius cannot exceed its contributors minR by more than this value - Configurable maxV0ToProngsRDiff = {"maxV0ToProngsRDiff", 50., ""}; ///< V0 radius cannot be lower than this ammount wrt minR of contributors - Configurable minPtV0 = {"minPtV0", 0.5, ""}; ///< v0 minimum pT - Configurable maxTglV0 = {"maxTglV0", 2., ""}; ///< maximum tgLambda of V0 - Configurable maxDCAXY2ToMeanVertex3bodyV0 = {"maxDCAXY2ToMeanVertex3bodyV0", 2 * 2, ""}; - Configurable minCosPAXYMeanVertex3bodyV0 = {"minCosPAXYMeanVertex3bodyV0", 0.9, ""}; ///< min cos of PA to beam line (mean vertex) in tr. plane for 3body V0 cand. - Configurable minCosPA3bodyV0 = {"minCosPA3bodyV0", 0.8, ""}; // min cos of PA to PV for 3body V0 - - // for 3 body reconstructed Vertex - Configurable minbachPt = {"minbachPt", 0.6, ""}; ///< Minimum bachelor Pt - Configurable maxRDiff3bodyV0 = {"maxRDiff3bodyV0", 3, ""}; ///< Maximum difference between V0 and 3body radii - Configurable minPt3Body = {"minPt3Body", 0.01, ""}; // minimum pT of 3body Vertex - Configurable maxTgl3Body = {"maxTgl3Body", 2, ""}; // maximum tgLambda of 3body Vertex - Configurable minCosPA3body = {"minCosPA3body", 0.8, ""}; // min cos of PA to PV for 3body Vertex - - // for DCA - Configurable dcavtxdau{"dcavtxdau", 2.0, "DCA Vtx Daughters"}; - Configurable d_UseH3LDCACut{"d_UseH3LDCACut", true, "Use Cuts for H3L DCA to PV"}; - Configurable maxDCAXY3Body{"maxDCAXY3Body", 0.5, "DCAXY H3L to PV"}; // max DCA of 3 body decay to PV in XY - Configurable maxDCAZ3Body{"maxDCAZ3Body", 1.0, "DCAZ H3L to PV"}; // max DCA of 3 body decay to PV in Z - - Configurable useMatCorrType{"useMatCorrType", 2, "0: none, 1: TGeo, 2: LUT"}; - // CCDB options - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - - Preslice perCollisionGoodPosTracks = o2::aod::v0goodpostrack::collisionId; - Preslice perCollisionGoodNegTracks = o2::aod::v0goodnegtrack::collisionId; - Preslice perCollisionGoodTracks = o2::aod::v0goodtrack::collisionId; - Preslice perCollisionV0s = o2::aod::v0::collisionId; - Preslice perCollisionV0Datas = o2::aod::v0data::collisionId; - - // Helper struct to pass V0 information - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - {"hDauTrackCounter", "hDauTrackCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hV0Counter", "hV0Counter", {HistType::kTH1F, {{8, -0.5f, 7.5f}}}}, - {"hTrueV0Counter", "hTrueV0Counter", {HistType::kTH1F, {{8, -0.5f, 7.5f}}}}, - {"hVtx3BodyCounter", "hVtx3BodyCounter", {HistType::kTH1F, {{9, -0.5f, 8.5f}}}}, - {"hTrueVtx3BodyCounter", "hTrueVtx3BodyCounter", {HistType::kTH1F, {{9, -0.5f, 8.5f}}}}, - {"hVirtLambaCounter", "hVirtualLambaCounter", {HistType::kTH1F, {{6, -0.5f, 5.5f}}}}, - {"hCFFilteredVirtLambaCounter", "hCFFilteredVirtLambaCounter", {HistType::kTH1F, {{6, -0.5f, 5.5f}}}}, - }, - }; - - //------------------------------------------------------------------ - // Fill stats histograms - enum v0step { kV0All = 0, - kV0hasSV, - kV0Radius, - kV0Pt, - kV0TgLamda, - kV0InvMass, - kV0DcaXY, - kV0CosPA, - kNV0Steps }; - enum vtxstep { kVtxAll = 0, - kVtxbachPt, - kVtxhasSV, - kVtxRadius, - kVtxPt, - kVtxTgLamda, - kVtxCosPA, - kVtxDcaDau, - kVtxDcaH3L, - kNVtxSteps }; - - // Helper struct to do bookkeeping of building parameters - struct { - std::array v0stats; - std::array truev0stats; - std::array vtxstats; - std::array truevtxstats; - std::array virtLambdastats; - } statisticsRegistry; - - void resetHistos() - { - for (Int_t ii = 0; ii < kNV0Steps; ii++) { - statisticsRegistry.v0stats[ii] = 0; - statisticsRegistry.truev0stats[ii] = 0; - } - for (Int_t ii = 0; ii < kNVtxSteps; ii++) { - statisticsRegistry.vtxstats[ii] = 0; - statisticsRegistry.truevtxstats[ii] = 0; - } - for (Int_t ii = 0; ii < 12; ii++) { - statisticsRegistry.virtLambdastats[ii] = 0; - } - } - - void fillHistos() - { - for (Int_t ii = 0; ii < kNV0Steps; ii++) { - registry.fill(HIST("hV0Counter"), ii, statisticsRegistry.v0stats[ii]); - registry.fill(HIST("hTrueV0Counter"), ii, statisticsRegistry.truev0stats[ii]); - } - for (Int_t ii = 0; ii < kNVtxSteps; ii++) { - registry.fill(HIST("hVtx3BodyCounter"), ii, statisticsRegistry.vtxstats[ii]); - registry.fill(HIST("hTrueVtx3BodyCounter"), ii, statisticsRegistry.truevtxstats[ii]); - } - for (Int_t ii = 0; ii < 3; ii++) { - registry.fill(HIST("hVirtLambaCounter"), ii, statisticsRegistry.virtLambdastats[ii]); - registry.fill(HIST("hVirtLambaCounter"), ii + 3, statisticsRegistry.virtLambdastats[ii + 3]); - registry.fill(HIST("hCFFilteredVirtLambaCounter"), ii, statisticsRegistry.virtLambdastats[ii + 6]); - registry.fill(HIST("hCFFilteredVirtLambaCounter"), ii + 3, statisticsRegistry.virtLambdastats[ii + 9]); - } - } - - // v0, vtx, and virtual Lambda statiscs - void FillV0Counter(int kn, bool istrue = false) - { - statisticsRegistry.v0stats[kn]++; - if (istrue) { - statisticsRegistry.truev0stats[kn]++; - } - } - void FillVtxCounter(int kn, bool istrue = false) - { - statisticsRegistry.vtxstats[kn]++; - if (istrue) { - statisticsRegistry.truevtxstats[kn]++; - } - } - //------------------------------------------------------------------ - - int mRunNumber; - float d_bz; - float maxSnp; // max sine phi for propagation - float maxStep; // max step size (cm) for propagation - o2::base::MatLayerCylSet* lut = nullptr; - o2::vertexing::DCAFitterN<2> fitter; - o2::vertexing::DCAFitterN<3> fitter3body; - - void init(InitContext&) - { - resetHistos(); - mRunNumber = 0; - d_bz = 0; - maxSnp = 0.85f; // could be changed later - maxStep = 2.00f; // could be changed later - - TString DauCounterbinLabel[3] = {"Proton", "Pion", "Deuteron"}; - TString V0CounterbinLabel[8] = {"Total", "hasSV", "V0R", "V0Pt", "TgLambda", "V0Mass", "DcaXY", "CosPA"}; - TString VtxCounterbinLabel[9] = {"Total", "bachPt", "hasSV", "VtxR", "VtxPt", "TgLambda", "CosPA", "DcaDau", "DcaH3L"}; - for (int i{0}; i < 3; i++) { - registry.get(HIST("hDauTrackCounter"))->GetXaxis()->SetBinLabel(i + 1, DauCounterbinLabel[i]); - } - for (int i{0}; i < kNV0Steps; i++) { - registry.get(HIST("hV0Counter"))->GetXaxis()->SetBinLabel(i + 1, V0CounterbinLabel[i]); - registry.get(HIST("hTrueV0Counter"))->GetXaxis()->SetBinLabel(i + 1, V0CounterbinLabel[i]); - } - for (int i{0}; i < kNVtxSteps; i++) { - registry.get(HIST("hVtx3BodyCounter"))->GetXaxis()->SetBinLabel(i + 1, VtxCounterbinLabel[i]); - registry.get(HIST("hTrueVtx3BodyCounter"))->GetXaxis()->SetBinLabel(i + 1, VtxCounterbinLabel[i]); - } - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - // Set 2-body fitter and 3-body fitter3body - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); //->maxRIni3body - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(d_UseAbsDCA); - fitter3body.setPropagateToPCA(true); - fitter3body.setMaxR(200.); //->maxRIni3body - fitter3body.setMinParamChange(1e-3); - fitter3body.setMinRelChi2Change(0.9); - fitter3body.setMaxDZIni(1e9); - fitter3body.setMaxChi2(1e9); - fitter3body.setUseAbsDCA(d_UseAbsDCA); - - // Material correction in the DCA fitter - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - if (useMatCorrType == 1) { - LOGF(info, "TGeo correction requested, loading geometry"); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); - } - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - } - if (useMatCorrType == 2) { - LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - } - fitter.setMatCorrType(matCorr); - fitter3body.setMatCorrType(matCorr); - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - - // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { - d_bz = d_bz_input; - fitter.setBz(d_bz); - fitter3body.setBz(d_bz); - o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = bc.runNumber(); - return; - } - - auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - o2::parameters::GRPMagField* grpmag = 0x0; - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } - mRunNumber = bc.runNumber(); - // Set magnetic field value once known - fitter.setBz(d_bz); - fitter3body.setBz(d_bz); - - if (useMatCorrType == 2) { - // setMatLUT only after magfield has been initalized - // (setMatLUT has implicit and problematic init field call if not) - o2::base::Propagator::Instance()->setMatLUT(lut); - } - } - - //------------------------------------------------------------------ - // Check the info of good tracks - template - void CheckGoodTracks(TGoodTrackTable const& dGoodtracks, aod::McParticles const& /*particlesMC*/) - { - for (auto& goodtrackid : dGoodtracks) { - auto goodtrack = goodtrackid.template goodTrack_as(); - if (!goodtrack.has_mcParticle()) { - continue; - } - auto mcgoodtrack = goodtrack.template mcParticle_as(); - if (!mcgoodtrack.has_mothers()) { - continue; - } - bool flag_H3L = false; - for (auto& mothertrack : mcgoodtrack.template mothers_as()) { - if (is3bodyDecayedH3L(mothertrack)) { - flag_H3L = true; - } - } - if (flag_H3L && std::abs(mcgoodtrack.pdgCode()) == 2212) { - registry.fill(HIST("hDauTrackCounter"), 0.5); - } - if (flag_H3L && std::abs(mcgoodtrack.pdgCode()) == 211) { - registry.fill(HIST("hDauTrackCounter"), 1.5); - } - if (flag_H3L && std::abs(mcgoodtrack.pdgCode()) == 1000010020) { - registry.fill(HIST("hDauTrackCounter"), 2.5); - } - } - } - - o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; - //------------------------------------------------------------------ - // Virtual Lambda V0 finder - template - bool DecayV0Finder(TCollisionTable const& dCollision, TTrackTable const& dPtrack, TTrackTable const& dNtrack, float& rv0, bool isTrue3bodyV0 = false) - { - if (dPtrack.collisionId() != dNtrack.collisionId()) { - return false; - } - FillV0Counter(kV0All, isTrue3bodyV0); - if (!isTrue3bodyV0 && RejectBkgInMC) { - return false; - } - - auto Track0 = getTrackParCov(dPtrack); - auto Track1 = getTrackParCov(dNtrack); - int nCand = fitter.process(Track0, Track1); - if (nCand == 0) { - return false; - } - FillV0Counter(kV0hasSV, isTrue3bodyV0); - - // validate V0 radial position - // First check closeness to the beam-line as same as SVertexer - const auto& v0XYZ = fitter.getPCACandidate(); - float dxv0 = v0XYZ[0] - mMeanVertex.getX(), dyv0 = v0XYZ[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; - // float rv0 = std::sqrt(r2v0); - rv0 = std::sqrt(r2v0); - if (rv0 < minRToMeanVertex) { - return false; - } - FillV0Counter(kV0Radius, isTrue3bodyV0); - - // Not involved: Get minR with same way in SVertexer - // float drv0P = rv0 - Track0minR, drv0N = rv0 - Track1minR; - - // check: if the process function finish the propagation - if (!fitter.isPropagateTracksToVertexDone() && !fitter.propagateTracksToVertex()) { - return false; - } - - auto& trPProp = fitter.getTrack(0); - auto& trNProp = fitter.getTrack(1); - std::array pP, pN; - trPProp.getPxPyPzGlo(pP); - trNProp.getPxPyPzGlo(pN); - // estimate DCA of neutral V0 track to beamline: straight line with parametric equation - // x = X0 + pV0[0]*t, y = Y0 + pV0[1]*t reaches DCA to beamline (Xv, Yv) at - // t = -[ (x0-Xv)*pV0[0] + (y0-Yv)*pV0[1]) ] / ( pT(pV0)^2 ) - // Similar equation for 3D distance involving pV0[2] - std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; - float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; - float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); - if (ptV0 < minPtV0) { // pt cut - return false; - } - FillV0Counter(kV0Pt, isTrue3bodyV0); - - if (pV0[2] / ptV0 > maxTglV0) { // tgLambda cut - return false; - } - FillV0Counter(kV0TgLamda, isTrue3bodyV0); - - // apply mass selections - float massV0LambdaHyp = RecoDecay::m(array{array{pP[0], pP[1], pP[2]}, array{pN[0], pN[1], pN[2]}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - float massV0AntiLambdaHyp = RecoDecay::m(array{array{pP[0], pP[1], pP[2]}, array{pN[0], pN[1], pN[2]}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); - float massMargin = 20 * (0.001 * (1. + 0.5 * ptV0)) + 0.07; - if (massV0LambdaHyp - o2::constants::physics::MassLambda > massMargin && massV0AntiLambdaHyp - o2::constants::physics::MassLambda > massMargin) { - return false; - } - FillV0Counter(kV0InvMass, isTrue3bodyV0); - - float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; - float cosPAXY = prodXYv0 / std::sqrt(r2v0 * pt2V0); - if (dca2 > maxDCAXY2ToMeanVertex3bodyV0) { - return false; - } - FillV0Counter(kV0DcaXY, isTrue3bodyV0); - - if (cosPAXY < minCosPAXYMeanVertex3bodyV0) { - return false; - } - float dx = v0XYZ[0] - dCollision.posX(), dy = v0XYZ[1] - dCollision.posY(), dz = v0XYZ[2] - dCollision.posZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; - float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); - if (cosPA < minCosPA3bodyV0) { - return false; - } - FillV0Counter(kV0CosPA, isTrue3bodyV0); - return true; - } - //------------------------------------------------------------------ - // 3body decay vertex finder - template - void Decay3bodyFinder(TCollisionTable const& dCollision, TTrackTable const& dPtrack, TTrackTable const& dNtrack, TTrackTable const& dBachtrack, float const& rv0, bool isTrue3bodyVtx = false) - { - if (dPtrack.collisionId() != dBachtrack.collisionId()) { - return; - } - if (dPtrack.globalIndex() == dBachtrack.globalIndex()) { - return; // skip the track used by V0 - } - FillVtxCounter(kVtxAll, isTrue3bodyVtx); - if (!isTrue3bodyVtx && RejectBkgInMC) { - return; - } - - auto track0 = getTrackParCov(dPtrack); - auto track1 = getTrackParCov(dNtrack); - auto bach = getTrackParCov(dBachtrack); - - if (bach.getPt() < minbachPt) { - return; - } - FillVtxCounter(kVtxbachPt, isTrue3bodyVtx); - - int n3bodyVtx = fitter3body.process(track0, track1, bach); - if (n3bodyVtx == 0) { // discard this pair - return; - } - FillVtxCounter(kVtxhasSV, isTrue3bodyVtx); - - const auto& vertexXYZ = fitter3body.getPCACandidatePos(); - // make sure the cascade radius is smaller than that of the vertex - float dxc = vertexXYZ[0] - dCollision.posX(), dyc = vertexXYZ[1] - dCollision.posY(), dzc = vertexXYZ[2] - dCollision.posZ(), r2vertex = dxc * dxc + dyc * dyc; - float rvertex = std::sqrt(r2vertex); - if (std::abs(rv0 - rvertex) > maxRDiff3bodyV0 || rvertex < minRToMeanVertex) { - return; - } - FillVtxCounter(kVtxRadius, isTrue3bodyVtx); - - // Not involved: bach.minR - rveretx check - - // check: if the process function finish the propagation - if (!fitter3body.isPropagateTracksToVertexDone() && !fitter3body.propagateTracksToVertex()) { - return; - } - - auto& tr0 = fitter3body.getTrack(0); - auto& tr1 = fitter3body.getTrack(1); - auto& tr2 = fitter3body.getTrack(2); - std::array p0, p1, p2; - tr0.getPxPyPzGlo(p0); - tr1.getPxPyPzGlo(p1); - tr2.getPxPyPzGlo(p2); - std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; - - float pt2 = p3B[0] * p3B[0] + p3B[1] * p3B[1], p2candidate = pt2 + p3B[2] * p3B[2]; - float pt = std::sqrt(pt2); - if (pt < minPt3Body) { // pt cut - return; - } - FillVtxCounter(kVtxPt, isTrue3bodyVtx); - - if (p3B[2] / pt > maxTgl3Body) { // tgLambda cut - return; - } - FillVtxCounter(kVtxTgLamda, isTrue3bodyVtx); - - float cosPA = (p3B[0] * dxc + p3B[1] * dyc + p3B[2] * dzc) / std::sqrt(p2candidate * (r2vertex + dzc * dzc)); - if (cosPA < minCosPA3body) { - return; - } - FillVtxCounter(kVtxCosPA, isTrue3bodyVtx); - - if (fitter3body.getChi2AtPCACandidate() > dcavtxdau) { - return; - } - FillVtxCounter(kVtxDcaDau, isTrue3bodyVtx); - - // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; - - auto Track0Par = getTrackPar(dPtrack); - o2::base::Propagator::Instance()->propagateToDCABxByBz({dCollision.posX(), dCollision.posY(), dCollision.posZ()}, Track0Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track0dcaXY = dcaInfo[0]; - auto Track0dca = std::sqrt(Track0dcaXY * Track0dcaXY + dcaInfo[1] * dcaInfo[1]); - - auto Track1Par = getTrackPar(dNtrack); - o2::base::Propagator::Instance()->propagateToDCABxByBz({dCollision.posX(), dCollision.posY(), dCollision.posZ()}, Track1Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track1dcaXY = dcaInfo[0]; - auto Track1dca = std::sqrt(Track1dcaXY * Track1dcaXY + dcaInfo[1] * dcaInfo[1]); - - auto Track2Par = getTrackPar(dBachtrack); - o2::base::Propagator::Instance()->propagateToDCABxByBz({dCollision.posX(), dCollision.posY(), dCollision.posZ()}, Track2Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track2dcaXY = dcaInfo[0]; - auto Track2dca = std::sqrt(Track2dcaXY * Track2dcaXY + dcaInfo[1] * dcaInfo[1]); - - // H3L DCA Check - // auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, fitter3body.calcPCACovMatrixFlat(), t2.sign()); - auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, dBachtrack.sign()); - o2::dataformats::DCA dca; - if (d_UseH3LDCACut && (!track3B.propagateToDCA({{dCollision.posX(), dCollision.posY(), dCollision.posZ()}, {dCollision.covXX(), dCollision.covXY(), dCollision.covYY(), dCollision.covXZ(), dCollision.covYZ(), dCollision.covZZ()}}, fitter3body.getBz(), &dca, 5.) || - std::abs(dca.getY()) > maxDCAXY3Body || std::abs(dca.getZ()) > maxDCAZ3Body)) { - return; - } - FillVtxCounter(kVtxDcaH3L, isTrue3bodyVtx); - - vtx3bodydata( - dPtrack.globalIndex(), dNtrack.globalIndex(), dBachtrack.globalIndex(), dCollision.globalIndex(), 0, - vertexXYZ[0], vertexXYZ[1], vertexXYZ[2], - p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], - fitter3body.getChi2AtPCACandidate(), - Track0dcaXY, Track1dcaXY, Track2dcaXY, - Track0dca, Track1dca, Track2dca, - 0); // To be fixed - } - //------------------------------------------------------------------ - // 3body decay finder for a collsion - template - void DecayFinder(TCollisionTable const& dCollision, TPosTrackTable const& dPtracks, TNegTrackTable const& dNtracks, TGoodTrackTable const& dGoodtracks) - { - for (auto& t0id : dPtracks) { // FIXME: turn into combination(...) - auto t0 = t0id.template goodTrack_as(); - - for (auto& t1id : dNtracks) { - auto t1 = t1id.template goodTrack_as(); - float rv0; - if (!DecayV0Finder(dCollision, t0, t1, rv0)) { - continue; - } - - for (auto& t2id : dGoodtracks) { - auto t2 = t2id.template goodTrack_as(); - Decay3bodyFinder(dCollision, t0, t1, t2, rv0); - } - } - } - fillHistos(); - resetHistos(); - } - //------------------------------------------------------------------ - // MC 3body decay vertex finder - template - void DecayFinderMC(TCollisionTable const& dCollision, TPosTrackTable const& dPtracks, TNegTrackTable const& dNtracks, TGoodTrackTable const& dGoodtracks) - { - for (auto& t0id : dPtracks) { // FIXME: turn into combination(...) - auto t0 = t0id.template goodTrack_as(); - for (auto& t1id : dNtracks) { - auto t1 = t1id.template goodTrack_as(); - if (t0.collisionId() != t1.collisionId()) { - continue; - } - - bool isTrue3bodyV0 = false; - if (t0.has_mcParticle() && t1.has_mcParticle()) { - auto t0mc = t0.template mcParticle_as(); - auto t1mc = t1.template mcParticle_as(); - if ((t0mc.pdgCode() == 2212 && t1mc.pdgCode() == -211) || (t0mc.pdgCode() == 211 && t1mc.pdgCode() == -2212)) { - if (t0mc.has_mothers() && t1mc.has_mothers()) { - for (auto& t0mother : t0mc.template mothers_as()) { - for (auto& t1mother : t1mc.template mothers_as()) { - if (t0mother.globalIndex() == t1mother.globalIndex() && std::abs(t0mother.pdgCode()) == 1010010030) { - isTrue3bodyV0 = true; - } - } - } - } - } - } - - float rv0; - if (!DecayV0Finder(dCollision, t0, t1, rv0, isTrue3bodyV0)) { - continue; - } - - for (auto& t2id : dGoodtracks) { - auto t2 = t2id.template goodTrack_as(); - - bool isTrue3bodyVtx = false; - if (t0.has_mcParticle() && t1.has_mcParticle() && t2.has_mcParticle()) { - auto t0mc = t0.template mcParticle_as(); - auto t1mc = t1.template mcParticle_as(); - auto t2mc = t2.template mcParticle_as(); - if ((t0mc.pdgCode() == 2212 && t1mc.pdgCode() == -211 && t2mc.pdgCode() == 1000010020) || (t0mc.pdgCode() == 211 && t1mc.pdgCode() == -2212 && t2mc.pdgCode() == -1000010020)) { - if (t0mc.has_mothers() && t1mc.has_mothers() && t2mc.has_mothers()) { - for (auto& t0mother : t0mc.template mothers_as()) { - for (auto& t1mother : t1mc.template mothers_as()) { - for (auto& t2mother : t2mc.template mothers_as()) { - if (t0mother.globalIndex() == t1mother.globalIndex() && t0mother.globalIndex() == t2mother.globalIndex() && std::abs(t0mother.pdgCode()) == 1010010030) { - isTrue3bodyVtx = true; - } - } - } - } - } - } - } - - Decay3bodyFinder(dCollision, t0, t1, t2, rv0, isTrue3bodyVtx); - } - } - } - fillHistos(); - resetHistos(); - } - //------------------------------------------------------------------ - // MC virtual lambda check - template - void VirtualLambdaCheck(TCollisionTable const& /*dCollision*/, TV0DataTable const& fullV0s, int bin) - { - for (auto& v0 : fullV0s) { - statisticsRegistry.virtLambdastats[bin]++; - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - if (postrack.has_mcParticle() && negtrack.has_mcParticle()) { - auto postrackmc = postrack.template mcParticle_as(); - auto negtrackmc = negtrack.template mcParticle_as(); - - if ((postrackmc.pdgCode() == 2212 && negtrackmc.pdgCode() == -211) || (postrackmc.pdgCode() == 211 && negtrackmc.pdgCode() == -2212)) { - if (postrackmc.has_mothers() && negtrackmc.has_mothers()) { - for (auto& posmother : postrackmc.template mothers_as()) { - for (auto& negmother : negtrackmc.template mothers_as()) { - if (posmother.globalIndex() == negmother.globalIndex()) { - if (posmother.pdgCode() == 1010010030) - statisticsRegistry.virtLambdastats[bin + 1]++; - else if (posmother.pdgCode() == -1010010030) - statisticsRegistry.virtLambdastats[bin + 2]++; - } - } - } - } - } - } - } - fillHistos(); - resetHistos(); - } - - //------------------------------------------------------------------ - // Process Function - void processData(aod::Collision const& collision, aod::V0GoodPosTracks const& ptracks, aod::V0GoodNegTracks const& ntracks, aod::V0GoodTracks const& goodtracks, FullTracksExtIU const&, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - DecayFinder(collision, ptracks, ntracks, goodtracks); - } - PROCESS_SWITCH(hypertriton3bodyFinder, processData, "Produce StoredVtx3BodyDatas with data", true); - - void processCFFilteredData(aod::Collisions const& collisions, aod::CFFilters const& cffilters, aod::V0GoodPosTracks const& Ptracks, aod::V0GoodNegTracks const& Ntracks, aod::V0GoodTracks const& Goodtracks, FullTracksExtIU const&, aod::BCsWithTimestamps const&) - { - for (int i{0}; i < collisions.size(); i++) { - auto collision = collisions.iteratorAt(i); - auto cffilter = cffilters.iteratorAt(i); - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - auto ptracks = Ptracks.sliceBy(perCollisionGoodPosTracks, collision.globalIndex()); - auto ntracks = Ntracks.sliceBy(perCollisionGoodNegTracks, collision.globalIndex()); - auto goodtracks = Goodtracks.sliceBy(perCollisionGoodTracks, collision.globalIndex()); - - if (!cffilter.hasLD_LooseKstar() && UseCFFilter) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - - DecayFinder(collision, ptracks, ntracks, goodtracks); - } - } - PROCESS_SWITCH(hypertriton3bodyFinder, processCFFilteredData, "Produce StoredVtx3BodyDatas with data using CFtriggers", false); - - void processMC(aod::Collision const& collision, aod::V0GoodPosTracks const& ptracks, aod::V0GoodNegTracks const& ntracks, aod::V0GoodTracks const& goodtracks, aod::McParticles const& particlesMC, MCLabeledTracksIU const&, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - CheckGoodTracks(goodtracks, particlesMC); - DecayFinderMC(collision, ptracks, ntracks, goodtracks); - } - PROCESS_SWITCH(hypertriton3bodyFinder, processMC, "Produce StoredVtx3BodyDatas with MC", false); - - void processCFFilteredMC(aod::Collisions const& collisions, aod::CFFilters const& cffilters, aod::V0GoodPosTracks const& Ptracks, aod::V0GoodNegTracks const& Ntracks, aod::V0GoodTracks const& Goodtracks, aod::V0s const& V0s, aod::V0Datas const& fullV0s, aod::McParticles const& particlesMC, MCLabeledTracksIU const&, aod::BCsWithTimestamps const&) - { - for (int i{0}; i < collisions.size(); i++) { - auto collision = collisions.iteratorAt(i); - auto cffilter = cffilters.iteratorAt(i); - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - auto goodtracks = Goodtracks.sliceBy(perCollisionGoodTracks, collision.globalIndex()); - CheckGoodTracks(goodtracks, particlesMC); - auto v0s = V0s.sliceBy(perCollisionV0s, collision.globalIndex()); - auto fullv0s = fullV0s.sliceBy(perCollisionV0Datas, collision.globalIndex()); - VirtualLambdaCheck(collision, v0s, 0); - VirtualLambdaCheck(collision, fullv0s, 3); - - if (!cffilter.hasLD_LooseKstar() && UseCFFilter) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - - auto ptracks = Ptracks.sliceBy(perCollisionGoodPosTracks, collision.globalIndex()); - auto ntracks = Ntracks.sliceBy(perCollisionGoodNegTracks, collision.globalIndex()); - - VirtualLambdaCheck(collision, v0s, 6); - VirtualLambdaCheck(collision, fullv0s, 9); - DecayFinderMC(collision, ptracks, ntracks, goodtracks); - } - } - PROCESS_SWITCH(hypertriton3bodyFinder, processCFFilteredMC, "Produce StoredVtx3BodyDatas with MC using CFtriggers", false); -}; - -struct hypertriton3bodyLabelBuilder { - - Produces vtxlabels; - - // for bookkeeping purposes: how many V0s come from same mother etc - HistogramRegistry registry{ - "registry", - { - {"hLabelCounter", "hLabelCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hHypertritonMCPt", "hHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hAntiHypertritonMCPt", "hAntiHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hHypertritonMCMass", "hHypertritonMCMass", {HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hAntiHypertritonMCMass", "hAntiHypertritonMCMass", {HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hHypertritonMCLifetime", "hHypertritonMCLifetime", {HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}}}, - {"hAntiHypertritonMCLifetime", "hAntiHypertritonMCLifetime", {HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}}}, - }, - }; - - void init(InitContext const&) - { - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(2, "Same MotherParticle"); - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(3, "True H3L"); - } - - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - - void processDoNotBuildLabels(aod::Collisions::iterator const&) - { - // dummy process function - should not be required in the future - } - PROCESS_SWITCH(hypertriton3bodyLabelBuilder, processDoNotBuildLabels, "Do not produce MC label tables", true); - - void processBuildLabels(aod::Vtx3BodyDatas const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const& /*particlesMC*/) - { - std::vector lIndices; - lIndices.reserve(vtx3bodydatas.size()); - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - lIndices[ii] = -1; - } - - for (auto& vtx3body : vtx3bodydatas) { - - int lLabel = -1; - int lPDG = -1; - float lPt = -1; - double MClifetime = -1; - bool is3bodyDecay = false; - int lGlobalIndex = -1; - - auto lTrack0 = vtx3body.track0_as(); - auto lTrack1 = vtx3body.track1_as(); - auto lTrack2 = vtx3body.track2_as(); - registry.fill(HIST("hLabelCounter"), 0.5); - - // Association check - // There might be smarter ways of doing this in the future - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - vtxlabels(-1); - continue; - } - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - vtxlabels(-1); - continue; - } - - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lGlobalIndex = lMother1.globalIndex(); - lPt = lMother1.pt(); - lPDG = lMother1.pdgCode(); - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); - is3bodyDecay = true; // vtxs with the same mother - } - } - } - } // end association check - if (!is3bodyDecay) { - vtxlabels(-1); - continue; - } - registry.fill(HIST("hLabelCounter"), 1.5); - - // Intended for cross-checks only - // N.B. no rapidity cut! - if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { - lLabel = lGlobalIndex; - double hypertritonMCMass = RecoDecay::m(array{array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hHypertritonMCPt"), lPt); - registry.fill(HIST("hHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); - } - if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { - lLabel = lGlobalIndex; - double antiHypertritonMCMass = RecoDecay::m(array{array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hAntiHypertritonMCPt"), lPt); - registry.fill(HIST("hAntiHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); - } - - // Construct label table, only true hypertriton and true daughters with a specified order is labeled - // for matter: track0->p, track1->pi, track2->d - // for antimatter: track0->pi, track1->p, track2->d - vtxlabels(lLabel); - } - } - PROCESS_SWITCH(hypertriton3bodyLabelBuilder, processBuildLabels, "Produce MC label tables", false); -}; - -struct hypertriton3bodyComparewithDecay3body { - - HistogramRegistry registry{ - "registry", - { - {"hMCInfoCounter", "hMCInfoCounter", {HistType::kTH1F, {{8, 0.0f, 8.0f}}}}, - {"hCheckCounter", "hCheckCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - {"hHypertritonMCPtTotal", "hHypertritonMCPtTotal", {HistType::kTH1F, {{20, 0.0f, 10.0f}}}}, - {"hHypertritonMCPt", "hHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hAntiHypertritonMCPt", "hAntiHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hHypertritonMCMass", "hHypertritonMCMass", {HistType::kTH1F, {{40, 2.95f, 3.05f}}}}, - {"hAntiHypertritonMCMass", "hAntiHypertritonMCMass", {HistType::kTH1F, {{40, 2.95f, 3.05f}}}}, - {"hPairedHypertritonMCPt", "hPairedHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hPairedAntiHypertritonMCPt", "hPairedAntiHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hSameMcIndexCounter", "hSameMcIndexCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - }, - }; - - void init(InitContext const&) - { - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(2, "Sig in Decay3body"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(3, "Sig SameCol"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(4, "Sig contained by finder"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(5, "Sig SameIndex"); - } - struct Indexdaughters { // check duplicated paired daughters - int64_t index0; - int64_t index1; - int64_t index2; - bool operator==(const Indexdaughters& t) const - { - return (this->index0 == t.index0 && this->index1 == t.index1 && this->index2 == t.index2); - } - }; - - void processDoNotCompare(aod::Collisions::iterator const&) - { - // dummy process function - should not be required in the future - } - PROCESS_SWITCH(hypertriton3bodyComparewithDecay3body, processDoNotCompare, "Do not do comparison", true); - - void processDoComparison(aod::Decay3Bodys const& decay3bodytable, soa::Join const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const& /*particlesMC*/) - { - std::vector set_pair; - for (auto d3body : decay3bodytable) { - registry.fill(HIST("hCheckCounter"), 0.5); - registry.fill(HIST("hMCInfoCounter"), 0.5); - auto lTrack0 = d3body.track0_as(); - auto lTrack1 = d3body.track1_as(); - auto lTrack2 = d3body.track2_as(); - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - continue; - } - registry.fill(HIST("hMCInfoCounter"), 1.5); - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (lMCTrack0.isPhysicalPrimary() || lMCTrack1.isPhysicalPrimary() || lMCTrack2.isPhysicalPrimary()) { - continue; - } - if (lMCTrack0.producedByGenerator() || lMCTrack1.producedByGenerator() || lMCTrack2.producedByGenerator()) { - continue; - } - registry.fill(HIST("hMCInfoCounter"), 2.5); - - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - continue; - } - registry.fill(HIST("hMCInfoCounter"), 3.5); - - int lPDG = -1; - float lPt = -1; - bool is3bodyDecayedH3L = false; - int lGlobalIndex = -1; - - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - registry.fill(HIST("hMCInfoCounter"), 4.5); - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { // vtxs with the same mother - registry.fill(HIST("hMCInfoCounter"), 7.5); - lGlobalIndex = lMother1.globalIndex(); - lPDG = lMother1.pdgCode(); - lPt = lMother1.pt(); - if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { - is3bodyDecayedH3L = true; - double hypertritonMCMass = RecoDecay::m(array{array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hHypertritonMCPt"), lPt); - registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); - } - if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { - is3bodyDecayedH3L = true; - double antiHypertritonMCMass = RecoDecay::m(array{array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hAntiHypertritonMCPt"), lPt); - registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); - } - } - } - } - } // end association check - - if (!is3bodyDecayedH3L) { - continue; - } - - registry.fill(HIST("hCheckCounter"), 1.5); - registry.fill(HIST("hMCInfoCounter"), 5.5); - // for check - registry.fill(HIST("hHypertritonMCPtTotal"), lPt); - - Indexdaughters temp = {lMCTrack0.globalIndex(), lMCTrack1.globalIndex(), lMCTrack2.globalIndex()}; - auto p = std::find(set_pair.begin(), set_pair.end(), temp); - if (p == set_pair.end()) { - set_pair.push_back(temp); - registry.fill(HIST("hMCInfoCounter"), 6.5); - } - - if (lTrack0.collisionId() != lTrack1.collisionId() || lTrack0.collisionId() != lTrack2.collisionId()) { - continue; - } - registry.fill(HIST("hCheckCounter"), 2.5); - - for (auto vtx : vtx3bodydatas) { - if (vtx.mcParticleId() == -1) { - continue; - } - auto mcparticle = vtx.mcParticle_as(); - if (mcparticle.globalIndex() == lGlobalIndex) { - registry.fill(HIST("hCheckCounter"), 4.5); // rare case check: if motherId matches but daughters not - if (lTrack0.globalIndex() == vtx.track0Id() && lTrack1.globalIndex() == vtx.track1Id() && lTrack2.globalIndex() == vtx.track2Id()) { - registry.fill(HIST("hCheckCounter"), 3.5); - if (lPDG > 0) { - registry.fill(HIST("hPairedHypertritonMCPt"), lPt); - } else { - registry.fill(HIST("hPairedAntiHypertritonMCPt"), lPt); - } - break; - } - } - } - } - } - PROCESS_SWITCH(hypertriton3bodyComparewithDecay3body, processDoComparison, "Compare decay3bodys and finder method with MC", false); -}; - -struct hypertriton3bodyInitializer { - Spawns vtx3bodydatas; - void init(InitContext const&) {} -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/Tasks/Nuspex/CMakeLists.txt b/PWGLF/Tasks/Nuspex/CMakeLists.txt index 0f16d5e7b58..9b3943d07d8 100644 --- a/PWGLF/Tasks/Nuspex/CMakeLists.txt +++ b/PWGLF/Tasks/Nuspex/CMakeLists.txt @@ -24,16 +24,6 @@ o2physics_add_dpl_workflow(nuclei-hist PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(hypertriton3bodyanalysis - SOURCES hypertriton3bodyanalysis.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(hypertriton3bodymcqa - SOURCES hypertriton3bodyMcqa.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore O2::TOFBase - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(helium-flow SOURCES helium_flow.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx b/PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx deleted file mode 100644 index ef8dfb4b958..00000000000 --- a/PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx +++ /dev/null @@ -1,908 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \file hypertriton3bodyMcqa.cxx -/// \brief QA for MC productions which contain hypertriton 3body decay process, including special checks for TOF PID -/// \author Yuanzhe Wang - -#include -#include -#include -#include -#include -#include -#include - -#include "CommonDataFormat/InteractionRecord.h" -#include "CommonDataFormat/IRFrame.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/pidTOFGeneric.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/TableProducer/PID/pidTOFBase.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/PhysicsConstants.h" -#include "CCDB/BasicCCDBManager.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; -using ColwithEvTimes = o2::soa::Join; -using FullTracksExtIU = soa::Join; -using MCLabeledTracksIU = soa::Join; - -template -bool is3bodyDecayedH3L(TMCParticle const& particle) -{ - if (std::abs(particle.pdgCode()) != 1010010030) { - return false; - } - bool haveProton = false, havePion = false, haveDeuteron = false; - bool haveAntiProton = false, haveAntiPion = false, haveAntiDeuteron = false; - for (const auto& mcDaughter : particle.template daughters_as()) { - if (mcDaughter.pdgCode() == 2212) - haveProton = true; - if (mcDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcDaughter.pdgCode() == 211) - havePion = true; - if (mcDaughter.pdgCode() == -211) - haveAntiPion = true; - if (mcDaughter.pdgCode() == 1000010020) - haveDeuteron = true; - if (mcDaughter.pdgCode() == -1000010020) - haveAntiDeuteron = true; - } - if (haveProton && haveAntiPion && haveDeuteron && particle.pdgCode() > 0) { - return true; - } else if (haveAntiProton && havePion && haveAntiDeuteron && particle.pdgCode() < 0) { - return true; - } - return false; -} - -template -bool isPairedH3LDaughters(TMCParticle const& mctrack0, TMCParticle const& mctrack1, TMCParticle const& mctrack2) -{ - for (const auto& particleMother : mctrack0.template mothers_as()) { - if (!(particleMother.pdgCode() == 1010010030 && mctrack0.pdgCode() == 2212 && mctrack1.pdgCode() == -211 && mctrack2.pdgCode() == 1000010020) && - !(particleMother.pdgCode() == -1010010030 && mctrack0.pdgCode() == -2212 && mctrack1.pdgCode() == 211 && mctrack2.pdgCode() == -1000010020)) { - continue; - } - bool flag1 = false, flag2 = false; - for (const auto& mcDaughter : particleMother.template daughters_as()) { - if (mcDaughter.globalIndex() == mctrack1.globalIndex()) - flag1 = true; - if (mcDaughter.globalIndex() == mctrack2.globalIndex()) - flag2 = true; - } - if (!flag1 || !flag2) - continue; - // move the requirement in mass region into the loop to draw a histogram - // double hypertritonMCMass = RecoDecay::m(array{array{mctrack0.px(), mctrack0.py(), mctrack0.pz()}, array{mctrack1.px(), mctrack1.py(), mctrack1.pz()}, array{mctrack2.px(), mctrack2.py(), mctrack2.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - // if (hypertritonMCMass > 2.990 && hypertritonMCMass < 2.993) - return true; - } - return false; -} - -// check the properties of daughters candidates and true daughters -struct Hypertriton3bodyMcqa { - - Service ccdb; - Preslice perCollisionTracks = aod::track::collisionId; - - int mRunNumber; - - // Basic checks - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hParticleCounter", "hParticleCounter", {HistType::kTH1F, {{7, 0.0f, 7.0f}}}}, - - {"hTPCNCls", "hTPCNCls", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, - {"hTPCNClsCrossedRows", "hTPCNClsCrossedRows", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, - {"hTrackEta", "hTrackEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hTrackITSNcls", "hTrackITSNcls", {HistType::kTH1F, {{10, 0.0f, 10.0f}}}}, - {"hTrackMcRapidity", "hTrackMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hTrackNsigmaProton", "hTrackNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hTrackNsigmaPion", "hTrackNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hTrackNsigmaDeuteron", "hTrackNsigmaDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - - {"hHypertritonEta", "hHypertritomEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hHypertritonMcRapidity", "hHypertritonMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hHypertritonMcPt", "hHypertritonMcPt", {HistType::kTH1F, {{300, 0.0f, 15.0f}}}}, - - {"hProtonCounter", "hProtonCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - {"hProtonPt", "hProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonP", "hProtonP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonMcPt", "hProtonMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonMcP", "hProtonMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonEta", "hProtonEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hProtonMcRapidity", "hProtonMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hProtonNsigmaProton", "hProtonNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hProtonTPCNCls", "hProtonTPCNCls", {HistType::kTH1F, {{120, 0.0f, 120.0f}}}}, - {"hProtonTPCBB", "hProtonTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hProtonTPCBBAfterTPCNclsCut", "hProtonTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDauProtonPt", "hDauProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauProtonMcPt", "hDauProtonMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauProtonNsigmaProton", "hDauProtonNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hDauProtonTPCVsPt", "hDauProtonTPCVsPt", {HistType::kTH2F, {{50, 0.0f, 5.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - - {"hPionCounter", "hPionCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - {"hPionPt", "hPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionP", "hPionP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionMcPt", "hPionMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionMcP", "hPionMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionEta", "hPionEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hPionMcRapidity", "hPionMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hPionNsigmaPion", "hPionNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hPionTPCNCls", "hPionTPCNCls", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, - {"hPionTPCBB", "hPionTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hPionTPCBBAfterTPCNclsCut", "hPionTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDauPionPt", "hDauPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauPionMcPt", "hDauPionMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauPionNsigmaPion", "hDauPionNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hDauPionTPCVsPt", "hDauPionTPCVsPt", {HistType::kTH2F, {{20, 0.0f, 2.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDauPionDcaXY", "hDauPionDcaXY", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}}, - - {"hDeuteronCounter", "hDeuteronCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - {"hDeuteronPt", "hDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronP", "hDeuteronP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronMcPt", "hDeuteronMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronMcP", "hDeuteronMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronEta", "hDeuteronEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hDeuteronMcRapidity", "hDeuteronMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hDeuteronNsigmaDeuteron", "hDeuteronNsigmaDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hDeuteronTPCNCls", "hDeuteronTPCNCls", {HistType::kTH1F, {{120, 0.0f, 120.0f}}}}, - {"hDeuteronTPCBB", "hDeuteronTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDeuteronTPCBBAfterTPCNclsCut", "hDeuteronTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDauDeuteronPt", "hDauDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauDeuteronMcPt", "hDauDeuteronMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauDeuteronTPCVsPt", "hDauDeuteronTPCVsPt", {HistType::kTH2F, {{80, 0.0f, 8.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsP", "hDauDeuteronTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsPHasTOF", "hDauDeuteronTOFNSigmaVsPHasTOF", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronMatchCounter", "hDauDeuteronMatchCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - - {"hTPCBB", "hTPCBB", {HistType::kTH2F, {{120, -8.0f, 8.0f, "p/z(GeV/c)"}, {100, 0.0f, 1000.0f, "TPCSignal"}}}}, - - {"hPairedH3LDaughers", "hPairedH3LDaughers", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hPairedH3LDaughersInvMass", "hPairedH3LDaughersInvMass", {HistType::kTH1F, {{300, 2.9f, 3.2f}}}}, - {"hDuplicatedH3LDaughers", "hDuplicatedH3LDaughers", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - - // Diff checks always requir hasTOF - {"hDiffTrackTOFSignal", "hDiffTrackTOFSignal", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, - {"hDiffEvTimeForTrack", "hDiffEvTimeForTrack", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, - {"hDiffTrackTOFNSigmaDe", "hDiffTrackTOFNSigmaDe", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, - {"hDauDeuteronNewTOFNSigmaVsP", "hDauDeuteronNewTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hWrongDeuteronTOFNSigmaVsP", "hWrongDeuteronTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hWrongDeuteronNewTOFNSigmaVsP", "hWrongDeuteronNewTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDiffColTime", "hDiffColTime", {HistType::kTH1F, {{200, -100.0f, 100.0f}}}}, - {"hDauDeuteronDiffTOFNsigmaDeHasTOF", "hDauDeuteronDiffTOFNsigmaDeHasTOF", {HistType::kTH1F, {{200, -100.0f, 100.0f}}}}, - - // _v2 for using relinked collision - {"hDauDeuteronTOFNSigmaVsP_CorrectCol", "hDauDeuteronTOFNSigmaVsP_CorrectCol", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronNewTOFNSigmaVsP_CorrectCol", "hDauDeuteronNewTOFNSigmaVsP_CorrectCol", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsP_v2", "hDauDeuteronTOFNSigmaVsP_v2", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronNewTOFNSigmaVsP_v2_AO2D", "hDauDeuteronNewTOFNSigmaVsP_v2 AO2D", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronNewTOFNSigmaVsP_v2_EvSel", "hDauDeuteronNewTOFNSigmaVsP_v2 EvSel", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsColTimeRes_v2", "hDauDeuteronTOFNSigmaVsColTimeRes_v2", {HistType::kTH2F, {{100, 0.0f, 400.0f, "CollisionTimeRes(ns)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsColTimeRes_v2_AO2D", "hDauDeuteronTOFNSigmaVsColTimeRes_v2 AO2D", {HistType::kTH2F, {{100, 0.0f, 400.0f, "CollisionTimeRes(ns)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsColTimeRes_v2_EvSel", "hDauDeuteronTOFNSigmaVsColTimeRes_v2 EvSel", {HistType::kTH2F, {{100, 0.0f, 400.0f, "CollisionTimeRes(ns)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronTOFPIDCounter", "hDauDeuteronTOFPIDCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - {"hDauDeuteronTOFPIDCounter_CloseBC", "hDauDeuteronTOFPIDCounter CloseBC", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - }, - }; - - void init(InitContext&) - { - registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(1, "Readin"); - registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(2, "Has_mcparticle"); - registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(3, "Rapidity Cut"); - registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(4, "McisHypertriton"); - registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(5, "McisProton"); - registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(6, "McisPion"); - registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(7, "McisDeuteron"); - - TString trackCounterbinLabel[2] = {"hasMom", "FromHypertriton"}; - for (int i{0}; i < 2; i++) { - registry.get(HIST("hProtonCounter"))->GetXaxis()->SetBinLabel(i + 1, trackCounterbinLabel[i]); - registry.get(HIST("hPionCounter"))->GetXaxis()->SetBinLabel(i + 1, trackCounterbinLabel[i]); - registry.get(HIST("hDeuteronCounter"))->GetXaxis()->SetBinLabel(i + 1, trackCounterbinLabel[i]); - } - registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(1, "proton"); - registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(2, "pion"); - registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(3, "deuteron"); - - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(2, "correct collision"); - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(3, "hasTOF"); - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(4, "hasTOF & correct collsion"); - - registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(1, "Origin |n#sigma| >= 5"); - registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(2, "BothBC work"); - registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(3, "Only BCAO2D work"); - registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(4, "Only BCEvSel work"); - registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(5, "BothBC not work"); - registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(1, "Origin |n#sigma| < 6"); - registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(2, "BothBC work"); - registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(3, "Only BCAO2D work"); - registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(4, "Only BCEvSel work"); - registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(5, "BothBC not work"); - } - - Configurable dcapiontopv{"dcapiontopv", .05, "DCA Pion To PV"}; - Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; - Configurable maxProtonPt{"maxProtonPt", 5, "maxProtonPt"}; - Configurable minPionPt{"minPionPt", 0.1, "minPionPt"}; - Configurable maxPionPt{"maxPionPt", 1.2, "maxPionPt"}; - Configurable minDeuteronPt{"minDeuteronPt", 0.6, "minDeuteronPt"}; - Configurable maxDeuteronPt{"maxDeuteronPt", 10, "maxDeuteronPt"}; - Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; - Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; - - // CCDB TOF PID paras - Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; - Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; - Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; - Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; - Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; - Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; - Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; - - o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; - o2::pid::tof::TOFResoParamsV2 mRespParamsV2; - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - mRunNumber = bc.runNumber(); - - // Initial TOF PID Paras, copied from PIDTOF.h - timestamp.value = bc.timestamp(); - ccdb->setTimestamp(timestamp.value); - // Not later than now objects - ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - // TODO: implement the automatic pass name detection from metadata - if (passName.value == "") { - passName.value = "unanchored"; // temporary default - LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << passName.value << "'"; - } - LOG(info) << "Using parameter collection, starting from pass '" << passName.value << "'"; - - const std::string fname = paramFileName.value; - if (!fname.empty()) { // Loading the parametrization from file - LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << parametrizationPath.value; - if (1) { - o2::tof::ParameterCollection paramCollection; - paramCollection.loadParamFromFile(fname, parametrizationPath.value); - LOG(info) << "+++ Loaded parameter collection from file +++"; - if (!paramCollection.retrieveParameters(mRespParamsV2, passName.value)) { - if (fatalOnPassNotAvailable) { - LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); - } else { - LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); - } - } else { - mRespParamsV2.setShiftParameters(paramCollection.getPars(passName.value)); - mRespParamsV2.printShiftParameters(); - } - } else { - mRespParamsV2.loadParamFromFile(fname.data(), parametrizationPath.value); - } - } else if (loadResponseFromCCDB) { // Loading it from CCDB - LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << parametrizationPath.value << " for timestamp " << timestamp.value; - o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(parametrizationPath.value, timestamp.value); - paramCollection->print(); - if (!paramCollection->retrieveParameters(mRespParamsV2, passName.value)) { // Attempt at loading the parameters with the pass defined - if (fatalOnPassNotAvailable) { - LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); - } else { - LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); - } - } else { // Pass is available, load non standard parameters - mRespParamsV2.setShiftParameters(paramCollection->getPars(passName.value)); - mRespParamsV2.printShiftParameters(); - } - } - mRespParamsV2.print(); - if (timeShiftCCDBPath.value != "") { - if (timeShiftCCDBPath.value.find(".root") != std::string::npos) { - mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Pos", true); - mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Neg", false); - } else { - mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", timeShiftCCDBPath.value.c_str()), timestamp.value), true); - mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", timeShiftCCDBPath.value.c_str()), timestamp.value), false); - } - } - - bachelorTOFPID.SetParams(mRespParamsV2); - } - - struct Indexdaughters { // check duplicated paired daughters - int64_t index0; - int64_t index1; - int64_t index2; - bool operator==(const Indexdaughters& t) const - { - return (this->index0 == t.index0 && this->index1 == t.index1 && this->index2 == t.index2); - } - }; - - void process(ColwithEvTimes const& collisions, MCLabeledTracksIU const& tracks, aod::McParticles const& /*particlesMC*/, aod::McCollisions const& /*mcCollisions*/, aod::BCsWithTimestamps const&) - { - for (const auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - - registry.fill(HIST("hEventCounter"), 0.5); - if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm - continue; - } - registry.fill(HIST("hEventCounter"), 2.5); - - std::vector protons, pions, deuterons; // index for daughter tracks - std::unordered_set set_proton, set_pion, set_deuteron; // check duplicated daughters - int itrack = -1; - - auto coltracks = tracks.sliceBy(perCollisionTracks, collision.globalIndex()); - - for (const auto& track : coltracks) { - - ++itrack; - registry.fill(HIST("hParticleCounter"), 0.5); - registry.fill(HIST("hTrackITSNcls"), track.itsNCls()); - registry.fill(HIST("hTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hTPCNClsCrossedRows"), track.tpcNClsCrossedRows()); - registry.fill(HIST("hTrackNsigmaDeuteron"), track.tpcNSigmaDe()); - registry.fill(HIST("hTrackNsigmaProton"), track.tpcNSigmaPr()); - registry.fill(HIST("hTrackNsigmaPion"), track.tpcNSigmaPi()); - - if (!track.has_mcParticle()) { - continue; - } - auto mcparticle = track.mcParticle_as(); - registry.fill(HIST("hTPCBB"), track.p() * track.sign(), track.tpcSignal()); - - registry.fill(HIST("hParticleCounter"), 1.5); - - // if (TMath::Abs(mcparticle.y()) > 0.9) {continue;} - registry.fill(HIST("hParticleCounter"), 2.5); - registry.fill(HIST("hTrackEta"), track.eta()); - registry.fill(HIST("hTrackMcRapidity"), mcparticle.y()); - - // Hypertriton detected directly - if (mcparticle.pdgCode() == 1010010030 || mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hParticleCounter"), 3.5); - registry.fill(HIST("hHypertritonMcPt"), mcparticle.pt()); - registry.fill(HIST("hHypertritonEta"), track.eta()); - registry.fill(HIST("hHypertritonMcRapidity"), mcparticle.y()); - } - - // Proton - if (mcparticle.pdgCode() == 2212 || mcparticle.pdgCode() == -2212) { - registry.fill(HIST("hParticleCounter"), 4.5); - if (track.tpcNClsFound() > 70) { - registry.fill(HIST("hProtonTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); - } - - if (mcparticle.has_mothers()) { - registry.fill(HIST("hProtonCounter"), 0.5); - for (const auto& particleMother : mcparticle.mothers_as()) { - bool flag_H3L = is3bodyDecayedH3L(particleMother); - if (!flag_H3L) { - continue; - } - protons.push_back(itrack); - auto p = set_proton.insert(mcparticle.globalIndex()); - if (p.second == false) - registry.fill(HIST("hDuplicatedH3LDaughers"), 0); - registry.fill(HIST("hProtonCounter"), 1.5); - registry.fill(HIST("hDauProtonPt"), track.pt()); - registry.fill(HIST("hDauProtonMcPt"), mcparticle.pt()); - registry.fill(HIST("hDauProtonNsigmaProton"), track.tpcNSigmaPr()); - registry.fill(HIST("hDauProtonTPCVsPt"), track.pt(), track.tpcNSigmaPr()); - } - } - - registry.fill(HIST("hProtonMcPt"), mcparticle.pt()); - registry.fill(HIST("hProtonMcP"), mcparticle.p()); - registry.fill(HIST("hProtonPt"), track.pt()); - registry.fill(HIST("hProtonP"), track.p()); - - registry.fill(HIST("hProtonNsigmaProton"), track.tpcNSigmaPr()); - registry.fill(HIST("hProtonTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hProtonEta"), track.eta()); - registry.fill(HIST("hProtonMcRapidity"), mcparticle.y()); - registry.fill(HIST("hProtonTPCBB"), track.p() * track.sign(), track.tpcSignal()); - } - - // Pion - if (mcparticle.pdgCode() == 211 || mcparticle.pdgCode() == -211) { - registry.fill(HIST("hParticleCounter"), 5.5); - if (track.tpcNClsFound() > 70) { - registry.fill(HIST("hPionTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); - } - - if (mcparticle.has_mothers()) { - registry.fill(HIST("hPionCounter"), 0.5); - for (const auto& particleMother : mcparticle.mothers_as()) { - bool flag_H3L = is3bodyDecayedH3L(particleMother); - if (!flag_H3L) { - continue; - } - pions.push_back(itrack); - auto p = set_pion.insert(mcparticle.globalIndex()); - if (p.second == false) { - registry.fill(HIST("hDuplicatedH3LDaughers"), 1); - } - registry.fill(HIST("hPionCounter"), 1.5); - registry.fill(HIST("hDauPionPt"), track.pt()); - registry.fill(HIST("hDauPionMcPt"), mcparticle.pt()); - registry.fill(HIST("hDauPionTPCVsPt"), track.pt(), track.tpcNSigmaPi()); - registry.fill(HIST("hDauPionDcaXY"), track.dcaXY()); - } - } - - registry.fill(HIST("hPionMcPt"), mcparticle.pt()); - registry.fill(HIST("hPionMcP"), mcparticle.p()); - registry.fill(HIST("hPionPt"), track.pt()); - registry.fill(HIST("hPionP"), track.p()); - - registry.fill(HIST("hPionNsigmaPion"), track.tpcNSigmaPi()); - registry.fill(HIST("hPionTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hPionEta"), track.eta()); - registry.fill(HIST("hPionMcRapidity"), mcparticle.y()); - registry.fill(HIST("hPionTPCBB"), track.p() * track.sign(), track.tpcSignal()); - } - - float tofNsigmaDe = -999; - static constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; // c in cm/ps - - if (track.hasTOF() && track.has_collision()) { - auto responseDe = o2::pid::tof::ExpTimes(); - // float bachExpTime = track.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v - - float mMassHyp = o2::track::pid_constants::sMasses2Z[track.pidForTracking()]; - float bachExpTime = track.length() * std::sqrt((mMassHyp * mMassHyp) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v - float tofsignal = track.trackTime() * 1000 + bachExpTime; // in ps - - float expSigma = responseDe.GetExpectedSigma(mRespParamsV2, track, tofsignal, track.tofEvTimeErr()); - // tofNsigmaDe = (track.tofSignal() - track.tofEvTime() - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; - tofNsigmaDe = (tofsignal - track.tofEvTime() - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; - // tofNsigmaDe = (tofsignal - track.evTimeForTrack() - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; - - if (collision.bcId() == collision.foundBCId()) { - registry.fill(HIST("hDiffColTime"), track.tofEvTime() - collision.collisionTime()); - } - - // Assume deuterons linked to the correct collision, result of new TOF PID should be same as the default one - registry.fill(HIST("hDiffTrackTOFSignal"), track.tofSignal() - tofsignal); - registry.fill(HIST("hDiffEvTimeForTrack"), track.tofEvTime() - track.evTimeForTrack()); - registry.fill(HIST("hDiffTrackTOFNSigmaDe"), track.tofNSigmaDe() - bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, collision, collision)); - // registry.fill(HIST("hDiffTrackTOFNSigmaDe"), track.tofExpSigmaDe() - bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, collision, collision)); - } - - // Deuteron - if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { - registry.fill(HIST("hParticleCounter"), 6.5); - if (track.tpcNClsFound() > 70) { - registry.fill(HIST("hDeuteronTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); - } - - if (mcparticle.has_mothers()) { - registry.fill(HIST("hDeuteronCounter"), 0.5); - for (const auto& particleMother : mcparticle.mothers_as()) { - bool flag_H3L = is3bodyDecayedH3L(particleMother); - if (!flag_H3L) { - continue; - } - deuterons.push_back(itrack); - auto p = set_deuteron.insert(mcparticle.globalIndex()); - if (p.second == false) - registry.fill(HIST("hDuplicatedH3LDaughers"), 2); - registry.fill(HIST("hDeuteronCounter"), 1.5); - registry.fill(HIST("hDauDeuteronPt"), track.pt()); - registry.fill(HIST("hDauDeuteronMcPt"), mcparticle.pt()); - registry.fill(HIST("hDauDeuteronTPCVsPt"), track.pt(), track.tpcNSigmaDe()); - registry.fill(HIST("hDauDeuteronTOFNSigmaVsP"), track.sign() * track.p(), track.tofNSigmaDe()); - - registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP"), track.sign() * track.p(), tofNsigmaDe); - if (track.hasTOF()) { - registry.fill(HIST("hDauDeuteronTOFNSigmaVsPHasTOF"), track.sign() * track.p(), track.tofNSigmaDe()); - registry.fill(HIST("hDauDeuteronDiffTOFNsigmaDeHasTOF"), track.tofNSigmaDe() - tofNsigmaDe); - } - registry.fill(HIST("hDauDeuteronMatchCounter"), 0.5); - if (mcparticle.mcCollisionId() == collision.mcCollisionId()) { - registry.fill(HIST("hDauDeuteronMatchCounter"), 1.5); - } - if (track.hasTOF()) { - registry.fill(HIST("hDauDeuteronMatchCounter"), 2.5); - if (mcparticle.mcCollisionId() == collision.mcCollisionId()) { - registry.fill(HIST("hDauDeuteronMatchCounter"), 3.5); - } - } - } - } - - registry.fill(HIST("hDeuteronMcPt"), mcparticle.pt()); - registry.fill(HIST("hDeuteronMcP"), mcparticle.p()); - registry.fill(HIST("hDeuteronPt"), track.pt()); - registry.fill(HIST("hDeuteronP"), track.p()); - - registry.fill(HIST("hDeuteronNsigmaDeuteron"), track.tpcNSigmaDe()); - registry.fill(HIST("hDeuteronTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hDeuteronEta"), track.eta()); - registry.fill(HIST("hDeuteronMcRapidity"), mcparticle.y()); - registry.fill(HIST("hDeuteronTPCBB"), track.p() * track.sign(), track.tpcSignal()); - } else { - if (track.hasTOF()) { - registry.fill(HIST("hWrongDeuteronTOFNSigmaVsP"), track.sign() * track.p(), track.tofNSigmaDe()); - registry.fill(HIST("hWrongDeuteronNewTOFNSigmaVsP"), track.sign() * track.p(), tofNsigmaDe); - } - } - } - - std::vector set_pair; - for (size_t iproton = 0; iproton < protons.size(); iproton++) { - auto track0 = tracks.iteratorAt(protons[iproton]); - auto mctrack0 = track0.mcParticle_as(); - for (size_t ipion = 0; ipion < pions.size(); ipion++) { - auto track1 = tracks.iteratorAt(pions[ipion]); - auto mctrack1 = track1.mcParticle_as(); - for (size_t ideuteron = 0; ideuteron < deuterons.size(); ideuteron++) { - auto track2 = tracks.iteratorAt(deuterons[ideuteron]); - auto mctrack2 = track2.mcParticle_as(); - if (isPairedH3LDaughters(mctrack0, mctrack1, mctrack2)) { - registry.fill(HIST("hPairedH3LDaughers"), 0); - // MC mass cut, to check if the daughters are from materials - double hypertritonMCMass = RecoDecay::m(std::array{std::array{mctrack0.px(), mctrack0.py(), mctrack0.pz()}, std::array{mctrack1.px(), mctrack1.py(), mctrack1.pz()}, std::array{mctrack2.px(), mctrack2.py(), mctrack2.pz()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hPairedH3LDaughersInvMass"), hypertritonMCMass); - if (hypertritonMCMass < 2.990 || hypertritonMCMass > 2.993) - continue; - registry.fill(HIST("hPairedH3LDaughers"), 1); - // duplicated daughters check - Indexdaughters temp = {mctrack0.globalIndex(), mctrack1.globalIndex(), mctrack2.globalIndex()}; - auto p = std::find(set_pair.begin(), set_pair.end(), temp); - if (p == set_pair.end()) { - set_pair.push_back(temp); - registry.fill(HIST("hPairedH3LDaughers"), 2); - } - } - } - } - } - } - - // Check for recalculated TOF PID for secondary deuterons - - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - for (const auto& collision : collisions) { - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); - } - - for (const auto& track : tracks) { - if (!track.has_mcParticle()) { - continue; - } - auto mcparticle = track.mcParticle_as(); - if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { - if (!mcparticle.has_mothers()) { - continue; - } - const auto evtReconstructed = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcparticle.mcCollision_as().globalIndex()); - if (evtReconstructed == SelectedEvents.end() || !track.has_collision()) { - continue; - } - if (!track.has_collision()) { - continue; - } - auto collision = collisions.iteratorAt(evtReconstructed - SelectedEvents.begin()); - auto originalcollision = track.collision_as(); - - for (const auto& particleMother : mcparticle.mothers_as()) { - bool flag_H3L = is3bodyDecayedH3L(particleMother); - if (!flag_H3L) { - continue; - } - - auto bc = collision.bc_as(); - initCCDB(bc); - float tofNsigmaDeAO2D = -999; - float tofNsigmaDeEvSel = -999; - - if (track.hasTOF()) { - /*auto responseDe = o2::pid::tof::ExpTimes(); - //float bachExpTime = track.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v - float mMassHyp = o2::track::pid_constants::sMasses2Z[track.pidForTracking()]; - float bachExpTime = track.length() * std::sqrt((mMassHyp * mMassHyp) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v - */ - - tofNsigmaDeAO2D = bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, originalcollision, collision); - tofNsigmaDeEvSel = bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, originalcollision, collision, false); - - if (collision.globalIndex() == originalcollision.globalIndex()) { - registry.fill(HIST("hDauDeuteronTOFNSigmaVsP_CorrectCol"), track.sign() * track.p(), track.tofNSigmaDe()); - registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP_CorrectCol"), track.sign() * track.p(), tofNsigmaDeAO2D); - continue; - } - - /*if (originalcollision.collisionTimeRes() > 40){ - continue; - }*/ - registry.fill(HIST("hDauDeuteronTOFNSigmaVsP_v2"), track.sign() * track.p(), track.tofNSigmaDe()); - registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP_v2_AO2D"), track.sign() * track.p(), tofNsigmaDeAO2D); - registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP_v2_EvSel"), track.sign() * track.p(), tofNsigmaDeEvSel); - registry.fill(HIST("hDauDeuteronTOFNSigmaVsColTimeRes_v2"), collision.collisionTimeRes(), track.tofNSigmaDe()); - registry.fill(HIST("hDauDeuteronTOFNSigmaVsColTimeRes_v2_AO2D"), originalcollision.collisionTimeRes(), tofNsigmaDeAO2D); - registry.fill(HIST("hDauDeuteronTOFNSigmaVsColTimeRes_v2_EvSel"), originalcollision.collisionTimeRes(), tofNsigmaDeEvSel); - - if (std::abs(track.tofNSigmaDe()) >= 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 0.5); - if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) < 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 1.5); - } else if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) >= 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 2.5); - } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) < 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 3.5); - } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) >= 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 4.5); - } - } else if (std::abs(track.tofNSigmaDe()) < 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 0.5); - if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) < 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 1.5); - } else if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) >= 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 2.5); - } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) < 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 3.5); - } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) >= 5) { - registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 4.5); - } - } - } - } - } - } - } -}; - -// check the performance of mcparticle -struct Hypertriton3bodyMcParticleCheck { - // Basic checks - HistogramRegistry registry{ - "registry", - { - {"hMcCollCounter", "hMcCollCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - - {"h3dMCDecayedHypertriton", "h3dMCDecayedHypertriton", {HistType::kTH3F, {{20, -1.0f, 1.0f, "Rapidity"}, {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {50, 0.0f, 50.0f, "ct(cm)"}}}}, - - {"hMcHypertritonCounter", "hMcHypertritonCounter", {HistType::kTH1F, {{9, 0.0f, 9.0f}}}}, - {"hMcHypertritonPt", "hMcHypertritonPt", {HistType::kTH1F, {{300, 0.0f, 15.0f}}}}, - {"hMcProtonPt", "hMcProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hMcPionPt", "hMcPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hMcDeuteronPt", "hMcDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - - {"hMcRecoInvMass", "hMcRecoInvMass", {HistType::kTH1F, {{100, 2.95, 3.05f}}}}, - - {"hDiffDaughterR", "hDiffDaughterR", {HistType::kTH1F, {{10000, -100, 100}}}}, // difference between minR of pion&proton and R of deuteron(bachelor) - {"hTrackX", "hTrackX", {HistType::kTH1F, {{10000, -100, 100}}}}, - {"hTrackY", "hTrackY", {HistType::kTH1F, {{10000, -100, 100}}}}, - {"hTrackZ", "hTrackZ", {HistType::kTH1F, {{10000, -100, 100}}}}, - }, - }; - - o2::pid::tof::TOFResoParamsV2 mRespParamsV2; - - void init(InitContext&) - { - registry.get(HIST("hMcCollCounter"))->GetXaxis()->SetBinLabel(1, "Total Counter"); - registry.get(HIST("hMcCollCounter"))->GetXaxis()->SetBinLabel(2, "Reconstructed"); - - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(1, "Hypertriton All"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(2, "Matter All"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(3, "AntiMatter All"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(4, "confirm to 3-body decay"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(5, "Matter"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(6, "AntiMatter"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(7, "Rapidity"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(8, "Lifetime"); - registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(9, "PtCut"); - } - - Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; - Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; - - Preslice permcCollision = o2::aod::mcparticle::mcCollisionId; - - std::vector mcPartIndices; - template - void SetTrackIDForMC(aod::McParticles const& particlesMC, TTrackTable const& tracks) - { - mcPartIndices.clear(); - mcPartIndices.resize(particlesMC.size()); - std::fill(mcPartIndices.begin(), mcPartIndices.end(), -1); - for (const auto& track : tracks) { - if (track.has_mcParticle()) { - auto mcparticle = track.template mcParticle_as(); - if (mcPartIndices[mcparticle.globalIndex()] == -1) { - mcPartIndices[mcparticle.globalIndex()] = track.globalIndex(); - } else { - auto candTrack = tracks.rawIteratorAt(mcPartIndices[mcparticle.globalIndex()]); - // Use the track which has innest information (also best quality? - if (track.x() < candTrack.x()) { - mcPartIndices[mcparticle.globalIndex()] = track.globalIndex(); - } - } - - // Checks for TrackR - registry.fill(HIST("hTrackX"), track.x()); - registry.fill(HIST("hTrackY"), track.y()); - registry.fill(HIST("hTrackZ"), track.z()); - } - } - } - - void process(aod::McCollisions const& mcCollisions, aod::McParticles const& particlesMC, const o2::soa::Join& collisions, MCLabeledTracksIU const& tracks) - { - SetTrackIDForMC(particlesMC, tracks); - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - for (const auto& collision : collisions) { - if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { - continue; - } - if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm - continue; - } - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); - } - SelectedEvents.resize(nevts); - - for (const auto& mcCollision : mcCollisions) { - registry.fill(HIST("hMcCollCounter"), 0.5); - const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); - if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection - continue; - } - registry.fill(HIST("hMcCollCounter"), 1.5); - - const auto& dparticlesMC = particlesMC.sliceBy(permcCollision, mcCollision.globalIndex()); - - for (const auto& mcparticle : dparticlesMC) { - - if (mcparticle.pdgCode() == 2212 || mcparticle.pdgCode() == -2212) { - registry.fill(HIST("hMcProtonPt"), mcparticle.pt()); - } - if (mcparticle.pdgCode() == 211 || mcparticle.pdgCode() == -211) { - registry.fill(HIST("hMcPionPt"), mcparticle.pt()); - } - if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { - registry.fill(HIST("hMcDeuteronPt"), mcparticle.pt()); - } - if (mcparticle.pdgCode() == 1010010030) { - registry.fill(HIST("hMcHypertritonCounter"), 1.5); - } else if (mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hMcHypertritonCounter"), 2.5); - } - if (mcparticle.pdgCode() == 1010010030 || mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hMcHypertritonCounter"), 0.5); - registry.fill(HIST("hMcHypertritonPt"), mcparticle.pt()); - - double dauDeuteronPos[3] = {-999, -999, -999}; - double dauProtonMom[3] = {-999, -999, -999}; - double dauPionMom[3] = {-999, -999, -999}; - double dauDeuteronMom[3] = {-999, -999, -999}; - double MClifetime = 999; - double dauProtonTrackR = 9999, dauPionTrackR = 99999, dauDeuteronTrackR = 999999; - bool flag_H3L = is3bodyDecayedH3L(mcparticle); - if (!flag_H3L) { - continue; - } - for (const auto& mcparticleDaughter : mcparticle.daughters_as()) { - if (std::abs(mcparticleDaughter.pdgCode()) == 2212) { - dauProtonMom[0] = mcparticleDaughter.px(); - dauProtonMom[1] = mcparticleDaughter.py(); - dauProtonMom[2] = mcparticleDaughter.pz(); - if (mcPartIndices[mcparticleDaughter.globalIndex()] != -1) { - auto trackProton = tracks.rawIteratorAt(mcPartIndices[mcparticleDaughter.globalIndex()]); - dauProtonTrackR = trackProton.x(); - } - } - if (std::abs(mcparticleDaughter.pdgCode()) == 211) { - dauPionMom[0] = mcparticleDaughter.px(); - dauPionMom[1] = mcparticleDaughter.py(); - dauPionMom[2] = mcparticleDaughter.pz(); - if (mcPartIndices[mcparticleDaughter.globalIndex()] != -1) { - auto trackPion = tracks.rawIteratorAt(mcPartIndices[mcparticleDaughter.globalIndex()]); - dauPionTrackR = trackPion.x(); - } - } - if (std::abs(mcparticleDaughter.pdgCode()) == 1000010020) { - dauDeuteronPos[0] = mcparticleDaughter.vx(); - dauDeuteronPos[1] = mcparticleDaughter.vy(); - dauDeuteronPos[2] = mcparticleDaughter.vz(); - dauDeuteronMom[0] = mcparticleDaughter.px(); - dauDeuteronMom[1] = mcparticleDaughter.py(); - dauDeuteronMom[2] = mcparticleDaughter.pz(); - if (mcPartIndices[mcparticleDaughter.globalIndex()] != -1) { - auto trackDeuteron = tracks.rawIteratorAt(mcPartIndices[mcparticleDaughter.globalIndex()]); - dauDeuteronTrackR = trackDeuteron.x(); - } - } - } - if (mcparticle.pdgCode() == 1010010030) { - registry.fill(HIST("hMcHypertritonCounter"), 3.5); - registry.fill(HIST("hMcHypertritonCounter"), 4.5); - } - if (mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hMcHypertritonCounter"), 3.5); - registry.fill(HIST("hMcHypertritonCounter"), 5.5); - } - double hypertritonMCMass = RecoDecay::m(std::array{std::array{dauProtonMom[0], dauProtonMom[1], dauProtonMom[2]}, std::array{dauPionMom[0], dauPionMom[1], dauPionMom[2]}, std::array{dauDeuteronMom[0], dauDeuteronMom[1], dauDeuteronMom[2]}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hMcRecoInvMass"), hypertritonMCMass); - - if (hypertritonMCMass > 2.990 && hypertritonMCMass < 2.993) { - MClifetime = RecoDecay::sqrtSumOfSquares(dauDeuteronPos[0] - mcparticle.vx(), dauDeuteronPos[1] - mcparticle.vy(), dauDeuteronPos[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - registry.fill(HIST("h3dMCDecayedHypertriton"), mcparticle.y(), mcparticle.pt(), MClifetime); - - double diffTrackR = dauDeuteronTrackR - std::min(dauPionTrackR, dauProtonTrackR); - registry.fill(HIST("hDiffDaughterR"), diffTrackR); - - // int daughterPionCount = 0; - // for (auto& mcparticleDaughter : mcparticle.daughters_as()) { - // if (std::abs(mcparticleDaughter.pdgCode()) == 211) { - // daughterPionCount++; - // } - // } - - // Counter for hypertriton N_gen - if (std::abs(mcparticle.y()) < 1) { - registry.fill(HIST("hMcHypertritonCounter"), 6.5); - if (MClifetime < 40) { - registry.fill(HIST("hMcHypertritonCounter"), 7.5); - if (mcparticle.pt() > 1 && mcparticle.pt() < 10) { - registry.fill(HIST("hMcHypertritonCounter"), 8.5); - } - } - } - } - } - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx b/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx deleted file mode 100644 index b8aeb1d34c3..00000000000 --- a/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx +++ /dev/null @@ -1,797 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \file hypertriton3bodyanalysis.cxx -/// \brief Standard analysis workflow for hypertriton 3-body decay -/// \author Yuanzhe Wang - -#include -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -// #include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/Vtx3BodyTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/PhysicsConstants.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using FullTracksExtIU = soa::Join; -// using FullTracksExtIU = soa::Join; // For TOF PID check -using MCLabeledTracksIU = soa::Join; - -struct hypertriton3bodyQa { - // Basic checks - HistogramRegistry registry{ - "registry", - { - {"hVtxRadius", "hVtxRadius", {HistType::kTH1F, {{1000, 0.0f, 100.0f, "cm"}}}}, - {"hVtxCosPA", "hVtxCosPA", {HistType::kTH1F, {{1000, 0.9f, 1.0f}}}}, - {"hPtProton", "hPtProton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtPionMinus", "hPtPionMinus", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtDeuteron", "hPtDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtAntiProton", "hPtAntiProton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtPionPlus", "hPtPionPlus", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtAntiDeuteron", "hPtAntiDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDCAXYProtonToPV", "hDCAXYProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAXYPionToPV", "hDCAXYPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAXYDeuteronToPV", "hDCAXYDeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAProtonToPV", "hDCAProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAPionToPV", "hDCAPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCADeuteronToPV", "hDCADeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hProtonTPCNcls", "hProtonTPCNcls", {HistType::kTH1F, {{300, 0, 300, "TPC cluster"}}}}, - {"hPionTPCNcls", "hPionTPCNcls", {HistType::kTH1F, {{300, 0, 300, "TPC cluster"}}}}, - {"hDeuteronTPCNcls", "hDeuteronTPCNcls", {HistType::kTH1F, {{300, 0, 300, "TPC cluster"}}}}, - {"hDCAVtxDau", "hDCAVtxDau", {HistType::kTH1F, {{1000, 0.0f, 10.0f, "cm^{2}"}}}}, - {"hVtxPt", "hVtxPt", {HistType::kTH1F, {{200, 0.0f, 10.0f, "p_{T}"}}}}, - {"hTOFPIDDeuteron", "hTOFPIDDeuteron", {HistType::kTH1F, {{2000, -100.0f, 100.0f}}}}, - {"hDeuTOFNsigma", "Deuteron TOF Nsigma distribution", {HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {2000, -100, 100, "TOF n#sigma"}}}}, - {"hDeuTOFNsigmaWithTPC", "Deuteron TOF Nsigma distribution", {HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {1000, -100, 100, "TOF n#sigma"}}}}, - }, - }; - - void init(InitContext const&) - { - AxisSpec massAxis = {120, 2.9f, 3.2f, "Inv. Mass (GeV/c^{2})"}; - registry.add("hMassHypertriton", "hMassHypertriton", {HistType::kTH1F, {massAxis}}); - registry.add("hMassAntiHypertriton", "hMassAntiHypertriton", {HistType::kTH1F, {massAxis}}); - // Check for selection criteria - registry.add("hDiffRVtxProton", "hDiffRVtxProton", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of proton - registry.add("hDiffRVtxPion", "hDiffRVtxPion", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of pion - registry.add("hDiffRVtxDeuteron", "hDiffRVtxDeuteron", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of deuteron - registry.add("hDiffDaughterR", "hDiffDaughterR", HistType::kTH1F, {{10000, -100, 100}}); // difference between minR of pion&proton and R of deuteron(bachelor) - } - - void process(aod::Collision const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const& /*tracks*/) - { - for (const auto& vtx : vtx3bodydatas) { - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); - - registry.fill(HIST("hVtxRadius"), vtx.vtxradius()); - registry.fill(HIST("hVtxCosPA"), vtx.vtxcosPA(collision.posX(), collision.posY(), collision.posZ())); - registry.fill(HIST("hDCAVtxDau"), vtx.dcaVtxdaughters()); - registry.fill(HIST("hVtxPt"), vtx.pt()); - registry.fill(HIST("hMassHypertriton"), vtx.mHypertriton()); - registry.fill(HIST("hMassAntiHypertriton"), vtx.mAntiHypertriton()); - if (std::abs(track2.tpcNSigmaDe()) < 5) { - registry.fill(HIST("hDeuTOFNsigmaWithTPC"), track2.tpcInnerParam() * track2.sign(), vtx.tofNSigmaBachDe()); - } - if (track2.sign() > 0) { - registry.fill(HIST("hPtProton"), track0.pt()); - registry.fill(HIST("hPtPionMinus"), track1.pt()); - registry.fill(HIST("hPtDeuteron"), track2.pt()); - registry.fill(HIST("hDCAXYProtonToPV"), vtx.dcaXYtrack0topv()); - registry.fill(HIST("hDCAXYPionToPV"), vtx.dcaXYtrack1topv()); - registry.fill(HIST("hDCAProtonToPV"), vtx.dcatrack0topv()); - registry.fill(HIST("hDCAPionToPV"), vtx.dcatrack1topv()); - registry.fill(HIST("hProtonTPCNcls"), track0.tpcNClsCrossedRows()); - registry.fill(HIST("hPionTPCNcls"), track1.tpcNClsCrossedRows()); - registry.fill(HIST("hDiffRVtxProton"), track0.x() - vtx.vtxradius()); - registry.fill(HIST("hDiffRVtxPion"), track1.x() - vtx.vtxradius()); - } else { - registry.fill(HIST("hPtPionPlus"), track0.pt()); - registry.fill(HIST("hPtAntiProton"), track1.pt()); - registry.fill(HIST("hPtAntiDeuteron"), track2.pt()); - registry.fill(HIST("hDCAXYProtonToPV"), vtx.dcaXYtrack1topv()); - registry.fill(HIST("hDCAXYPionToPV"), vtx.dcaXYtrack0topv()); - registry.fill(HIST("hDCAProtonToPV"), vtx.dcatrack1topv()); - registry.fill(HIST("hDCAPionToPV"), vtx.dcatrack0topv()); - registry.fill(HIST("hProtonTPCNcls"), track1.tpcNClsCrossedRows()); - registry.fill(HIST("hPionTPCNcls"), track0.tpcNClsCrossedRows()); - registry.fill(HIST("hDiffRVtxProton"), track1.x() - vtx.vtxradius()); - registry.fill(HIST("hDiffRVtxPion"), track0.x() - vtx.vtxradius()); - } - registry.fill(HIST("hDCAXYDeuteronToPV"), vtx.dcaXYtrack2topv()); - registry.fill(HIST("hDCADeuteronToPV"), vtx.dcatrack2topv()); - registry.fill(HIST("hDeuteronTPCNcls"), track2.tpcNClsCrossedRows()); - registry.fill(HIST("hTOFPIDDeuteron"), vtx.tofNSigmaBachDe()); - registry.fill(HIST("hDeuTOFNsigma"), track2.tpcInnerParam() * track2.sign(), vtx.tofNSigmaBachDe()); - registry.fill(HIST("hDiffRVtxDeuteron"), track2.x() - vtx.vtxradius()); - float diffTrackR = track2.x() - std::min(track0.x(), track1.x()); - registry.fill(HIST("hDiffDaughterR"), diffTrackR); - } - } -}; - -struct hypertriton3bodyAnalysis { - - Preslice perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; - - // Selection criteria - Configurable vtxcospa{"vtxcospa", 0.99, "Vtx CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable dcavtxdau{"dcavtxdau", 1.0, "DCA Vtx Daughters"}; // loose cut - Configurable dcapiontopv{"dcapiontopv", .05, "DCA Pion To PV"}; - Configurable etacut{"etacut", 0.9, "etacut"}; - Configurable rapiditycut{"rapiditycut", 1, "rapiditycut"}; - Configurable tofPIDNSigmaMin{"tofPIDNSigmaMin", -5, "tofPIDNSigmaMin"}; - Configurable tofPIDNSigmaMax{"tofPIDNSigmaMax", 5, "tofPIDNSigmaMax"}; - Configurable tpcPIDNSigmaCut{"tpcPIDNSigmaCut", 5, "tpcPIDNSigmaCut"}; - Configurable event_sel8_selection{"event_sel8_selection", true, "event selection count post sel8 cut"}; - Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; - Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; - Configurable lifetimecut{"lifetimecut", 40., "lifetimecut"}; // ct - Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; - Configurable maxProtonPt{"maxProtonPt", 5, "maxProtonPt"}; - Configurable minPionPt{"minPionPt", 0.1, "minPionPt"}; - Configurable maxPionPt{"maxPionPt", 1.2, "maxPionPt"}; - Configurable minDeuteronPt{"minDeuteronPt", 0.6, "minDeuteronPt"}; - Configurable maxDeuteronPt{"maxDeuteronPt", 10, "maxDeuteronPt"}; - Configurable minDeuteronPUseTOF{"minDeuteronPUseTOF", 1, "minDeuteronPt Enable TOF PID"}; - Configurable h3LMassLowerlimit{"h3LMassLowerlimit", 2.96, "Hypertriton mass lower limit"}; - Configurable h3LMassUpperlimit{"h3LMassUpperlimit", 3.04, "Hypertriton mass upper limit"}; - Configurable mintpcNClsproton{"mintpcNClsproton", 90, "min tpc Nclusters for proton"}; - Configurable mintpcNClspion{"mintpcNClspion", 70, "min tpc Nclusters for pion"}; - Configurable mintpcNClsdeuteron{"mintpcNClsdeuteron", 100, "min tpc Nclusters for deuteron"}; - - Configurable mcsigma{"mcsigma", 0.0015, "sigma of mc invariant mass fit"}; // obtained from MC - Configurable bachelorPdgCode{"bachelorPdgCode", 1000010020, "pdgCode of bachelor daughter"}; - Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother track"}; - - // 3sigma region for Dalitz plot - float lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; - float uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; - - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - {"hCandidatesCounter", "hCandidatesCounter", {HistType::kTH1F, {{12, 0.0f, 12.0f}}}}, - {"hMassHypertriton", "hMassHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hMassAntiHypertriton", "hMassAntiHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hMassHypertritonTotal", "hMassHypertritonTotal", {HistType::kTH1F, {{300, 2.9f, 3.2f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hPtProton", "hPtProton", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hPtPionMinus", "hPtPionMinus", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hPtDeuteron", "hPtDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hPtAntiProton", "hPtAntiProton", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hPtPionPlus", "hPtPionPlus", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hPtAntiDeuteron", "hPtAntiDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hDCAXYProtonToPV", "hDCAXYProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAXYPionToPV", "hDCAXYPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAXYDeuteronToPV", "hDCAXYDeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAProtonToPV", "hDCAProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAPionToPV", "hDCAPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCADeuteronToPV", "hDCADeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hProtonTPCNcls", "hProtonTPCNcls", {HistType::kTH1F, {{180, 0, 180, "TPC cluster"}}}}, - {"hPionTPCNcls", "hPionTPCNcls", {HistType::kTH1F, {{180, 0, 180, "TPC cluster"}}}}, - {"hDeuteronTPCNcls", "hDeuteronTPCNcls", {HistType::kTH1F, {{180, 0, 180, "TPC cluster"}}}}, - {"hVtxCosPA", "hVtxCosPA", {HistType::kTH1F, {{1000, 0.9f, 1.0f}}}}, - {"hDCAVtxDau", "hDCAVtxDau", {HistType::kTH1F, {{1000, 0.0f, 10.0f, "cm^{2}"}}}}, - {"hTOFPIDDeuteron", "hTOFPIDDeuteron", {HistType::kTH1F, {{2000, -100.0f, 100.0f}}}}, - {"hTPCPIDProton", "hTPCPIDProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hTPCPIDPion", "hTPCPIDPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hTPCPIDDeuteron", "hTPCPIDDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hProtonTPCBB", "hProtonTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hPionTPCBB", "hPionTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDeuteronTPCBB", "hDeuteronTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hProtonTPCVsPt", "hProtonTPCVsPt", {HistType::kTH2F, {{50, 0.0f, 5.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hPionTPCVsPt", "hPionTPCVsPt", {HistType::kTH2F, {{20, 0.0f, 2.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDeuteronTPCVsPt", "hDeuteronTPCVsPt", {HistType::kTH2F, {{80, 0.0f, 8.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDeuteronTOFVsPBeforeTOFCut", "hDeuteronTOFVsPBeforeTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronTOFVsPAfterTOFCut", "hDeuteronTOFVsPAfterTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - - {"hDalitz", "hDalitz", {HistType::kTH2F, {{120, 7.85, 8.45, "M^{2}(dp) (GeV^{2}/c^{4})"}, {60, 1.1, 1.4, "M^{2}(p#pi) (GeV^{2}/c^{4})"}}}}, - {"h3dMassHypertriton", "h3dMassHypertriton", {HistType::kTH3F, {{20, 0.0f, 100.0f, "Cent (%)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"h3dMassAntiHypertriton", "h3dMassAntiHypertriton", {HistType::kTH3F, {{20, 0.0f, 100.0f, "Cent (%)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"h3dTotalHypertriton", "h3dTotalHypertriton", {HistType::kTH3F, {{50, 0, 50, "ct(cm)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - - {"hDeuteronTOFVsPBeforeTOFCutSig", "hDeuteronTOFVsPBeforeTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronTOFVsPAfterTOFCutSig", "hDeuteronTOFVsPAfterTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"h3dTotalTrueHypertriton", "h3dTotalTrueHypertriton", {HistType::kTH3F, {{50, 0, 50, "ct(cm)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - // For TOF PID check - /*{"hDeuteronDefaultTOFVsPBeforeTOFCut", "hDeuteronDefaultTOFVsPBeforeTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronDefaultTOFVsPAtferTOFCut", "hDeuteronDefaultTOFVsPAtferTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronDefaultTOFVsPBeforeTOFCutSig", "hDeuteronDefaultTOFVsPBeforeTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronDefaultTOFVsPAfterTOFCutSig", "hDeuteronDefaultTOFVsPAfterTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}},*/ - }, - }; - - //------------------------------------------------------------------ - // Fill stats histograms - enum vtxstep { kCandAll = 0, - kCandDauEta, - kCandDauPt, - kCandTPCNcls, - kCandTPCPID, - kCandTOFPID, - kCandDcaToPV, - kCandRapidity, - kCandct, - kCandCosPA, - kCandDcaDau, - kCandInvMass, - kNCandSteps }; - - struct { - std::array candstats; - std::array truecandstats; - } statisticsRegistry; - - void resetHistos() - { - for (int ii = 0; ii < kNCandSteps; ii++) { - statisticsRegistry.candstats[ii] = 0; - statisticsRegistry.truecandstats[ii] = 0; - } - } - void FillCandCounter(int kn, bool istrue = false) - { - statisticsRegistry.candstats[kn]++; - if (istrue) { - statisticsRegistry.truecandstats[kn]++; - } - } - void fillHistos() - { - for (int ii = 0; ii < kNCandSteps; ii++) { - registry.fill(HIST("hCandidatesCounter"), ii, statisticsRegistry.candstats[ii]); - if (doprocessMC == true) { - registry.fill(HIST("hTrueHypertritonCounter"), ii, statisticsRegistry.truecandstats[ii]); - } - } - } - - ConfigurableAxis dcaBinning{"dca-binning", {200, 0.0f, 1.0f}, ""}; - ConfigurableAxis ptBinning{"pt-binning", {200, 0.0f, 10.0f}, ""}; - - void init(InitContext const&) - { - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(1, "total"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(2, "sel8"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(3, "vertexZ"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(4, "has Candidate"); - - if (doprocessMC == true) { - registry.add("hTrueHypertritonCounter", "hTrueHypertritonCounter", HistType::kTH1F, {{12, 0.0f, 12.0f}}); - auto hGeneratedHypertritonCounter = registry.add("hGeneratedHypertritonCounter", "hGeneratedHypertritonCounter", HistType::kTH1F, {{2, 0.0f, 2.0f}}); - hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(1, "Total"); - hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(2, "3-body decay"); - registry.add("hPtGeneratedHypertriton", "hPtGeneratedHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); - registry.add("hctGeneratedHypertriton", "hctGeneratedHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); - registry.add("hEtaGeneratedHypertriton", "hEtaGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - registry.add("hRapidityGeneratedHypertriton", "hRapidityGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - registry.add("hPtGeneratedAntiHypertriton", "hPtGeneratedAntiHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); - registry.add("hctGeneratedAntiHypertriton", "hctGeneratedAntiHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); - registry.add("hEtaGeneratedAntiHypertriton", "hEtaGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - registry.add("hRapidityGeneratedAntiHypertriton", "hRapidityGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); - } - - TString CandCounterbinLabel[kNCandSteps] = {"Total", "TrackEta", "DauPt", "TPCNcls", "TPCPID", "d TOFPID", "PionDcatoPV", "MomRapidity", "Lifetime", "VtxCosPA", "VtxDcaDau", "InvMass"}; - for (int i{0}; i < kNCandSteps; i++) { - registry.get(HIST("hCandidatesCounter"))->GetXaxis()->SetBinLabel(i + 1, CandCounterbinLabel[i]); - if (doprocessMC == true) { - registry.get(HIST("hTrueHypertritonCounter"))->GetXaxis()->SetBinLabel(i + 1, CandCounterbinLabel[i]); - } - } - } - - //------------------------------------------------------------------ - // Selections for candidates - template - bool SelectCand(TCollisionTable const& collision, TCandTable const& candData, TTrackTable const& trackProton, TTrackTable const& trackPion, TTrackTable const& trackDeuteron, bool isMatter, bool isTrueCand = false, double MClifetime = -1, double lPt = -1) - { - FillCandCounter(kCandAll, isTrueCand); - - // Selection on daughters - if (std::abs(trackProton.eta()) > etacut || std::abs(trackPion.eta()) > etacut || std::abs(trackDeuteron.eta()) > etacut) { - return false; - } - FillCandCounter(kCandDauEta, isTrueCand); - - if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { - return false; - } - FillCandCounter(kCandDauPt, isTrueCand); - - if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { - return false; - } - FillCandCounter(kCandTPCNcls, isTrueCand); - - if (std::abs(trackProton.tpcNSigmaPr()) > tpcPIDNSigmaCut || std::abs(trackPion.tpcNSigmaPi()) > tpcPIDNSigmaCut || std::abs(trackDeuteron.tpcNSigmaDe()) > tpcPIDNSigmaCut) { - return false; - } - FillCandCounter(kCandTPCPID, isTrueCand); - - // registry.fill(HIST("hDeuteronDefaultTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - if (isTrueCand) { - // registry.fill(HIST("hDeuteronDefaultTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - } - if ((candData.tofNSigmaBachDe() < tofPIDNSigmaMin || candData.tofNSigmaBachDe() > tofPIDNSigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { - return false; - } - FillCandCounter(kCandTOFPID, isTrueCand); - // registry.fill(HIST("hDeuteronDefaultTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - registry.fill(HIST("hDeuteronTOFVsPAfterTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - if (isTrueCand) { - // registry.fill(HIST("hDeuteronDefaultTOFVsPAfterTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - registry.fill(HIST("hDeuteronTOFVsPAfterTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - } - - double dcapion = isMatter ? candData.dcatrack1topv() : candData.dcatrack0topv(); - if (std::abs(dcapion) < dcapiontopv) { - return false; - } - FillCandCounter(kCandDcaToPV, isTrueCand); - - // Selection on candidate hypertriton - if (std::abs(candData.yHypertriton()) > rapiditycut) { - return false; - } - FillCandCounter(kCandRapidity, isTrueCand); - - double ct = candData.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassHyperTriton; - if (ct > lifetimecut) { - return false; - } - FillCandCounter(kCandct, isTrueCand); - - double cospa = candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()); - if (cospa < vtxcospa) { - return false; - } - FillCandCounter(kCandCosPA, isTrueCand); - - if (candData.dcaVtxdaughters() > dcavtxdau) { - return false; - } - FillCandCounter(kCandDcaDau, isTrueCand); - - if ((isMatter && candData.mHypertriton() > h3LMassLowerlimit && candData.mHypertriton() < h3LMassUpperlimit)) { - // Hypertriton - registry.fill(HIST("hPtProton"), trackProton.pt()); - registry.fill(HIST("hPtPionMinus"), trackPion.pt()); - registry.fill(HIST("hPtDeuteron"), trackDeuteron.pt()); - registry.fill(HIST("hDCAXYProtonToPV"), candData.dcaXYtrack0topv()); - registry.fill(HIST("hDCAXYPionToPV"), candData.dcaXYtrack1topv()); - registry.fill(HIST("hDCAProtonToPV"), candData.dcatrack0topv()); - registry.fill(HIST("hDCAPionToPV"), candData.dcatrack1topv()); - - registry.fill(HIST("hMassHypertriton"), candData.mHypertriton()); - registry.fill(HIST("hMassHypertritonTotal"), candData.mHypertriton()); - registry.fill(HIST("h3dMassHypertriton"), 0., candData.pt(), candData.mHypertriton()); // collision.centV0M() instead of 0. once available - registry.fill(HIST("h3dTotalHypertriton"), ct, candData.pt(), candData.mHypertriton()); - if (candData.mHypertriton() > lowersignallimit && candData.mHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); - } - if (isTrueCand) { - registry.fill(HIST("h3dTotalTrueHypertriton"), MClifetime, lPt, candData.mHypertriton()); - } - } else if ((!isMatter && candData.mAntiHypertriton() > h3LMassLowerlimit && candData.mAntiHypertriton() < h3LMassUpperlimit)) { - // AntiHypertriton - registry.fill(HIST("hPtAntiProton"), trackProton.pt()); - registry.fill(HIST("hPtPionPlus"), trackPion.pt()); - registry.fill(HIST("hPtAntiDeuteron"), trackDeuteron.pt()); - registry.fill(HIST("hDCAXYProtonToPV"), candData.dcaXYtrack1topv()); - registry.fill(HIST("hDCAXYPionToPV"), candData.dcaXYtrack0topv()); - registry.fill(HIST("hDCAProtonToPV"), candData.dcatrack1topv()); - registry.fill(HIST("hDCAPionToPV"), candData.dcatrack0topv()); - - registry.fill(HIST("hMassAntiHypertriton"), candData.mAntiHypertriton()); - registry.fill(HIST("hMassHypertritonTotal"), candData.mAntiHypertriton()); - registry.fill(HIST("h3dMassAntiHypertriton"), 0., candData.pt(), candData.mAntiHypertriton()); // collision.centV0M() instead of 0. once available - registry.fill(HIST("h3dTotalHypertriton"), ct, candData.pt(), candData.mAntiHypertriton()); - if (candData.mAntiHypertriton() > lowersignallimit && candData.mAntiHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); - } - if (isTrueCand) { - registry.fill(HIST("h3dTotalTrueHypertriton"), MClifetime, lPt, candData.mHypertriton()); - } - } else { - return false; - } - - FillCandCounter(kCandInvMass, isTrueCand); - - registry.fill(HIST("hDCAXYDeuteronToPV"), candData.dcaXYtrack2topv()); - registry.fill(HIST("hDCADeuteronToPV"), candData.dcatrack2topv()); - registry.fill(HIST("hVtxCosPA"), candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ())); - registry.fill(HIST("hDCAVtxDau"), candData.dcaVtxdaughters()); - registry.fill(HIST("hProtonTPCNcls"), trackProton.tpcNClsCrossedRows()); - registry.fill(HIST("hPionTPCNcls"), trackPion.tpcNClsCrossedRows()); - registry.fill(HIST("hDeuteronTPCNcls"), trackDeuteron.tpcNClsCrossedRows()); - registry.fill(HIST("hTPCPIDProton"), trackProton.tpcNSigmaPr()); - registry.fill(HIST("hTPCPIDPion"), trackPion.tpcNSigmaPi()); - registry.fill(HIST("hTPCPIDDeuteron"), trackDeuteron.tpcNSigmaDe()); - registry.fill(HIST("hProtonTPCBB"), trackProton.sign() * trackProton.p(), trackProton.tpcSignal()); - registry.fill(HIST("hPionTPCBB"), trackPion.sign() * trackPion.p(), trackPion.tpcSignal()); - registry.fill(HIST("hDeuteronTPCBB"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tpcSignal()); - registry.fill(HIST("hProtonTPCVsPt"), trackProton.pt(), trackProton.tpcNSigmaPr()); - registry.fill(HIST("hPionTPCVsPt"), trackProton.pt(), trackPion.tpcNSigmaPi()); - registry.fill(HIST("hDeuteronTPCVsPt"), trackDeuteron.pt(), trackDeuteron.tpcNSigmaDe()); - registry.fill(HIST("hTOFPIDDeuteron"), candData.tofNSigmaBachDe()); - - return true; - } - - //------------------------------------------------------------------ - // Analysis process for a single candidate - template - void CandidateAnalysis(TCollisionTable const& collision, TCandTable const& candData, bool& if_hasvtx, bool isTrueCand = false, double MClifetime = -1, double lPt = -1) - { - - auto track0 = candData.template track0_as(); - auto track1 = candData.template track1_as(); - auto track2 = candData.template track2_as(); - - bool isMatter = track2.sign() > 0; - - auto& trackProton = isMatter ? track0 : track1; - auto& trackPion = isMatter ? track1 : track0; - auto& trackDeuteron = track2; - - if (SelectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, MClifetime, lPt)) { - if_hasvtx = true; - } - } - - //------------------------------------------------------------------ - // collect information for generated hypertriton (should be called after event selection) - void GetGeneratedH3LInfo(aod::McParticles const& particlesMC) - { - for (const auto& mcparticle : particlesMC) { - if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { - continue; - } - registry.fill(HIST("hGeneratedHypertritonCounter"), 0.5); - - bool haveProton = false, havePionPlus = false, haveDeuteron = false; - bool haveAntiProton = false, havePionMinus = false, haveAntiDeuteron = false; - double MClifetime = -1; - for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == 2212) - haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) - havePionPlus = true; - if (mcparticleDaughter.pdgCode() == -211) - havePionMinus = true; - if (mcparticleDaughter.pdgCode() == bachelorPdgCode) { - haveDeuteron = true; - MClifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - } - if (mcparticleDaughter.pdgCode() == -bachelorPdgCode) { - haveAntiDeuteron = true; - MClifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - } - } - if (haveProton && havePionMinus && haveDeuteron && mcparticle.pdgCode() == motherPdgCode) { - registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); - registry.fill(HIST("hPtGeneratedHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedHypertriton"), MClifetime); - registry.fill(HIST("hEtaGeneratedHypertriton"), mcparticle.eta()); - registry.fill(HIST("hRapidityGeneratedHypertriton"), mcparticle.y()); - } else if (haveAntiProton && havePionPlus && haveAntiDeuteron && mcparticle.pdgCode() == -motherPdgCode) { - registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); - registry.fill(HIST("hPtGeneratedAntiHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedAntiHypertriton"), MClifetime); - registry.fill(HIST("hEtaGeneratedAntiHypertriton"), mcparticle.eta()); - registry.fill(HIST("hRapidityGeneratedAntiHypertriton"), mcparticle.y()); - } - } - } - - //------------------------------------------------------------------ - // process real data analysis - void processData(soa::Join::iterator const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const& /*tracks*/) - { - registry.fill(HIST("hEventCounter"), 0.5); - if (event_sel8_selection && !collision.sel8()) { - return; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm - return; - } - registry.fill(HIST("hEventCounter"), 2.5); - - bool if_hasvtx = false; - - for (const auto& vtx : vtx3bodydatas) { - CandidateAnalysis(collision, vtx, if_hasvtx); - } - - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); - fillHistos(); - resetHistos(); - } - PROCESS_SWITCH(hypertriton3bodyAnalysis, processData, "Real data analysis", true); - - //------------------------------------------------------------------ - // process mc analysis - void processMC(soa::Join const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, aod::McParticles const& particlesMC, MCLabeledTracksIU const& /*tracks*/) - { - GetGeneratedH3LInfo(particlesMC); - - for (const auto& collision : collisions) { - registry.fill(HIST("hEventCounter"), 0.5); - if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm - continue; - } - registry.fill(HIST("hEventCounter"), 2.5); - - bool if_hasvtx = false; - auto vtxsthiscol = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - - for (const auto& vtx : vtxsthiscol) { - // int lLabel = -1; - int lPDG = -1; - float lPt = -1; - double MClifetime = -1; - bool isTrueCand = false; - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); - if (track0.has_mcParticle() && track1.has_mcParticle() && track2.has_mcParticle()) { - auto lMCTrack0 = track0.mcParticle_as(); - auto lMCTrack1 = track1.mcParticle_as(); - auto lMCTrack2 = track2.mcParticle_as(); - if (lMCTrack0.has_mothers() && lMCTrack1.has_mothers() && lMCTrack2.has_mothers()) { - for (const auto& lMother0 : lMCTrack0.mothers_as()) { - for (const auto& lMother1 : lMCTrack1.mothers_as()) { - for (const auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - // lLabel = lMother1.globalIndex(); - lPt = lMother1.pt(); - lPDG = lMother1.pdgCode(); - if ((lPDG == motherPdgCode && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == bachelorPdgCode) || - (lPDG == -motherPdgCode && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -bachelorPdgCode)) { - isTrueCand = true; - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); - } - } - } - } - } - } - } - - CandidateAnalysis(collision, vtx, if_hasvtx, isTrueCand, MClifetime, lPt); - } - - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); - fillHistos(); - resetHistos(); - } - } - PROCESS_SWITCH(hypertriton3bodyAnalysis, processMC, "MC analysis", false); -}; - -// check vtx3body with mclabels -struct hypertriton3bodyLabelCheck { - - Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; - Configurable event_posZ_selection{"event_posZ_selection", false, "event selection count post poZ cut"}; - Configurable tpcPIDNSigmaCut{"tpcPIDNSigmaCut", 5, "tpcPIDNSigmaCut"}; - Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother track"}; - - HistogramRegistry registry{"registry", {}}; - - void init(InitContext const&) - { - if (doprocessData == false) { - auto hLabeledVtxCounter = registry.add("hLabeledVtxCounter", "hLabeledVtxCounter", HistType::kTH1F, {{3, 0.0f, 3.0f}}); - hLabeledVtxCounter->GetXaxis()->SetBinLabel(1, "Readin"); - hLabeledVtxCounter->GetXaxis()->SetBinLabel(2, "TrueMCH3L"); - hLabeledVtxCounter->GetXaxis()->SetBinLabel(3, "Nonrepetitive"); - registry.add("hMassTrueH3L", "hMassTrueH3L", HistType::kTH1F, {{80, 2.96f, 3.04f}}); - registry.add("hMassTrueH3LMatter", "hMassTrueH3LMatter", HistType::kTH1F, {{80, 2.96f, 3.04f}}); - registry.add("hMassTrueH3LAntiMatter", "hMassTrueH3LAntiMatter", HistType::kTH1F, {{80, 2.96f, 3.04f}}); - auto hPIDCounter = registry.add("hPIDCounter", "hPIDCounter", HistType::kTH1F, {{6, 0.0f, 6.0f}}); - hPIDCounter->GetXaxis()->SetBinLabel(1, "H3L Proton PID > 5"); - hPIDCounter->GetXaxis()->SetBinLabel(2, "H3L Pion PID > 5"); - hPIDCounter->GetXaxis()->SetBinLabel(3, "H3L Deuteron PID > 5"); - hPIDCounter->GetXaxis()->SetBinLabel(4, "#bar{H3L} Proton PID > 5"); - hPIDCounter->GetXaxis()->SetBinLabel(5, "#bar{H3L} Pion PID > 5"); - hPIDCounter->GetXaxis()->SetBinLabel(6, "#bar{H3L} Deuteron PID > 5"); - auto hHypertritonCounter = registry.add("hHypertritonCounter", "hHypertritonCounter", HistType::kTH1F, {{4, 0.0f, 4.0f}}); - hHypertritonCounter->GetXaxis()->SetBinLabel(1, "H3L"); - hHypertritonCounter->GetXaxis()->SetBinLabel(2, "H3L daughters pass PID"); - hHypertritonCounter->GetXaxis()->SetBinLabel(3, "#bar{H3L}"); - hHypertritonCounter->GetXaxis()->SetBinLabel(4, "#bar{H3L} daughters pass PID"); - auto hDecay3BodyCounter = registry.add("hDecay3BodyCounter", "hDecay3BodyCounter", HistType::kTH1F, {{5, 0.0f, 5.0f}}); - hDecay3BodyCounter->GetXaxis()->SetBinLabel(1, "Total"); - hDecay3BodyCounter->GetXaxis()->SetBinLabel(2, "True H3L"); - hDecay3BodyCounter->GetXaxis()->SetBinLabel(3, "Unduplicated H3L"); - hDecay3BodyCounter->GetXaxis()->SetBinLabel(4, "Correct collision"); - hDecay3BodyCounter->GetXaxis()->SetBinLabel(5, "Same ColID for daughters"); - registry.add("hDiffRVtxProton", "hDiffRVtxProton", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of proton - registry.add("hDiffRVtxPion", "hDiffRVtxPion", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of pion - registry.add("hDiffRVtxDeuteron", "hDiffRVtxDeuteron", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of deuteron - } - } - - struct Indexdaughters { // check duplicated paired daughters - int64_t index0; - int64_t index1; - int64_t index2; - bool operator==(const Indexdaughters& t) const - { - return (this->index0 == t.index0 && this->index1 == t.index1 && this->index2 == t.index2); - } - }; - - void processData(soa::Join::iterator const&) - { - // dummy function - } - PROCESS_SWITCH(hypertriton3bodyLabelCheck, processData, "Donot check MC label tables", true); - - void processCheckLabel(soa::Join::iterator const& collision, aod::Decay3Bodys const& decay3bodys, soa::Join const& vtx3bodydatas, MCLabeledTracksIU const& /*tracks*/, aod::McParticles const& /*particlesMC*/, aod::McCollisions const& /*mcCollisions*/) - { - // check the decay3body table - std::vector set_pair; - for (const auto& d3body : decay3bodys) { - registry.fill(HIST("hDecay3BodyCounter"), 0.5); - auto lTrack0 = d3body.track0_as(); - auto lTrack1 = d3body.track1_as(); - auto lTrack2 = d3body.track2_as(); - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - continue; - } - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - continue; - } - - for (const auto& lMother0 : lMCTrack0.mothers_as()) { - for (const auto& lMother1 : lMCTrack1.mothers_as()) { - for (const auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - registry.fill(HIST("hDecay3BodyCounter"), 1.5); - // duplicated daughters check - Indexdaughters temp = {lMCTrack0.globalIndex(), lMCTrack1.globalIndex(), lMCTrack2.globalIndex()}; - auto p = std::find(set_pair.begin(), set_pair.end(), temp); - if (p == set_pair.end()) { - set_pair.push_back(temp); - registry.fill(HIST("hDecay3BodyCounter"), 2.5); - if (lMother0.mcCollisionId() == collision.mcCollisionId()) { - registry.fill(HIST("hDecay3BodyCounter"), 3.5); - if (lTrack0.collisionId() == lTrack1.collisionId() && lTrack0.collisionId() == lTrack2.collisionId()) { - registry.fill(HIST("hDecay3BodyCounter"), 4.5); - } - } - } - } - } - } - } - } - - if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { - return; - } - - if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm - return; - } - - std::vector set_mothertrack; - for (const auto& vtx : vtx3bodydatas) { - registry.fill(HIST("hLabeledVtxCounter"), 0.5); - if (vtx.mcParticleId() != -1) { - auto mcparticle = vtx.mcParticle_as(); - auto lTrack0 = vtx.track0_as(); - auto lTrack1 = vtx.track1_as(); - auto lTrack2 = vtx.track2_as(); - if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { - continue; - } - registry.fill(HIST("hLabeledVtxCounter"), 1.5); - registry.fill(HIST("hDiffRVtxDeuteron"), lTrack2.x() - vtx.vtxradius()); - if (mcparticle.pdgCode() > 0) { - registry.fill(HIST("hHypertritonCounter"), 0.5); - registry.fill(HIST("hMassTrueH3L"), vtx.mHypertriton()); - registry.fill(HIST("hMassTrueH3LMatter"), vtx.mHypertriton()); - registry.fill(HIST("hDiffRVtxProton"), lTrack0.x() - vtx.vtxradius()); - registry.fill(HIST("hDiffRVtxPion"), lTrack1.x() - vtx.vtxradius()); - auto p = std::find(set_mothertrack.begin(), set_mothertrack.end(), mcparticle.globalIndex()); - if (p == set_mothertrack.end()) { - set_mothertrack.push_back(mcparticle.globalIndex()); - registry.fill(HIST("hLabeledVtxCounter"), 2.5); - } - if (std::abs(lTrack0.tpcNSigmaPr()) > tpcPIDNSigmaCut) { - registry.fill(HIST("hPIDCounter"), 0.5); - } - if (std::abs(lTrack1.tpcNSigmaPi()) > tpcPIDNSigmaCut) { - registry.fill(HIST("hPIDCounter"), 1.5); - } - if (std::abs(lTrack2.tpcNSigmaDe()) > tpcPIDNSigmaCut) { - registry.fill(HIST("hPIDCounter"), 2.5); - } - if (std::abs(lTrack0.tpcNSigmaPr()) < tpcPIDNSigmaCut && std::abs(lTrack1.tpcNSigmaPi()) < tpcPIDNSigmaCut && std::abs(lTrack2.tpcNSigmaDe()) < tpcPIDNSigmaCut) { - registry.fill(HIST("hHypertritonCounter"), 1.5); - } - } else { - registry.fill(HIST("hHypertritonCounter"), 2.5); - registry.fill(HIST("hMassTrueH3L"), vtx.mAntiHypertriton()); - registry.fill(HIST("hMassTrueH3LAntiMatter"), vtx.mAntiHypertriton()); - registry.fill(HIST("hDiffRVtxProton"), lTrack1.x() - vtx.vtxradius()); - registry.fill(HIST("hDiffRVtxPion"), lTrack0.x() - vtx.vtxradius()); - auto p = std::find(set_mothertrack.begin(), set_mothertrack.end(), mcparticle.globalIndex()); - if (p == set_mothertrack.end()) { - set_mothertrack.push_back(mcparticle.globalIndex()); - registry.fill(HIST("hLabeledVtxCounter"), 2.5); - } - if (std::abs(lTrack0.tpcNSigmaPi()) > tpcPIDNSigmaCut) { - registry.fill(HIST("hPIDCounter"), 4.5); - } - if (std::abs(lTrack1.tpcNSigmaPr()) > tpcPIDNSigmaCut) { - registry.fill(HIST("hPIDCounter"), 3.5); - } - if (std::abs(lTrack2.tpcNSigmaDe()) > tpcPIDNSigmaCut) { - registry.fill(HIST("hPIDCounter"), 5.5); - } - if (std::abs(lTrack0.tpcNSigmaPi()) < tpcPIDNSigmaCut && std::abs(lTrack1.tpcNSigmaPr()) < tpcPIDNSigmaCut && std::abs(lTrack2.tpcNSigmaDe()) < tpcPIDNSigmaCut) { - registry.fill(HIST("hHypertritonCounter"), 3.5); - } - } - } - } - } - PROCESS_SWITCH(hypertriton3bodyLabelCheck, processCheckLabel, "Check MC label tables", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/Utils/decay3bodyBuilderHelper.h b/PWGLF/Utils/decay3bodyBuilderHelper.h index 1588acb1717..d84cf4fbbca 100644 --- a/PWGLF/Utils/decay3bodyBuilderHelper.h +++ b/PWGLF/Utils/decay3bodyBuilderHelper.h @@ -112,15 +112,10 @@ class decay3bodyBuilderHelper fitterV0.setMaxChi2(1e9); fitterV0.setUseAbsDCA(true); - // LUT has to be loaded later - lut = nullptr; - fitter3body.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrLUT); - // mag field has to be set later fitter3body.setBz(-999.9f); // will NOT make sense if not changed }; - o2::base::MatLayerCylSet* lut = nullptr; // material LUT for DCA fitter o2::vertexing::DCAFitterN<2> fitterV0; // 2-prong o2 dca fitter o2::vertexing::DCAFitterN<3> fitter3body; // 3-prong o2 dca fitter @@ -590,7 +585,7 @@ class decay3bodyBuilderHelper // caluclate covariance matrices if (calculateCovariance) { // candidate covariance matrix - o2::gpu::gpustd::array covKF; + std::array covKF; for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) covKF[i] = KFH3L.GetCovariance(i); decay3body.covariance[i] = covKF[i]; From 8a186f897485c84ef6d4a768cbc1f20a5b932c87 Mon Sep 17 00:00:00 2001 From: creetz16 Date: Mon, 26 May 2025 18:27:04 +0200 Subject: [PATCH 5/7] Fixes --- .../Nuspex/decay3bodybuilder.cxx | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index b6ccb0ffa95..cba3580f0cd 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -75,7 +75,7 @@ static const std::vector tableNames{ "Vtx3BodyCovs", "McVtx3BodyDatas"}; -static constexpr int nTablesConst = 5; +static constexpr int nTablesConst = 4; static const std::vector parameterNames{"enable"}; static const int defaultParameters[nTablesConst][nParameters]{ @@ -373,7 +373,7 @@ struct decay3bodyBuilder { // print base cuts LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); - LOGF(info, "-~> max daughter eta ..............: %i", decay3bodyBuilderOpts.maxEtaDaughters.value); + LOGF(info, "-~> max daughter eta ..............: %f", decay3bodyBuilderOpts.maxEtaDaughters.value); LOGF(info, "-~> min TPC ncls proton ...........: %i", decay3bodyBuilderOpts.minTPCNClProton.value); LOGF(info, "-~> min TPC ncls pion .............: %i", decay3bodyBuilderOpts.minTPCNClPion.value); LOGF(info, "-~> min TPC ncls bach .............: %i", decay3bodyBuilderOpts.minTPCNClDeuteron.value); @@ -403,20 +403,20 @@ struct decay3bodyBuilder { LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); // bookkeeping histograms - auto h = registry.add("hTableBuildingStatistics", "hTableBuildingStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); - auto h2 = registry.add("hInputStatistics", "hInputStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + auto h = registry.add("Counters/hTableBuildingStatistics", "hTableBuildingStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + auto h2 = registry.add("Counters/hInputStatistics", "hInputStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); h2->SetTitle("Input table sizes"); // configure tables to generate for (int i = 0; i < nTables; i++) { h->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); h2->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); - h->SetBinContent(i + 1, -1); // mark all as disabled to start + h->SetBinContent(i + 1, 0); // mark all as disabled to start int f = enabledTables->get(tableNames[i].c_str(), "enable"); if (f == 1) { mEnabledTables[i] = 1; - h->SetBinContent(i + 1, 0); // mark enabled + h->SetBinContent(i + 1, 1); // mark enabled } } @@ -441,6 +441,7 @@ struct decay3bodyBuilder { registry.add("QA/Tracks/hTrackProtonHasTPC", "hTrackProtonHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); registry.add("QA/Tracks/hTrackPionHasTPC", "hTrackPionHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); registry.add("QA/Tracks/hTrackDeuteronHasTPC", "hTrackDeuteronHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackDeuteronITSClusSizes", "hTrackDeuteronITSClusSizes", HistType::kTH1F, {{10, 0., 10., "ITS cluster sizes"}}); registry.add("QA/Tracks/hTrackProtonTPCPID", "hTrackProtonTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); registry.add("QA/Tracks/hTrackPionTPCPID", "hTrackPionTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); registry.add("QA/Tracks/hTrackDeuteronTPCPID", "hTrackDeuteronTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); @@ -647,6 +648,7 @@ struct decay3bodyBuilder { TMCCollisions const& mcCollisions) { if (!(mEnabledTables[kVtx3BodyDatas] || mEnabledTables[kMcVtx3BodyDatas])) { + LOG(info) << "No request for candidate analysis table in place, skipping candidate building." << std::endl; return; // don't do if no request for decay3bodys in place } @@ -704,12 +706,12 @@ struct decay3bodyBuilder { isGoodCollision[collision.mcCollisionId()] = true; } } - } + } // loop over collisions int nDecay3Bodys = 0; // Loop over all decay3bodys in same time frame - registry.fill(HIST("hInputStatistics"), kVtx3BodyDatas, decay3bodys.size()); + registry.fill(HIST("Counters/hInputStatistics"), kVtx3BodyDatas, decay3bodys.size()); int lastRunNumber = -1; for (const auto& decay3body : decay3bodys) { // skip decay3body without assigned collision @@ -1092,7 +1094,7 @@ struct decay3bodyBuilder { products.decay3bodyindices(helper.decay3body.decay3bodyID, helper.decay3body.protonID, helper.decay3body.pionID, helper.decay3body.deuteronID, helper.decay3body.collisionID); - registry.fill(HIST("hTableBuildingStatistics"), kDecay3BodyIndices); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kDecay3BodyIndices); } if (mEnabledTables[kVtx3BodyDatas]) { products.vtx3bodydatas(helper.decay3body.sign, @@ -1113,14 +1115,14 @@ struct decay3bodyBuilder { helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron helper.decay3body.pidForTrackingDeuteron); - registry.fill(HIST("hTableBuildingStatistics"), kVtx3BodyDatas); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kVtx3BodyDatas); } if (mEnabledTables[kVtx3BodyCovs]) { products.vtx3bodycovs(helper.decay3body.covProton, helper.decay3body.covPion, helper.decay3body.covDeuteron, helper.decay3body.covariance); - registry.fill(HIST("hTableBuildingStatistics"), kVtx3BodyCovs); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kVtx3BodyCovs); } if (mEnabledTables[kMcVtx3BodyDatas]) { products.mcvtx3bodydatas(helper.decay3body.sign, @@ -1153,7 +1155,7 @@ struct decay3bodyBuilder { this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, this3BodyMCInfo.isDeuteronPrimary, this3BodyMCInfo.survivedEventSel); - registry.fill(HIST("hTableBuildingStatistics"), kMcVtx3BodyDatas); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kMcVtx3BodyDatas); } } @@ -1256,6 +1258,7 @@ struct decay3bodyBuilder { { // initialise CCDB from BCs if (!initCCDB(bcs, collisions)) { + LOG(info) << "CCDB initialisation failed, skipping candidate building." << std::endl; return; } @@ -1333,6 +1336,7 @@ struct decay3bodyBuilder { { // initialise CCDB from BCs if (!initCCDB(bcs, collisions)) { + LOG(info) << "CCDB initialisation failed, skipping candidate building." << std::endl; return; } From f3dd51e8ba9c0053b6800c4592be704ebc12fac8 Mon Sep 17 00:00:00 2001 From: creetz16 Date: Sun, 8 Jun 2025 13:17:00 +0200 Subject: [PATCH 6/7] Fixes for runtime errors --- .../Nuspex/decay3bodybuilder.cxx | 57 +++++++++---------- .../Nuspex/reduced3bodyCreator.cxx | 24 +++++--- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index cba3580f0cd..dc452692767 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -183,10 +183,10 @@ struct decay3bodyBuilder { std::string prefix = "mixingOpts"; Configurable n3bodyMixing{"n3bodyMixing", 0, "Number of decay3bodys to mix: 0 - value set to maximum bin entry in hDecay3BodyRadiusPhi, > 0 - manual setting"}; Configurable mixingType{"mixingType", 0, "0: mix V0 from one event with bachelor from another, 1: mix pion and bachelor from one event with proton from another, 1: mix proton and bachelor from one event with pion from another "}; - ConfigurableAxis bins3BodyRadius{"bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 2.0f, 4.0f, 7.0f, 10.0f, 14.0f, 18.0f, 22.0f, 30.0f, 40.0f}, "Mixing bins - 3body radius"}; - ConfigurableAxis bins3BodyPhi{"bins3BodyPhi", {VARIABLE_WIDTH, -180 * TMath::Pi() / 180, -120 * TMath::Pi() / 180, -60 * TMath::Pi() / 180, 0, 60 * TMath::Pi() / 180, 120 * TMath::Pi() / 180, 180 * TMath::Pi() / 180}, "Mixing bins - 3body phi (rad)"}; - ConfigurableAxis bins3BodyPhiDegree{"bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi (degree)"}; - ConfigurableAxis bins3BodyPosZ{"bins3BodyPosZ", {VARIABLE_WIDTH, -500.0f, -200.0f, -100.0f, -70.0f, -60.0f, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -20.0f, -15.0f, -13.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f, 13.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f, 60.0f, 70.0f, 100.0f, 200.0f, 500.0f}, "3body SV z position"}; + ConfigurableAxis bins3BodyRadius{"mixingOpts.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 2.0f, 4.0f, 7.0f, 10.0f, 14.0f, 18.0f, 22.0f, 30.0f, 40.0f}, "Mixing bins - 3body radius"}; + ConfigurableAxis bins3BodyPhi{"mixingOpts.bins3BodyPhi", {VARIABLE_WIDTH, -180 * TMath::Pi() / 180, -120 * TMath::Pi() / 180, -60 * TMath::Pi() / 180, 0, 60 * TMath::Pi() / 180, 120 * TMath::Pi() / 180, 180 * TMath::Pi() / 180}, "Mixing bins - 3body phi (rad)"}; + ConfigurableAxis bins3BodyPhiDegree{"mixingOpts.bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi (degree)"}; + ConfigurableAxis bins3BodyPosZ{"mixingOpts.bins3BodyPosZ", {VARIABLE_WIDTH, -500.0f, -200.0f, -100.0f, -70.0f, -60.0f, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -20.0f, -15.0f, -13.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f, 13.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f, 60.0f, 70.0f, 100.0f, 200.0f, 500.0f}, "3body SV z position"}; Configurable selectPVPosZ3bodyMixing{"selectPVPosZ3bodyMixing", true, "Select same pvPosZ events in case of 3body mixing"}; Configurable maxDeltaPVPosZ3bodyMixing{"maxDeltaPVPosZ3bodyMixing", 1., "max difference between PV z position in case of 3body mixing"}; // SVertexer selections @@ -464,14 +464,14 @@ struct decay3bodyBuilder { } if (doprocessRealDataReduced3bodyMixing == true) { - auto h3bodyCombinationCounter = registry.add("EM/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + auto h3bodyCombinationCounter = registry.add("Mixing/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "not same collision"); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "collision VtxZ"); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "bach sign/ID"); h3bodyCombinationCounter->LabelsOption("v"); - registry.add("EM/hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}); - registry.add("EM/hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {mixingOpts.bins3BodyPosZ}); + registry.add("Mixing/hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}); + registry.add("Mixing/hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {mixingOpts.bins3BodyPosZ}); } } @@ -652,8 +652,7 @@ struct decay3bodyBuilder { return; // don't do if no request for decay3bodys in place } - // prepare MC containers (not necessarily used) - std::vector mc3BodyInfos; // Decay3bodyMCCore information + // prepare MC container (not necessarily used) std::vector mcParticleIsReco; // clear and reserve size for MC info vectors @@ -983,7 +982,7 @@ struct decay3bodyBuilder { if (!mEnabledTables[kVtx3BodyDatas]) { return; // don't do if no request for decay3bodys in place } - + // Strictly upper index policy for decay3body objects binned by radius, phi for (const auto& [decay3body0, decay3body1] : selfPairCombinations(binningType, mixingOpts.n3bodyMixing, -1, decay3bodys)) { auto trackPos0 = decay3body0.template track0_as(); @@ -1007,13 +1006,13 @@ struct decay3bodyBuilder { trackPion1 = trackPos1; } - registry.fill(HIST("h3bodyCombinationCounter"), 0.5); + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 0.5); // only combine if from different event if (decay3body0.collisionId() == decay3body1.collisionId()) { continue; } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 1.5); + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 1.5); // collision vertex selection auto collision0 = decay3body0.template collision_as(); @@ -1027,27 +1026,27 @@ struct decay3bodyBuilder { if (mixingOpts.selectPVPosZ3bodyMixing && std::abs(collision0.posZ() - collision1.posZ()) > mixingOpts.maxDeltaPVPosZ3bodyMixing) { continue; } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 2.5); + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 2.5); // Charge selections // same magnetic fields --> mix matter with matter - if (std::signbit(magFieldCol0) == std::signbit(magFieldCol1)) { + if ((magFieldCol0/std::abs(magFieldCol0)) == (magFieldCol1/std::abs(magFieldCol1))) { if (trackDeuteron0.sign() != trackDeuteron1.sign()) { - continue; - } + continue; + } } // opposite magnetic fields --> mix matter with anti-matter - if (std::signbit(magFieldCol0) != std::signbit(magFieldCol1)) { + if ((magFieldCol0/std::abs(magFieldCol0)) != (magFieldCol1/std::abs(magFieldCol1))) { if (trackDeuteron0.sign() == trackDeuteron1.sign()) { - continue; - } + continue; + } } // don't mix 3body with itself if ((trackDeuteron0.globalIndex() == trackDeuteron1.globalIndex()) || (trackProton0.globalIndex() == trackProton1.globalIndex()) || (trackPion0.globalIndex() == trackPion1.globalIndex())) { continue; } - registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 3.5); // candidate analysis // mix deuteron @@ -1300,29 +1299,29 @@ struct decay3bodyBuilder { soa::Join const& decay3bodys, aod::RedIUTracks const&) { - auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); - auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); + auto xAxis = registry.get(HIST("Mixing/hDecay3BodyRadiusPhi"))->GetXaxis(); + auto yAxis = registry.get(HIST("Mixing/hDecay3BodyRadiusPhi"))->GetYaxis(); for (const auto& decay3body : decay3bodys) { int bin_Radius, bin_Phi; if (decay3bodyBuilderOpts.useKFParticle) { bin_Radius = xAxis->FindBin(decay3body.radiusKF()); bin_Phi = yAxis->FindBin(decay3body.phiKF()); - registry.fill(HIST("hDecay3BodyPosZ"), decay3body.poszKF()); + registry.fill(HIST("Mixing/hDecay3BodyPosZ"), decay3body.poszKF()); } else { bin_Radius = xAxis->FindBin(decay3body.radiusDCA()); bin_Phi = yAxis->FindBin(decay3body.phiDCA()); - registry.fill(HIST("hDecay3BodyPosZ"), decay3body.poszDCA()); + registry.fill(HIST("Mixing/hDecay3BodyPosZ"), decay3body.poszDCA()); } - registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); + registry.fill(HIST("Mixing/hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); } if (decay3bodyBuilderOpts.useKFParticle) { - Binning3BodyKF binningOnRadPhi{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; - buildMixedCandidates(decay3bodys, binningOnRadPhi); + Binning3BodyKF binningOnRadPhiKF{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; + buildMixedCandidates(decay3bodys, binningOnRadPhiKF); } else { - Binning3BodyDCAfitter binningOnRadPhi{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; - buildMixedCandidates(decay3bodys, binningOnRadPhi); + Binning3BodyDCAfitter binningOnRadPhiDCA{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; + buildMixedCandidates(decay3bodys, binningOnRadPhiDCA); } } diff --git a/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx b/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx index 0fe65459765..4f52fdd8066 100644 --- a/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx +++ b/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx @@ -88,7 +88,6 @@ struct reduced3bodyCreator { o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; Configurable event_sel8_selection{"event_sel8_selection", true, "event selection count post sel8 cut"}; - Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; // CCDB options Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -285,7 +284,7 @@ struct reduced3bodyCreator { //------------------------------------------------------------------ // function to fit KFParticle 3body vertex template - void fit3bodyVertex(TKFParticle& kfpProton, TKFParticle& kfpPion, TKFParticle& kfpDeuteron, TKFParticle& KFHt) + bool fit3bodyVertex(TKFParticle& kfpProton, TKFParticle& kfpPion, TKFParticle& kfpDeuteron, TKFParticle& KFHt) { // Construct 3body vertex int nDaughters3body = 3; @@ -295,9 +294,10 @@ struct reduced3bodyCreator { KFHt.Construct(Daughters3body, nDaughters3body); } catch (std::runtime_error& e) { LOG(debug) << "Failed to create Hyper triton 3-body vertex." << e.what(); - return; + return false; } LOG(debug) << "Hypertriton vertex constructed."; + return true; } void process(ColwithEvTimesMultsCents const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::Tracked3Bodys const& tracked3bodys, aod::BCsWithTimestamps const&) @@ -423,12 +423,18 @@ struct reduced3bodyCreator { kfpPion = createKFParticleFromTrackParCov(trackParCovPos, daughter0.sign(), constants::physics::MassPionCharged); } kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, daughter2.sign(), constants::physics::MassDeuteron); - // fit 3body vertex + // fit 3body vertex and caclulate radius, phi, z position + float radius, phi, posZ; KFParticle KFHt; - fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt); - // calculate radius and phi - auto radius = std::hypot(KFHt.GetX(), KFHt.GetY()); - auto phi = RecoDecay::phi(KFHt.GetPx(), KFHt.GetPy()); + if (fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt)) { + radius = std::hypot(KFHt.GetX(), KFHt.GetY()); + phi = std::atan2(KFHt.GetPx(), KFHt.GetPy()); + posZ = KFHt.GetZ(); + } else { + radius = -999.; + phi = -999.; + posZ = -999.; + } // -------- get decay3body info with DCA fitter -------- auto Track0 = getTrackParCov(daughter0); @@ -457,7 +463,7 @@ struct reduced3bodyCreator { } // fill 3body info table (KF and DCA fitter info) - reduced3BodyInfo(radius, phi, KFHt.GetZ(), rVtx, phiVtx, zVtx, fTrackedClSizeVector[d3body.globalIndex()]); + reduced3BodyInfo(radius, phi, posZ, rVtx, phiVtx, zVtx, fTrackedClSizeVector[d3body.globalIndex()]); } // end decay3body loop registry.fill(HIST("hEventCounter"), 3.5, reducedCollisions.lastIndex() + 1); From 4d8ce42e8713c40986b8884815b848f8ca4ea06f Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Sun, 8 Jun 2025 11:20:42 +0000 Subject: [PATCH 7/7] Please consider the following formatting changes --- PWGLF/DataModel/Vtx3BodyTables.h | 10 +- .../Nuspex/decay3bodybuilder.cxx | 188 +++++++++--------- 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/PWGLF/DataModel/Vtx3BodyTables.h b/PWGLF/DataModel/Vtx3BodyTables.h index 6526dd6a391..f03dfa8254c 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -42,7 +42,7 @@ DECLARE_SOA_COLUMN(Z, z, float); //! decay position Z DECLARE_SOA_COLUMN(Px, px, float); //! momentum X DECLARE_SOA_COLUMN(Py, py, float); //! momentum Y DECLARE_SOA_COLUMN(Pz, pz, float); //! momentum Z -DECLARE_SOA_COLUMN(Chi2, chi2, float); //! KFParticle: chi2geo/ndf or chi2topo/ndf of vertex fit, DCA fitter: Chi2AtPCACandidate value +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! KFParticle: chi2geo/ndf or chi2topo/ndf of vertex fit, DCA fitter: Chi2AtPCACandidate value // daughter properties DECLARE_SOA_COLUMN(MassV0, massV0, float); //! V0 mass (with H3L or Anti-H3L mass hypothesis depending on deuteron charge) @@ -105,7 +105,7 @@ DECLARE_SOA_COLUMN(GenZ, genZ, float); // generated decay vtx p DECLARE_SOA_COLUMN(GenCt, genCt, float); // generated Ct of the hypertriton DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // generated Phi of the hypertriton DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton -DECLARE_SOA_COLUMN(GenRap, genRap, float); // generated rapidity of the hypertriton +DECLARE_SOA_COLUMN(GenRap, genRap, float); // generated rapidity of the hypertriton DECLARE_SOA_COLUMN(GenPPr, genPPr, float); //! generated momentum proton daughter particle DECLARE_SOA_COLUMN(GenPPi, genPPi, float); //! generated momentum pion daughter particle DECLARE_SOA_COLUMN(GenPDe, genPDe, float); //! generated momentum deuteron daughter particle @@ -186,9 +186,9 @@ DECLARE_SOA_DYNAMIC_COLUMN(TrackDePhi, trackDePhi, //! daughter2 phi // index table DECLARE_SOA_TABLE(Decay3BodyIndices, "AOD", "3BodyINDEX", //! - o2::soa::Index<>, - vtx3body::Decay3BodyId, - vtx3body::TrackPrId, vtx3body::TrackPiId, vtx3body::TrackDeId, + o2::soa::Index<>, + vtx3body::Decay3BodyId, + vtx3body::TrackPrId, vtx3body::TrackPiId, vtx3body::TrackDeId, vtx3body::CollisionId); // reconstructed candidate table for analysis diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index dc452692767..5a7b0496334 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -16,7 +16,7 @@ /// \author Carolina Reetz // ======================== -/// TODO: include likesign analysis here +/// TODO: include likesign analysis here /// TODO: include possibility to mix 3bodys with opposite B fields #include @@ -111,8 +111,8 @@ struct decay3bodyBuilder { } products; // enablde tables - Configurable> enabledTables{"enabledTables", - {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, "Produce this table: 0 - false, 1 - true"}; std::vector mEnabledTables; // Vector of enabled tables @@ -244,7 +244,7 @@ struct decay3bodyBuilder { float d_bz; Service ccdb; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - std::unordered_map ccdbCache; // Maps runNumber -> d_bz + std::unordered_map ccdbCache; // Maps runNumber -> d_bz o2::base::MatLayerCylSet* lut = nullptr; // histogram registry @@ -462,7 +462,7 @@ struct decay3bodyBuilder { registry.add("QA/Event/hVtxCovYZ", "hVtxCovYZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); } } - + if (doprocessRealDataReduced3bodyMixing == true) { auto h3bodyCombinationCounter = registry.add("Mixing/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); @@ -587,14 +587,14 @@ struct decay3bodyBuilder { return true; } - float getMagFieldFromRunNumber(int runNumber) + float getMagFieldFromRunNumber(int runNumber) { float magField; // Check if the CCDB data for this run is already cached if (ccdbCache.find(runNumber) != ccdbCache.end()) { LOG(debug) << "CCDB data already cached for run " << runNumber; magField = ccdbCache[runNumber]; - // if not, retrieve it from CCDB + // if not, retrieve it from CCDB } else { std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(ccdbConfigurations.grpmagPath, runNumber)); if (!grpmag) { @@ -611,7 +611,7 @@ struct decay3bodyBuilder { return magField; } - void initFittersWithMagField(int runNumber, float magField) + void initFittersWithMagField(int runNumber, float magField) { // set magnetic field only when run number changes if (mRunNumber == runNumber) { @@ -756,7 +756,7 @@ struct decay3bodyBuilder { float tofNSigmaDeuteron; if constexpr (!soa::is_table) { // running over derived data tofNSigmaDeuteron = trackDeuteron.tofNSigmaDe(); - } else if constexpr (soa::is_table) { // running over AO2Ds + } else if constexpr (soa::is_table) { // running over AO2Ds if constexpr (soa::is_table) { // running over MC (track table with labels) tofNSigmaDeuteron = getTOFnSigma(collision, trackDeuteron); } else { // running over real data @@ -939,36 +939,36 @@ struct decay3bodyBuilder { // fill MCDecay3BodyCores table if requested if (mEnabledTables[kMcVtx3BodyDatas]) { - products.mcvtx3bodydatas(-1, // sign - -1., -1., // mass, massV0 - -1., -1., -1., // position - -1., -1., -1., // momentum - -1., // chi2 - -1., // trackedClSize - -1., -1., -1., // momProton - -1., -1., -1., // momPion - -1., -1., -1., // momDeuteron - -1., -1., -1., // trackDCAxyToPV: 0 - proton, 1 - pion, 2 - deuteron - -1., -1., -1., // trackDCAzToPV: 0 - proton, 1 - pion, 2 - deuteron - -1., -1., -1., // daughterDCAtoSV: 0 - proton, 1 - pion, 2 - deuteron - -1., // daughterDCAatSV - -1., -1., -1., -1., // tpcNsigma: 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp - -1., // tofNsigmaDeuteron - -1., -1., -1., // average ITS cluster sizes: proton, pion, deuteron - -1., -1., -1., // TPCNCl: proton, pion, deuteron - -1., // pidForTrackingDeuteron - // MC information - mcparticle.px(), mcparticle.py(), mcparticle.pz(), - this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], - this3BodyMCInfo.genCt, - mcparticle.phi(), mcparticle.eta(), mcparticle.y(), - this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, - this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, - this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, - this3BodyMCInfo.isReco, - this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, - this3BodyMCInfo.isDeuteronPrimary, - this3BodyMCInfo.survivedEventSel); + products.mcvtx3bodydatas(-1, // sign + -1., -1., // mass, massV0 + -1., -1., -1., // position + -1., -1., -1., // momentum + -1., // chi2 + -1., // trackedClSize + -1., -1., -1., // momProton + -1., -1., -1., // momPion + -1., -1., -1., // momDeuteron + -1., -1., -1., // trackDCAxyToPV: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // trackDCAzToPV: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // daughterDCAtoSV: 0 - proton, 1 - pion, 2 - deuteron + -1., // daughterDCAatSV + -1., -1., -1., -1., // tpcNsigma: 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + -1., // tofNsigmaDeuteron + -1., -1., -1., // average ITS cluster sizes: proton, pion, deuteron + -1., -1., -1., // TPCNCl: proton, pion, deuteron + -1., // pidForTrackingDeuteron + // MC information + mcparticle.px(), mcparticle.py(), mcparticle.pz(), + this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], + this3BodyMCInfo.genCt, + mcparticle.phi(), mcparticle.eta(), mcparticle.y(), + this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, + this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, + this3BodyMCInfo.isReco, + this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, + this3BodyMCInfo.isDeuteronPrimary, + this3BodyMCInfo.survivedEventSel); } // enabled table check } // mcParticles loop } // constexpr requires mcParticles check @@ -982,7 +982,7 @@ struct decay3bodyBuilder { if (!mEnabledTables[kVtx3BodyDatas]) { return; // don't do if no request for decay3bodys in place } - + // Strictly upper index policy for decay3body objects binned by radius, phi for (const auto& [decay3body0, decay3body1] : selfPairCombinations(binningType, mixingOpts.n3bodyMixing, -1, decay3bodys)) { auto trackPos0 = decay3body0.template track0_as(); @@ -1030,13 +1030,13 @@ struct decay3bodyBuilder { // Charge selections // same magnetic fields --> mix matter with matter - if ((magFieldCol0/std::abs(magFieldCol0)) == (magFieldCol1/std::abs(magFieldCol1))) { + if ((magFieldCol0 / std::abs(magFieldCol0)) == (magFieldCol1 / std::abs(magFieldCol1))) { if (trackDeuteron0.sign() != trackDeuteron1.sign()) { continue; } } // opposite magnetic fields --> mix matter with anti-matter - if ((magFieldCol0/std::abs(magFieldCol0)) != (magFieldCol1/std::abs(magFieldCol1))) { + if ((magFieldCol0 / std::abs(magFieldCol0)) != (magFieldCol1 / std::abs(magFieldCol1))) { if (trackDeuteron0.sign() == trackDeuteron1.sign()) { continue; } @@ -1081,7 +1081,7 @@ struct decay3bodyBuilder { return bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); } } - return -999; + return -999; } // ______________________________________________________________ @@ -1090,30 +1090,30 @@ struct decay3bodyBuilder { { // generate analysis tables if (mEnabledTables[kDecay3BodyIndices]) { - products.decay3bodyindices(helper.decay3body.decay3bodyID, - helper.decay3body.protonID, helper.decay3body.pionID, helper.decay3body.deuteronID, - helper.decay3body.collisionID); - registry.fill(HIST("Counters/hTableBuildingStatistics"), kDecay3BodyIndices); - } + products.decay3bodyindices(helper.decay3body.decay3bodyID, + helper.decay3body.protonID, helper.decay3body.pionID, helper.decay3body.deuteronID, + helper.decay3body.collisionID); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kDecay3BodyIndices); + } if (mEnabledTables[kVtx3BodyDatas]) { products.vtx3bodydatas(helper.decay3body.sign, - helper.decay3body.mass, helper.decay3body.massV0, - helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], - helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], - helper.decay3body.chi2, - helper.decay3body.trackedClSize, - helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], - helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], - helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], - helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.trackDCAzToPV[0], helper.decay3body.trackDCAzToPV[1], helper.decay3body.trackDCAzToPV[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.daughterDCAatSV, - helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp - helper.decay3body.tofNsigmaDeuteron, - helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.pidForTrackingDeuteron); + helper.decay3body.mass, helper.decay3body.massV0, + helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], + helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], + helper.decay3body.chi2, + helper.decay3body.trackedClSize, + helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], + helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], + helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], + helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAzToPV[0], helper.decay3body.trackDCAzToPV[1], helper.decay3body.trackDCAzToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAatSV, + helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + helper.decay3body.tofNsigmaDeuteron, + helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.pidForTrackingDeuteron); registry.fill(HIST("Counters/hTableBuildingStatistics"), kVtx3BodyDatas); } if (mEnabledTables[kVtx3BodyCovs]) { @@ -1125,35 +1125,35 @@ struct decay3bodyBuilder { } if (mEnabledTables[kMcVtx3BodyDatas]) { products.mcvtx3bodydatas(helper.decay3body.sign, - helper.decay3body.mass, helper.decay3body.massV0, - helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], - helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], - helper.decay3body.chi2, - helper.decay3body.trackedClSize, - helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], - helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], - helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], - helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.trackDCAzToPV[0], helper.decay3body.trackDCAzToPV[1], helper.decay3body.trackDCAzToPV[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.daughterDCAatSV, - helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp - helper.decay3body.tofNsigmaDeuteron, - helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron - helper.decay3body.pidForTrackingDeuteron, - // MC information - this3BodyMCInfo.genMomentum[0], this3BodyMCInfo.genMomentum[1], this3BodyMCInfo.genMomentum[2], - this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], - this3BodyMCInfo.genCt, - this3BodyMCInfo.genPhi, this3BodyMCInfo.genEta, this3BodyMCInfo.genRapidity, - this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, - this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, - this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, - this3BodyMCInfo.isReco, - this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, - this3BodyMCInfo.isDeuteronPrimary, - this3BodyMCInfo.survivedEventSel); + helper.decay3body.mass, helper.decay3body.massV0, + helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], + helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], + helper.decay3body.chi2, + helper.decay3body.trackedClSize, + helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], + helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], + helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], + helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAzToPV[0], helper.decay3body.trackDCAzToPV[1], helper.decay3body.trackDCAzToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAatSV, + helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + helper.decay3body.tofNsigmaDeuteron, + helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.pidForTrackingDeuteron, + // MC information + this3BodyMCInfo.genMomentum[0], this3BodyMCInfo.genMomentum[1], this3BodyMCInfo.genMomentum[2], + this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], + this3BodyMCInfo.genCt, + this3BodyMCInfo.genPhi, this3BodyMCInfo.genEta, this3BodyMCInfo.genRapidity, + this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, + this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, + this3BodyMCInfo.isReco, + this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, + this3BodyMCInfo.isDeuteronPrimary, + this3BodyMCInfo.survivedEventSel); registry.fill(HIST("Counters/hTableBuildingStatistics"), kMcVtx3BodyDatas); } }