diff --git a/.github/labeler.yml b/.github/labeler.yml index 0002f9b7327..23f9cda941a 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -87,3 +87,7 @@ trigger: tutorial: - changed-files: - any-glob-to-any-file: ["Tutorials/**"] + +photon: + - changed-files: + - any-glob-to-any-file: ["PWGEM/PhotonMeson/**", "*/PWGEM/PhotonMeson/**"] diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index 009c658b22d..7b558e9e825 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -38,7 +38,7 @@ jobs: id: ml # You can override MegaLinter flavor used to have faster performances # More info at https://megalinter.io/flavors/ - uses: oxsecurity/megalinter@v9.3.0 + uses: oxsecurity/megalinter@v9.4.0 env: # All available variables are described in documentation: # https://megalinter.io/configuration/ @@ -49,7 +49,7 @@ jobs: # Upload MegaLinter artifacts - name: Archive production artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: MegaLinter reports diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6c154ffad42..f837e1ad5a0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: - id: trailing-whitespace - id: end-of-file-fixer - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v21.1.8 # clang-format version + rev: v20.1.3 # clang-format version (keep synced with https://github.com/alisw/ali-bot/blob/master/.github/workflows/c++-code-formatting.yml) hooks: - id: clang-format - repo: https://github.com/cpplint/cpplint diff --git a/ALICE3/Core/FastTracker.cxx b/ALICE3/Core/FastTracker.cxx index a74858cfe02..be4ef7d2a12 100644 --- a/ALICE3/Core/FastTracker.cxx +++ b/ALICE3/Core/FastTracker.cxx @@ -288,7 +288,7 @@ float FastTracker::ProbGoodChiSqHit(float radius, float searchRadiusRPhi, float // function to provide a reconstructed track from a perfect input track // returns number of intercepts (generic for now) -int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch) +int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch, const float maxRadius) { dNdEtaCent = nch; // set the number of charged particles per unit rapidity hits.clear(); @@ -335,6 +335,14 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa continue; // this layer should not be attempted, but go ahead } + if (layers[il].getRadius() > maxRadius) { + if (lastLayerReached == -1) { + // This means that we didn't reach the first layer + return -9; + } + break; // could not reach + } + // check if layer is reached float targetX = 1e+3; inputTrack.getXatLabR(layers[il].getRadius(), targetX, magneticField); @@ -367,6 +375,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa break; } } + if (std::abs(inputTrack.getZ()) > layers[il].getZ() && mApplyZacceptance) { break; // out of acceptance bounds } @@ -405,8 +414,9 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa static constexpr float kLargeErr2Dir = 0.7 * 0.7; static constexpr float kLargeErr2PtI = 30.5 * 30.5; std::array largeCov = {0.}; - for (int ic = o2::track::kCovMatSize; ic--;) + for (int ic = o2::track::kCovMatSize; ic--;) { largeCov[ic] = 0.; + } largeCov[o2::track::CovLabels::kSigY2] = largeCov[o2::track::CovLabels::kSigZ2] = kLargeErr2Coord; largeCov[o2::track::CovLabels::kSigSnp2] = largeCov[o2::track::CovLabels::kSigTgl2] = kLargeErr2Dir; largeCov[o2::track::CovLabels::kSigQ2Pt2] = kLargeErr2PtI * trPars[o2::track::ParLabels::kQ2Pt] * trPars[o2::track::ParLabels::kQ2Pt]; @@ -442,8 +452,10 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa std::cos(alpha) * spacePoint[0] + std::sin(alpha) * spacePoint[1], -std::sin(alpha) * spacePoint[0] + std::cos(alpha) * spacePoint[1], spacePoint[2]}; - if (!inwardTrack.propagateTo(xyz1[0], magneticField)) + + if (!inwardTrack.propagateTo(xyz1[0], magneticField)) { continue; + } if (!layers[il].isInert()) { // only update covm for tracker hits const o2::track::TrackParametrization::dim2_t hitpoint = { @@ -474,13 +486,14 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa } } - if (layers[il].isSilicon()) + if (layers[il].isSilicon()) { nSiliconPoints++; // count silicon hits - if (layers[il].isGas()) + } + if (layers[il].isGas()) { nGasPoints++; // count TPC/gas hits + } hits.push_back(thisHit); - if (!layers[il].isInert()) { // good hit probability calculation float sigYCmb = o2::math_utils::sqrt(inwardTrack.getSigmaY2() + layers[il].getResolutionRPhi() * layers[il].getResolutionRPhi()); float sigZCmb = o2::math_utils::sqrt(inwardTrack.getSigmaZ2() + layers[il].getResolutionZ() * layers[il].getResolutionZ()); @@ -502,21 +515,24 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa } // only attempt to continue if intercepts are at least four - if (nIntercepts < 4) + if (nIntercepts < 4) { return nIntercepts; + } // generate efficiency float eff = 1.; for (size_t i = 0; i < layers.size(); i++) { float iGoodHit = goodHitProbability[i]; - if (iGoodHit <= 0) + if (iGoodHit <= 0) { continue; + } eff *= iGoodHit; } if (mApplyEffCorrection) { - if (gRandom->Uniform() > eff) + if (gRandom->Uniform() > eff) { return -8; + } } outputTrack.setCov(inwardTrack.getCov()); @@ -524,8 +540,9 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa // Use covariance matrix based smearing std::array covMat = {0.}; - for (int ii = 0; ii < o2::track::kCovMatSize; ii++) + for (int ii = 0; ii < o2::track::kCovMatSize; ii++) { covMat[ii] = outputTrack.getCov()[ii]; + } TMatrixDSym m(5); double fcovm[5][5]; // double precision is needed for regularisation diff --git a/ALICE3/Core/FastTracker.h b/ALICE3/Core/FastTracker.h index 5b8fa150c4c..d361e261603 100644 --- a/ALICE3/Core/FastTracker.h +++ b/ALICE3/Core/FastTracker.h @@ -92,7 +92,7 @@ class FastTracker * @param nch Charged particle multiplicity (used for hit density calculations). * @return int i.e. number of intercepts (implementation-defined). */ - int FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch); + int FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch, const float maxRadius = 100.f); // For efficiency calculation float Dist(float z, float radius); diff --git a/ALICE3/Core/GeometryContainer.cxx b/ALICE3/Core/GeometryContainer.cxx index 622e3d01757..f58c9b80926 100644 --- a/ALICE3/Core/GeometryContainer.cxx +++ b/ALICE3/Core/GeometryContainer.cxx @@ -101,6 +101,14 @@ void GeometryContainer::init(o2::framework::InitContext& initContext) } } +void GeometryContainer::addEntry(const std::string& filename) +{ + if (!mCcdb) { + LOG(fatal) << " --- ccdb is not set"; + } + mEntries.emplace_back(filename, mCcdb); +} + std::map GeometryEntry::getConfiguration(const std::string& layerName) const { auto it = mConfigurations.find(layerName); diff --git a/ALICE3/Core/GeometryContainer.h b/ALICE3/Core/GeometryContainer.h index 755fa57b87b..b3e9e23a538 100644 --- a/ALICE3/Core/GeometryContainer.h +++ b/ALICE3/Core/GeometryContainer.h @@ -91,7 +91,7 @@ class GeometryContainer void init(o2::framework::InitContext& initContext); // Add a geometry entry from a configuration file - void addEntry(const std::string& filename) { mEntries.emplace_back(filename, mCcdb); } + void addEntry(const std::string& filename); static void setLutCleanupSetting(const bool cleanLutWhenLoaded) { mCleanLutWhenLoaded = cleanLutWhenLoaded; } void setCcdbManager(o2::ccdb::BasicCCDBManager* mgr) { mCcdb = mgr; } diff --git a/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx index b2738c32c56..c11327e9f03 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx @@ -288,6 +288,7 @@ struct OnTheFlyRichPid { float mMagneticField = 0.0f; void init(o2::framework::InitContext& initContext) { + mGeoContainer.setCcdbManager(ccdb.operator->()); mGeoContainer.init(initContext); const int nGeometries = mGeoContainer.getNumberOfConfigurations(); diff --git a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx index aecf7a85134..75e9d41d5c2 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx @@ -147,6 +147,7 @@ struct OnTheFlyTofPid { float mMagneticField = 0.0f; void init(o2::framework::InitContext& initContext) { + mGeoContainer.setCcdbManager(ccdb.operator->()); mGeoContainer.init(initContext); const int nGeometries = mGeoContainer.getNumberOfConfigurations(); diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 4eb0cf81ea4..5989f9d3965 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -181,6 +181,19 @@ struct OnTheFlyTracker { Configurable doV0QA{"doV0QA", false, "QA plots for when treating V0"}; } v0DecaySettings; + struct : ConfigurableGroup { + std::string prefix = "cfgFitter"; + Configurable propagateToPCA{"propagateToPCA", false, "create tracks version propagated to PCA"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + Configurable maxDZIni{"maxDZIni", 1e9, "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable maxDXYIni{"maxDXYIni", 4, "reject (if>0) PCA candidate if tracks DXY exceeds threshold"}; + Configurable maxVtxChi2{"maxVtxChi2", 1e9, "reject (if>0) vtx. chi2 above this value"}; + Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + } cfgFitter; + using PVertex = o2::dataformats::PrimaryVertex; // for secondary vertex finding @@ -317,6 +330,7 @@ struct OnTheFlyTracker { LOG(info) << "Initializing OnTheFlyTracker task"; ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setTimestamp(-1); + mGeoContainer.setCcdbManager(ccdb.operator->()); mGeoContainer.init(initContext); const int nGeometries = mGeoContainer.getNumberOfConfigurations(); @@ -464,6 +478,7 @@ struct OnTheFlyTracker { getHist(TH1, histPath + "hFastTrackerQA")->GetXaxis()->SetBinLabel(6, "multiple scattering"); getHist(TH1, histPath + "hFastTrackerQA")->GetXaxis()->SetBinLabel(7, "energy loss"); getHist(TH1, histPath + "hFastTrackerQA")->GetXaxis()->SetBinLabel(8, "efficiency"); + getHist(TH1, histPath + "hFastTrackerQA")->GetXaxis()->SetBinLabel(9, "no layers hit"); } } @@ -490,6 +505,27 @@ struct OnTheFlyTracker { hCovMatOK->GetXaxis()->SetBinLabel(1, "Not OK"); hCovMatOK->GetXaxis()->SetBinLabel(2, "OK"); + auto hFitterStatusCode = histos.add("hFitterStatusCode", "hFitterStatusCode", kTH1D, {{15, -0.5, 14.5}}); + hFitterStatusCode->GetXaxis()->SetBinLabel(1, "None"); // no status set (should not be possible!) + + /* Good Conditions */ + hFitterStatusCode->GetXaxis()->SetBinLabel(2, "Converged"); // fit converged + hFitterStatusCode->GetXaxis()->SetBinLabel(3, "MaxIter"); // max iterations reached before fit convergence + + /* Error Conditions */ + hFitterStatusCode->GetXaxis()->SetBinLabel(4, "NoCrossing"); // no reasaonable crossing was found + hFitterStatusCode->GetXaxis()->SetBinLabel(5, "RejRadius"); // radius of crossing was not acceptable + hFitterStatusCode->GetXaxis()->SetBinLabel(6, "RejTrackX"); // one candidate track x was below the mimimum required radius + hFitterStatusCode->GetXaxis()->SetBinLabel(7, "RejTrackRoughZ"); // rejected by rough cut on tracks Z difference + hFitterStatusCode->GetXaxis()->SetBinLabel(8, "RejChi2Max"); // rejected by maximum chi2 cut + hFitterStatusCode->GetXaxis()->SetBinLabel(9, "FailProp"); // propagation of at least prong to PCA failed + hFitterStatusCode->GetXaxis()->SetBinLabel(10, "FailInvCov"); // inversion of cov.-matrix failed + hFitterStatusCode->GetXaxis()->SetBinLabel(11, "FailInvWeight"); // inversion of Ti weight matrix failed + hFitterStatusCode->GetXaxis()->SetBinLabel(12, "FailInv2ndDeriv"); // inversion of 2nd derivatives failed + hFitterStatusCode->GetXaxis()->SetBinLabel(13, "FailCorrTracks"); // correction of tracks to updated x failed + hFitterStatusCode->GetXaxis()->SetBinLabel(14, "FailCloserAlt"); // alternative PCA is closer + hFitterStatusCode->GetXaxis()->SetBinLabel(15, "NStatusesDefined"); + if (doExtraQA) { histos.add("h2dVerticesVsContributors", "h2dVerticesVsContributors;Multiplicity;N vertices", kTH2F, {axes.axisMultiplicity, axes.axisNVertices}); histos.add("h1dVerticesNotReco", "h1dVerticesNotReco;Multiplicity;Vertices Not Reco", kTH1F, {axes.axisMultiplicity}); @@ -514,6 +550,7 @@ struct OnTheFlyTracker { h->GetXaxis()->SetBinLabel(6, "multiple scattering"); h->GetXaxis()->SetBinLabel(7, "energy loss"); h->GetXaxis()->SetBinLabel(8, "efficiency"); + h->GetXaxis()->SetBinLabel(8, "no layers hit"); histPointers.insert({v0histPath + "hFastTrackerQA", h}); // K0s insertHist(v0histPath + "K0/hGen", "hGen", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); @@ -582,15 +619,16 @@ struct OnTheFlyTracker { o2::vertexing::PVertexerParams::Instance().printKeyValues(); // initialize O2 2-prong fitter - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxDXYIni(4); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(true); - fitter.setWeightedFinalPCA(false); + fitter.setPropagateToPCA(cfgFitter.propagateToPCA); + fitter.setMaxR(cfgFitter.maxR); + fitter.setMinParamChange(cfgFitter.minParamChange); + fitter.setMinRelChi2Change(cfgFitter.minRelChi2Change); + fitter.setMaxDZIni(cfgFitter.maxDZIni); + fitter.setMaxDXYIni(cfgFitter.maxDXYIni); + fitter.setMaxChi2(cfgFitter.maxVtxChi2); + fitter.setUseAbsDCA(cfgFitter.useAbsDCA); + fitter.setWeightedFinalPCA(cfgFitter.useWeightedFinalPCA); + fitter.setBz(mMagneticField); fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); // such a light detector here // Set seed for TGenPhaseSpace @@ -890,12 +928,12 @@ struct OnTheFlyTracker { const float timeResolutionUs = timeResolutionNs * nsToMus; // us const float time = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; static constexpr int kCascProngs = 3; - std::vector xiDaughterTrackParCovsPerfect(3); - std::vector xiDaughterTrackParCovsTracked(3); - std::vector isReco(kCascProngs); - std::vector nHits(kCascProngs); // total - std::vector nSiliconHits(kCascProngs); // silicon type - std::vector nTPCHits(kCascProngs); // TPC type + std::array xiDaughterTrackParCovsPerfect; + std::array xiDaughterTrackParCovsTracked; + std::array isReco; + std::array nHitsCascadeProngs; // total + std::array nSiliconHitsCascadeProngs; // silicon type + std::array nTPCHitsCascadeProngs; // TPC type bool tryKinkReco = false; if (cascadeDecaySettings.decayXi && isCascade) { @@ -913,19 +951,19 @@ struct OnTheFlyTracker { for (int i = 0; i < kCascProngs; i++) { isReco[i] = false; - nHits[i] = 0; - nSiliconHits[i] = 0; - nTPCHits[i] = 0; + nHitsCascadeProngs[i] = 0; + nSiliconHitsCascadeProngs[i] = 0; + nTPCHitsCascadeProngs[i] = 0; if (enableSecondarySmearing) { - nHits[i] = fastTracker[icfg]->FastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); - nSiliconHits[i] = fastTracker[icfg]->GetNSiliconPoints(); - nTPCHits[i] = fastTracker[icfg]->GetNGasPoints(); + nHitsCascadeProngs[i] = fastTracker[icfg]->FastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); + nSiliconHitsCascadeProngs[i] = fastTracker[icfg]->GetNSiliconPoints(); + nTPCHitsCascadeProngs[i] = fastTracker[icfg]->GetNGasPoints(); - if (nHits[i] < 0 && cascadeDecaySettings.doXiQA) { // QA - getHist(TH1, histPath + "hFastTrackerQA")->Fill(o2::math_utils::abs(nHits[i])); + if (nHitsCascadeProngs[i] < 0 && cascadeDecaySettings.doXiQA) { // QA + getHist(TH1, histPath + "hFastTrackerQA")->Fill(o2::math_utils::abs(nHitsCascadeProngs[i])); } - if (nSiliconHits[i] >= fastTrackerSettings.minSiliconHits || (nSiliconHits[i] >= fastTrackerSettings.minSiliconHitsIfTPCUsed && nTPCHits[i] >= fastTrackerSettings.minTPCClusters)) { + if (nSiliconHitsCascadeProngs[i] >= fastTrackerSettings.minSiliconHits || (nSiliconHitsCascadeProngs[i] >= fastTrackerSettings.minSiliconHitsIfTPCUsed && nTPCHitsCascadeProngs[i] >= fastTrackerSettings.minTPCClusters)) { isReco[i] = true; } else { continue; // extra sure @@ -944,7 +982,7 @@ struct OnTheFlyTracker { histos.fill(HIST("hNaNBookkeeping"), i + 1, 1.0f); } if (isReco[i]) { - tracksAlice3.push_back(TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), time, timeResolutionUs, true, true, i + 2, nSiliconHits[i], nTPCHits[i]}); + tracksAlice3.push_back(TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), time, timeResolutionUs, true, true, i + 2, nSiliconHitsCascadeProngs[i], nTPCHitsCascadeProngs[i]}); } else { ghostTracksAlice3.push_back(TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), time, timeResolutionUs, true, true, i + 2}); } @@ -986,6 +1024,12 @@ struct OnTheFlyTracker { if (nCand == 0) { dcaFitterOK_V0 = false; } + + fitter.propagateTracksToVertex(); + if (!fitter.isPropagateTracksToVertexDone()) { + dcaFitterOK_V0 = false; + } + // V0 found successfully if (dcaFitterOK_V0) { if (cascadeDecaySettings.doXiQA) { @@ -1025,6 +1069,7 @@ struct OnTheFlyTracker { covV[MomInd[i]] = 1e-6; covV[i] = 1e-6; } + o2::track::TrackParCov v0Track = o2::track::TrackParCov( {pos[0], pos[1], pos[2]}, {posP[0] + negP[0], posP[1] + negP[1], posP[2] + negP[2]}, @@ -1045,6 +1090,13 @@ struct OnTheFlyTracker { dcaFitterOK_Cascade = false; } + fitter.propagateTracksToVertex(); + if (!fitter.isPropagateTracksToVertexDone()) { + dcaFitterOK_Cascade = false; + } + + const u_int8_t fitterStatusCode = fitter.getFitStatus(); + histos.fill(HIST("hFitterStatusCode"), fitterStatusCode); // Cascade found successfully if (dcaFitterOK_Cascade) { if (cascadeDecaySettings.doXiQA) { @@ -1097,8 +1149,9 @@ struct OnTheFlyTracker { // find perfect intercept XYZ float targetX = 1e+3; trackParCov.getXatLabR(layer.getRadius(), targetX, mMagneticField); - if (targetX > 999) + if (targetX > 999) { continue; // failed to find intercept + } if (!trackParCov.propagateTo(targetX, mMagneticField)) { continue; // failed to propagate @@ -1117,8 +1170,9 @@ struct OnTheFlyTracker { posClusterCandidate[2] = gRandom->Gaus(posClusterCandidate[2], layer.getResolutionZ()); } - if (std::isnan(phi)) + if (std::isnan(phi)) { continue; // Catch when getXatLabR misses layer[i] + } // towards adding cluster: move to track alpha double alpha = cascadeTrack.getAlpha(); @@ -1127,8 +1181,10 @@ struct OnTheFlyTracker { -TMath::Sin(alpha) * posClusterCandidate[0] + TMath::Cos(alpha) * posClusterCandidate[1], posClusterCandidate[2]}; - if (!(cascadeTrack.propagateTo(xyz1[0], mMagneticField))) + if (!(cascadeTrack.propagateTo(xyz1[0], mMagneticField))) { continue; + } + const o2::track::TrackParametrization::dim2_t hitpoint = {static_cast(xyz1[1]), static_cast(xyz1[2])}; const o2::track::TrackParametrization::dim3_t hitpointcov = {layer.getResolutionRPhi() * layer.getResolutionRPhi(), 0.f, layer.getResolutionZ() * layer.getResolutionZ()}; if (layer.isInDeadPhiRegion(phi)) { @@ -1138,10 +1194,10 @@ struct OnTheFlyTracker { cascadeTrack.update(hitpoint, hitpointcov); thisCascade.foundClusters++; // add to findable } - } - if (thisCascade.foundClusters < cascadeDecaySettings.minStraTrackHits) { - continue; // We didn't find enough hits for strangeness tracking + if (thisCascade.foundClusters < cascadeDecaySettings.minStraTrackHits) { + continue; // We didn't find enough hits for strangeness tracking + } } // add cascade track @@ -1155,20 +1211,19 @@ struct OnTheFlyTracker { } // end cascade building if (isReco[0] && ((cascadeDecaySettings.doKinkReco == 1 && tryKinkReco) || cascadeDecaySettings.doKinkReco == 2)) { // mode 1 or 2 - o2::track::TrackParCov prefectCascadeTrack, trackedCasc; + o2::track::TrackParCov prefectCascadeTrack, trackedCascade; const o2::track::TrackParCov& trackedBach = xiDaughterTrackParCovsTracked[0]; o2::upgrade::convertMCParticleToO2Track(mcParticle, prefectCascadeTrack, pdgDB); // back track is already smeared prefectCascadeTrack.setPID(pdgCodeToPID(PDG_t::kXiMinus)); // FIXME: not OK for omegas - int nCascHits = fastTracker[icfg]->FastTrack(prefectCascadeTrack, trackedCasc, dNdEta); - reconstructedCascade = (fastTrackerSettings.minSiliconHitsForKinkReco < nCascHits) ? false : true; - + const int nCascHits = fastTracker[icfg]->FastTrack(prefectCascadeTrack, trackedCascade, dNdEta, xiDecayRadius2D); + reconstructedCascade = (fastTrackerSettings.minSiliconHitsForKinkReco < nCascHits) ? true : false; if (reconstructedCascade) { std::array pCasc; std::array pBach; std::array pV0; - trackedCasc.getPxPyPzGlo(pCasc); + trackedCascade.getPxPyPzGlo(pCasc); trackedBach.getPxPyPzGlo(pBach); for (size_t i = 0; i < pCasc.size(); ++i) { pV0[i] = pCasc[i] - pBach[i]; @@ -1191,7 +1246,7 @@ struct OnTheFlyTracker { int nCand = 0; bool kinkFitterOK = true; try { - nCand = fitter.process(trackedCasc, trackedBach); + nCand = fitter.process(trackedCascade, trackedBach); } catch (...) { kinkFitterOK = false; } @@ -1200,43 +1255,43 @@ struct OnTheFlyTracker { kinkFitterOK = false; } + fitter.propagateTracksToVertex(); + if (!fitter.isPropagateTracksToVertexDone()) { + kinkFitterOK = false; + } + + const u_int8_t fitterStatusCode = fitter.getFitStatus(); + histos.fill(HIST("hFitterStatusCode"), fitterStatusCode); if (kinkFitterOK) { if (cascadeDecaySettings.doXiQA) { getHist(TH1, histPath + "hXiBuilding")->Fill(6.0f); } - } - fitter.propagateTracksToVertex(); // propagate e and K to D vertex - if (!fitter.isPropagateTracksToVertexDone()) { - kinkFitterOK = false; - } + o2::track::TrackParCov newCascadeTrack = fitter.getTrack(0); // (cascade) + std::array kinkVtx = {-999, -999, -999}; + kinkVtx = fitter.getPCACandidatePos(); + thisCascade.bachelorId = lastTrackIndex + tracksAlice3.size() - isReco.size(); + thisCascade.cascadeTrackId = lastTrackIndex + tracksAlice3.size(); // this should be ok + thisCascade.dcaV0dau = -1.f; // unknown + thisCascade.v0radius = -1.f; // unknown + thisCascade.dcacascdau = std::sqrt(fitter.getChi2AtPCACandidate()); + thisCascade.cascradius = std::hypot(kinkVtx[0], kinkVtx[1]); + thisCascade.cascradiusMC = xiDecayRadius2D; + thisCascade.mLambda = o2::constants::physics::MassLambda; + thisCascade.findableClusters = nCascHits; + thisCascade.foundClusters = nCascHits; + thisCascade.pt = newCascadeTrack.getPt(); + thisCascade.eta = newCascadeTrack.getEta(); + thisCascade.mXi = RecoDecay::m(std::array{std::array{pBach[0], pBach[1], pBach[2]}, std::array{pV0[0], pV0[1], pV0[2]}}, + std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassLambda}); - o2::track::TrackParCov newCascadeTrack = fitter.getTrack(0); // (cascade) - std::array kinkVtx = {-999, -999, -999}; - kinkVtx = fitter.getPCACandidatePos(); - - thisCascade.bachelorId = lastTrackIndex + tracksAlice3.size() - isReco.size(); - thisCascade.cascadeTrackId = lastTrackIndex + tracksAlice3.size(); // this should be ok - thisCascade.dcaV0dau = -1.f; // unknown - thisCascade.v0radius = -1.f; // unknown - thisCascade.dcacascdau = std::sqrt(fitter.getChi2AtPCACandidate()); - thisCascade.cascradius = std::hypot(kinkVtx[0], kinkVtx[1]); - thisCascade.cascradiusMC = xiDecayRadius2D; - thisCascade.mLambda = o2::constants::physics::MassLambda; - thisCascade.findableClusters = nCascHits; - thisCascade.foundClusters = nCascHits; - thisCascade.pt = newCascadeTrack.getPt(); - thisCascade.eta = newCascadeTrack.getEta(); - thisCascade.mXi = RecoDecay::m(std::array{std::array{pBach[0], pBach[1], pBach[2]}, - std::array{pV0[0], pV0[1], pV0[2]}}, - std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassLambda}); - - newCascadeTrack.setPID(pdgCodeToPID(PDG_t::kXiMinus)); // FIXME: not OK for omegas - tracksAlice3.push_back(TrackAlice3{newCascadeTrack, mcParticle.globalIndex(), time, timeResolutionUs, false, false, 1, thisCascade.foundClusters}); - - // add this cascade to vector (will fill cursor later with collision ID) - cascadesAlice3.push_back(thisCascade); - } + newCascadeTrack.setPID(pdgCodeToPID(PDG_t::kXiMinus)); // FIXME: not OK for omegas + tracksAlice3.push_back(TrackAlice3{newCascadeTrack, mcParticle.globalIndex(), time, timeResolutionUs, false, false, 1, thisCascade.foundClusters}); + + // add this cascade to vector (will fill cursor later with collision ID) + cascadesAlice3.push_back(thisCascade); + } // end fitter OK + } // end cascade found } // end cascade kink building // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ @@ -1246,7 +1301,7 @@ struct OnTheFlyTracker { getHist(TH1, histPath + "hMassLambda")->Fill(thisCascade.mLambda); getHist(TH1, histPath + "hMassXi")->Fill(thisCascade.mXi); getHist(TH2, histPath + "h2dMassXi")->Fill(thisCascade.mXi, thisCascade.pt); - getHist(TH2, histPath + "h2dDeltaPtVsPt")->Fill(thisCascade.pt, mcParticle.pt() - thisCascade.pt); + getHist(TH2, histPath + "h2dDeltaPtVsPt")->Fill(thisCascade.pt, (mcParticle.pt() - thisCascade.pt) / thisCascade.pt); getHist(TH2, histPath + "h2dDeltaEtaVsPt")->Fill(thisCascade.pt, mcParticle.eta() - thisCascade.eta); getHist(TH2, histPath + "hFoundVsFindable")->Fill(thisCascade.findableClusters, thisCascade.foundClusters); } @@ -1324,7 +1379,7 @@ struct OnTheFlyTracker { // histos.fill(HIST("hNaNBookkeeping"), i + 1, 1.0f); // } if (isReco[i]) { - tracksAlice3.push_back(TrackAlice3{v0DaughterTrackParCovsTracked[i], mcParticle.globalIndex(), time, timeResolutionUs, true, true, i + 2, nSiliconHits[i], nTPCHits[i]}); + tracksAlice3.push_back(TrackAlice3{v0DaughterTrackParCovsTracked[i], mcParticle.globalIndex(), time, timeResolutionUs, true, true, i + 2, nSiliconHitsCascadeProngs[i], nTPCHitsCascadeProngs[i]}); } else { ghostTracksAlice3.push_back(TrackAlice3{v0DaughterTrackParCovsTracked[i], mcParticle.globalIndex(), time, timeResolutionUs, true, true, i + 2}); } @@ -1381,6 +1436,14 @@ struct OnTheFlyTracker { if (nCand == 0) { dcaFitterOK_V0 = false; } + + fitter.propagateTracksToVertex(); + if (!fitter.isPropagateTracksToVertexDone()) { + dcaFitterOK_V0 = false; + } + + const u_int8_t fitterStatusCode = fitter.getFitStatus(); + histos.fill(HIST("hFitterStatusCode"), fitterStatusCode); // V0 found successfully if (dcaFitterOK_V0) { if (v0DecaySettings.doV0QA) { @@ -1462,14 +1525,16 @@ struct OnTheFlyTracker { } bool reconstructed = true; + int nTrkHits = 0; if (enablePrimarySmearing && !fastPrimaryTrackerSettings.fastTrackPrimaries) { reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + nTrkHits = fastTrackerSettings.minSiliconHits; } else if (fastPrimaryTrackerSettings.fastTrackPrimaries) { o2::track::TrackParCov o2Track; o2::upgrade::convertMCParticleToO2Track(mcParticle, o2Track, pdgDB); o2Track.setPID(pdgCodeToPID(mcParticle.pdgCode())); - const int nHits = fastTracker[icfg]->FastTrack(o2Track, trackParCov, dNdEta); - if (nHits < fastPrimaryTrackerSettings.minSiliconHits) { + nTrkHits = fastTracker[icfg]->FastTrack(o2Track, trackParCov, dNdEta); + if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits) { reconstructed = false; } } @@ -1504,7 +1569,7 @@ struct OnTheFlyTracker { // populate vector with track if we reco-ed it if (reconstructed) { - tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter}); + tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter, false, 0, nTrkHits}); } else { ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter}); } @@ -1864,15 +1929,17 @@ struct OnTheFlyTracker { const float time = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; bool reconstructed = false; + int nTrkHits = 0; if (enablePrimarySmearing && mcParticle.isPrimary()) { o2::upgrade::convertMCParticleToO2Track(mcParticle, trackParCov, pdgDB); reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + nTrkHits = fastTrackerSettings.minSiliconHits; } else if (enableSecondarySmearing) { o2::track::TrackParCov perfectTrackParCov; o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); - const int nHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta); - if (nHits < fastTrackerSettings.minSiliconHits) { + nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta); + if (nTrkHits < fastTrackerSettings.minSiliconHits) { reconstructed = false; } else { reconstructed = true; @@ -1902,7 +1969,7 @@ struct OnTheFlyTracker { } if (reconstructed) { - tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter}); + tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter, false, 0, nTrkHits}); } else { ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter}); } diff --git a/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx index 391b99553e9..78db04bba62 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx @@ -433,12 +433,13 @@ struct OnTheFlyTrackerPid { float mMagneticField = 0.0f; void init(o2::framework::InitContext& initContext) { - mGeoContainer.init(initContext); - mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield"); - ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setTimestamp(-1); + mGeoContainer.setCcdbManager(ccdb.operator->()); + mGeoContainer.init(initContext); + mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield"); + if (static_cast(maxBarrelLayers.value) > kTrackerRadii.size()) { LOG(fatal) << "Configured maxBarrelLayers (" << maxBarrelLayers.value << ") exceeds the size of kTrackerRadii (" << kTrackerRadii.size() diff --git a/ALICE3/TableProducer/alice3MulticharmFinder.cxx b/ALICE3/TableProducer/alice3MulticharmFinder.cxx index e66708bd911..16e0e9571c7 100644 --- a/ALICE3/TableProducer/alice3MulticharmFinder.cxx +++ b/ALICE3/TableProducer/alice3MulticharmFinder.cxx @@ -87,7 +87,20 @@ struct Alice3MulticharmFinder { Configurable fillMCharmIdx{"fillMCharmIdx", true, "fill MCharmIdx[] tables (careful: memory)"}; Configurable fillMCharmCore{"fillMCharmCore", true, "fill MCharmCores[] tables (careful: memory)"}; Configurable fillMCharmExtra{"fillMCharmExtra", false, "fill MCharmExtra[] tables (careful: memory)"}; - } derivedTable; // allows for gap between peak and bg in case someone wants to + } derivedTable; + + struct : ConfigurableGroup { + std::string prefix = "cfgFitter"; + Configurable propagateToPCA{"propagateToPCA", false, "create tracks version propagated to PCA"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + Configurable maxDZIni{"maxDZIni", 1e9, "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable maxDXYIni{"maxDXYIni", 4, "reject (if>0) PCA candidate if tracks DXY exceeds threshold"}; + Configurable maxVtxChi2{"maxVtxChi2", 1e9, "reject (if>0) vtx. chi2 above this value"}; + Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + } cfgFitter; Configurable cfgMagneticField{"cfgMagneticField", 20.0f, "Magnetic field (in kilogauss) if value not found from geo provider"}; Configurable doDCAplots{"doDCAplots", true, "do daughter prong DCA plots for D mesons"}; @@ -164,7 +177,6 @@ struct Alice3MulticharmFinder { // filter expressions for pions static constexpr uint32_t TrackSelectionPic = 1 << kInnerTOFPion | 1 << kOuterTOFPion | 1 << kRICHPion | 1 << kTruePiFromXiC; static constexpr uint32_t TrackSelectionPicc = 1 << kInnerTOFPion | 1 << kOuterTOFPion | 1 << kRICHPion | 1 << kTruePiFromXiCC; - float magneticField{}; // partitions Partition trueXi = aod::mcparticle::pdgCode == static_cast(PDG_t::kXiMinus); @@ -224,11 +236,19 @@ struct Alice3MulticharmFinder { } catch (...) { return false; } + + const u_int8_t fitterStatusCode = fitter.getFitStatus(); + histos.fill(HIST("hFitterStatusCode"), fitterStatusCode); if (nCand == 0) { return false; } - //}-{}-{}-{}-{}-{}-{}-{}-{}-{} + fitter.propagateTracksToVertex(); + if (!fitter.isPropagateTracksToVertexDone()) { + return false; + } + + //}-{}-{}-{}-{}-{}-{}-{}-{}-{} o2::track::TrackParCov t0new = fitter.getTrack(0); o2::track::TrackParCov t1new = fitter.getTrack(1); t0new.getPxPyPzGlo(thisXiccCandidate.prong0mom); @@ -295,9 +315,17 @@ struct Alice3MulticharmFinder { } catch (...) { return false; } + + const u_int8_t fitter3StatusCode = fitter3.getFitStatus(); + histos.fill(HIST("hFitter3StatusCode"), fitter3StatusCode); if (nCand == 0) { return false; } + + fitter3.propagateTracksToVertex(); + if (!fitter3.isPropagateTracksToVertexDone()) { + return false; + } //}-{}-{}-{}-{}-{}-{}-{}-{}-{} t0 = fitter3.getTrack(0); @@ -399,40 +427,75 @@ struct Alice3MulticharmFinder { return returnValue; } - void init(o2::framework::InitContext& initContext) + void init(o2::framework::InitContext&) { - const bool foundMagneticField = common::core::getTaskOptionValue(initContext, "on-the-fly-detector-geometry-provider", "magneticField", magneticField, false); - if (!foundMagneticField) { - LOG(info) << "Could not retrieve magnetic field from geometry provider."; - LOG(info) << "Using value from configurable cfgMagneticField: " << cfgMagneticField; - magneticField = cfgMagneticField; - } else { - LOG(info) << "Using magnetic field form geometry provider with value: " << magneticField; - } - // initialize O2 2-prong fitter (only once) - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(true); - fitter.setWeightedFinalPCA(false); - fitter.setBz(magneticField); + fitter.setPropagateToPCA(cfgFitter.propagateToPCA); + fitter.setMaxR(cfgFitter.maxR); + fitter.setMinParamChange(cfgFitter.minParamChange); + fitter.setMinRelChi2Change(cfgFitter.minRelChi2Change); + fitter.setMaxDZIni(cfgFitter.maxDZIni); + fitter.setMaxDXYIni(cfgFitter.maxDXYIni); + fitter.setMaxChi2(cfgFitter.maxVtxChi2); + fitter.setUseAbsDCA(cfgFitter.useAbsDCA); + fitter.setWeightedFinalPCA(cfgFitter.useWeightedFinalPCA); + fitter.setBz(cfgMagneticField); fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); - fitter3.setPropagateToPCA(true); - fitter3.setMaxR(200.); - fitter3.setMinParamChange(1e-3); - fitter3.setMinRelChi2Change(0.9); - fitter3.setMaxDZIni(1e9); - fitter3.setMaxChi2(1e9); - fitter3.setUseAbsDCA(true); - fitter3.setWeightedFinalPCA(false); - fitter3.setBz(magneticField); + fitter3.setPropagateToPCA(cfgFitter.propagateToPCA); + fitter3.setMaxR(cfgFitter.maxR); + fitter3.setMinParamChange(cfgFitter.minParamChange); + fitter3.setMinRelChi2Change(cfgFitter.minRelChi2Change); + fitter3.setMaxDZIni(cfgFitter.maxDZIni); + fitter3.setMaxDZIni(cfgFitter.maxDXYIni); + fitter3.setMaxChi2(cfgFitter.maxVtxChi2); + fitter3.setUseAbsDCA(cfgFitter.useAbsDCA); + fitter3.setWeightedFinalPCA(cfgFitter.useWeightedFinalPCA); + fitter3.setBz(cfgMagneticField); fitter3.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); + auto hFitterStatusCode = histos.add("hFitterStatusCode", "hFitterStatusCode", kTH1D, {{15, -0.5, 14.5}}); + hFitterStatusCode->GetXaxis()->SetBinLabel(1, "None"); // no status set (should not be possible!) + + /* Good Conditions */ + hFitterStatusCode->GetXaxis()->SetBinLabel(2, "Converged"); // fit converged + hFitterStatusCode->GetXaxis()->SetBinLabel(3, "MaxIter"); // max iterations reached before fit convergence + + /* Error Conditions */ + hFitterStatusCode->GetXaxis()->SetBinLabel(4, "NoCrossing"); // no reasaonable crossing was found + hFitterStatusCode->GetXaxis()->SetBinLabel(5, "RejRadius"); // radius of crossing was not acceptable + hFitterStatusCode->GetXaxis()->SetBinLabel(6, "RejTrackX"); // one candidate track x was below the mimimum required radius + hFitterStatusCode->GetXaxis()->SetBinLabel(7, "RejTrackRoughZ"); // rejected by rough cut on tracks Z difference + hFitterStatusCode->GetXaxis()->SetBinLabel(8, "RejChi2Max"); // rejected by maximum chi2 cut + hFitterStatusCode->GetXaxis()->SetBinLabel(9, "FailProp"); // propagation of at least prong to PCA failed + hFitterStatusCode->GetXaxis()->SetBinLabel(10, "FailInvCov"); // inversion of cov.-matrix failed + hFitterStatusCode->GetXaxis()->SetBinLabel(11, "FailInvWeight"); // inversion of Ti weight matrix failed + hFitterStatusCode->GetXaxis()->SetBinLabel(12, "FailInv2ndDeriv"); // inversion of 2nd derivatives failed + hFitterStatusCode->GetXaxis()->SetBinLabel(13, "FailCorrTracks"); // correction of tracks to updated x failed + hFitterStatusCode->GetXaxis()->SetBinLabel(14, "FailCloserAlt"); // alternative PCA is closer + hFitterStatusCode->GetXaxis()->SetBinLabel(15, "NStatusesDefined"); + + auto hFitter3StatusCode = histos.add("hFitter3StatusCode", "hFitter3StatusCode", kTH1D, {{15, -0.5, 14.5}}); + hFitter3StatusCode->GetXaxis()->SetBinLabel(1, "None"); // no status set (should not be possible!) + + /* Good Conditions */ + hFitter3StatusCode->GetXaxis()->SetBinLabel(2, "Converged"); // fit converged + hFitter3StatusCode->GetXaxis()->SetBinLabel(3, "MaxIter"); // max iterations reached before fit convergence + + /* Error Conditions */ + hFitter3StatusCode->GetXaxis()->SetBinLabel(4, "NoCrossing"); // no reasaonable crossing was found + hFitter3StatusCode->GetXaxis()->SetBinLabel(5, "RejRadius"); // radius of crossing was not acceptable + hFitter3StatusCode->GetXaxis()->SetBinLabel(6, "RejTrackX"); // one candidate track x was below the mimimum required radius + hFitter3StatusCode->GetXaxis()->SetBinLabel(7, "RejTrackRoughZ"); // rejected by rough cut on tracks Z difference + hFitter3StatusCode->GetXaxis()->SetBinLabel(8, "RejChi2Max"); // rejected by maximum chi2 cut + hFitter3StatusCode->GetXaxis()->SetBinLabel(9, "FailProp"); // propagation of at least prong to PCA failed + hFitter3StatusCode->GetXaxis()->SetBinLabel(10, "FailInvCov"); // inversion of cov.-matrix failed + hFitter3StatusCode->GetXaxis()->SetBinLabel(11, "FailInvWeight"); // inversion of Ti weight matrix failed + hFitter3StatusCode->GetXaxis()->SetBinLabel(12, "FailInv2ndDeriv"); // inversion of 2nd derivatives failed + hFitter3StatusCode->GetXaxis()->SetBinLabel(13, "FailCorrTracks"); // correction of tracks to updated x failed + hFitter3StatusCode->GetXaxis()->SetBinLabel(14, "FailCloserAlt"); // alternative PCA is closer + hFitter3StatusCode->GetXaxis()->SetBinLabel(15, "NStatusesDefined"); + INSERT_HIST(std::string("h2dGenXi"), "h2dGenXi", {kTH2D, {{axisPt, axisEta}}}); INSERT_HIST(std::string("h2dGenXiC"), "h2dGenXiC", {kTH2D, {{axisPt, axisEta}}}); INSERT_HIST(std::string("h2dGenXiCC"), "h2dGenXiCC", {kTH2D, {{axisPt, axisEta}}}); @@ -665,7 +728,7 @@ struct Alice3MulticharmFinder { o2::vertexing::PVertex primaryVertex; primaryVertex.setXYZ(collision.posX(), collision.posY(), collision.posZ()); - if (xicTrackCopy.propagateToDCA(primaryVertex, magneticField, &dcaInfo)) { + if (xicTrackCopy.propagateToDCA(primaryVertex, cfgMagneticField, &dcaInfo)) { xicdcaXY = dcaInfo.getY(); xicdcaZ = dcaInfo.getZ(); } @@ -760,7 +823,7 @@ struct Alice3MulticharmFinder { GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(6.0f); GET_HIST(TH2, histPath + "hXicRadiusVsXiccRadius")->Fill(xicDecayRadius2D * ToMicrons, xiccDecayRadius2D * ToMicrons); float xiccdcaXY = 1e+10, xiccdcaZ = 1e+10; - if (xiccTrack.propagateToDCA(primaryVertex, magneticField, &dcaInfo)) { + if (xiccTrack.propagateToDCA(primaryVertex, cfgMagneticField, &dcaInfo)) { xiccdcaXY = dcaInfo.getY(); xiccdcaZ = dcaInfo.getZ(); } diff --git a/ALICE3/TableProducer/alice3strangenessFinder.cxx b/ALICE3/TableProducer/alice3strangenessFinder.cxx index 2d36590ede0..f2a60b5ab8c 100644 --- a/ALICE3/TableProducer/alice3strangenessFinder.cxx +++ b/ALICE3/TableProducer/alice3strangenessFinder.cxx @@ -44,6 +44,7 @@ #include #include +#include using namespace o2; // using namespace o2::analysis; @@ -153,6 +154,27 @@ struct Alice3strangenessFinder { fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); histos.add("hFitterQA", "", kTH1D, {{10, 0, 10}}); // For QA reasons, counting found candidates at different stages + auto hFitterStatusCode = histos.add("hFitterStatusCode", "hFitterStatusCode", kTH1D, {{15, -0.5, 14.5}}); + hFitterStatusCode->GetXaxis()->SetBinLabel(1, "None"); // no status set (should not be possible!) + + /* Good Conditions */ + hFitterStatusCode->GetXaxis()->SetBinLabel(2, "Converged"); // fit converged + hFitterStatusCode->GetXaxis()->SetBinLabel(3, "MaxIter"); // max iterations reached before fit convergence + + /* Error Conditions */ + hFitterStatusCode->GetXaxis()->SetBinLabel(4, "NoCrossing"); // no reasaonable crossing was found + hFitterStatusCode->GetXaxis()->SetBinLabel(5, "RejRadius"); // radius of crossing was not acceptable + hFitterStatusCode->GetXaxis()->SetBinLabel(6, "RejTrackX"); // one candidate track x was below the mimimum required radius + hFitterStatusCode->GetXaxis()->SetBinLabel(7, "RejTrackRoughZ"); // rejected by rough cut on tracks Z difference + hFitterStatusCode->GetXaxis()->SetBinLabel(8, "RejChi2Max"); // rejected by maximum chi2 cut + hFitterStatusCode->GetXaxis()->SetBinLabel(9, "FailProp"); // propagation of at least prong to PCA failed + hFitterStatusCode->GetXaxis()->SetBinLabel(10, "FailInvCov"); // inversion of cov.-matrix failed + hFitterStatusCode->GetXaxis()->SetBinLabel(11, "FailInvWeight"); // inversion of Ti weight matrix failed + hFitterStatusCode->GetXaxis()->SetBinLabel(12, "FailInv2ndDeriv"); // inversion of 2nd derivatives failed + hFitterStatusCode->GetXaxis()->SetBinLabel(13, "FailCorrTracks"); // correction of tracks to updated x failed + hFitterStatusCode->GetXaxis()->SetBinLabel(14, "FailCloserAlt"); // alternative PCA is closer + hFitterStatusCode->GetXaxis()->SetBinLabel(15, "NStatusesDefined"); + histos.add("hPtPosDau", "", kTH1D, {axisPt}); histos.add("hPtNegDau", "", kTH1D, {axisPt}); histos.add("hPtPosDauAfterV0Finding", "", kTH2D, {axisPt, axisPt}); @@ -220,6 +242,9 @@ struct Alice3strangenessFinder { } catch (...) { return false; } + + const u_int8_t fitterStatusCode = fitter.getFitStatus(); + histos.fill(HIST("hFitterStatusCode"), fitterStatusCode); histos.fill(HIST("hFitterQA"), 1.5); if (nCand == 0) { LOG(info) << "0 candidates found by fitter"; diff --git a/ALICE3/Tasks/alice3-dilepton.cxx b/ALICE3/Tasks/alice3-dilepton.cxx index bb142b11834..4ed9ee35a87 100644 --- a/ALICE3/Tasks/alice3-dilepton.cxx +++ b/ALICE3/Tasks/alice3-dilepton.cxx @@ -642,7 +642,7 @@ struct Alice3Dilepton { } // end of mc particle loop registry.fill(HIST("Generated/Particle/ParticlesPerEvent"), nParticlesInEvent); - registry.fill(HIST("Generated/Particle/ParticlesFIT"), nParticlesFIT); + registry.fill(HIST("Generated/Particle/ParticlesFit"), nParticlesFIT); auto neg_mcParticles_coll = neg_mcParticles->sliceByCached(o2::aod::mcparticle::mcCollisionId, mccollision.globalIndex(), cache_mc); auto pos_mcParticles_coll = pos_mcParticles->sliceByCached(o2::aod::mcparticle::mcCollisionId, mccollision.globalIndex(), cache_mc); diff --git a/CODEOWNERS b/CODEOWNERS index 1ab937857ca..f2ea6f38a0b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -31,11 +31,24 @@ /EventFiltering/PWGJE @alibuild @fkrizek @nzardosh @raymondEhlers @mpuccio @lietava @fgrosa @ariedel-cern /EventFiltering/PWGEM @alibuild @dsekihat @nstrangm @mpuccio @lietava @fgrosa @ariedel-cern -/PWGCF @alibuild @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane -/PWGCF/Core @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane -/PWGCF/DataModel @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane -/PWGCF/TableProducer @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane -/PWGCF/Tasks @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF @alibuild @victor-gonzalez @otonvd @shouqiye +/PWGCF/Core @alibuild @jgrosseo +/PWGCF/DataModel @alibuild @jgrosseo @jaelpark @victor-gonzalez @otonvd @shouqiye +/PWGCF/TableProducer @alibuild @jgrosseo @jaelpark @victor-gonzalez @otonvd @shouqiye +/PWGCF/Tasks @alibuild @jgrosseo @jaelpark @victor-gonzalez @otonvd @shouqiye +/PWGCF/EbyEFluctuations @alibuild @SwatiSaha-1997 @isputows @victor-gonzalez @otonvd @shouqiye +/PWGCF/Femto @alibuild @lauraser @ariedel-cern @dimihayl @victor-gonzalez @otonvd @shouqiye +/PWGCF/FemtoDream @alibuild @lauraser @ariedel-cern @dimihayl @victor-gonzalez @otonvd @shouqiye +/PWGCF/Femto3D @alibuild @glromane @sofiatomassini @lauraser @dimihayl @victor-gonzalez @otonvd @shouqiye +/PWGCF/FemtoUniverse @alibuild @prchakra @lgraczykCern @majanik @lauraser @dimihayl @victor-gonzalez @otonvd @shouqiye +/PWGCF/FemtoWorld @alibuild @prchakra @lgraczykCern @majanik @lauraser @dimihayl @victor-gonzalez @otonvd @shouqiye +/PWGCF/Flow @alibuild @majanik @EmilGorm @jaelpark @wenyaCern @victor-gonzalez @otonvd @shouqiye +/PWGCF/GenericFramework @alibuild @EmilGorm @jaelpark @wenyaCern @victor-gonzalez @otonvd @shouqiye +/PWGCF/MultiparticleCorrelations @alibuild @abilandz @jaelpark @wenyaCern @victor-gonzalez @otonvd @shouqiye +/PWGCF/JCorran @alibuild @jaelpark @wenyaCern @victor-gonzalez @otonvd @shouqiye +/PWGCF/TwoParticleCorrelations @alibuild @Luzhiyongg @jaelpark @wenyaCern @victor-gonzalez @otonvd @shouqiye +/PWGCF/Tutorial @alibuild @ariedel-cern @victor-gonzalez @otonvd @shouqiye + /PWGDQ @alibuild @iarsene @mcoquet642 @lucamicheletti93 @XiaozhiBai /PWGEM @alibuild @feisenhu @dsekihat @ivorobye @jokonig /PWGEM/Dilepton @alibuild @mikesas @rbailhac @dsekihat @ivorobye @feisenhu @hscheid @jokonig @@ -43,18 +56,18 @@ /PWGHF @alibuild @vkucera @fcolamar @fgrosa @fcatalan92 @mfaggin @mmazzilli @deepathoms @NicoleBastid @hahassan7 @jpxrk @apalasciano @zhangbiao-phy @gluparel @stefanopolitano @xinyepeng @singhra1994 # PWG-LF /PWGLF @alibuild @omvazque @skundu692 @mpuccio -/PWGLF/DataModel @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT +/PWGLF/DataModel @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova /PWGLF/Tasks/GlobalEventProperties @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @omvazque /PWGLF/TableProducer/GlobalEventProperties @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @omvazque /PWGLF/Tasks/Nuspex @alibuild @omvazque @skundu692 @mpuccio @fmazzasc @maciacco @HorstMa /PWGLF/TableProducer/Nuspex @alibuild @omvazque @skundu692 @mpuccio @fmazzasc @maciacco @HorstMa /PWGLF/Tasks/Resonances @alibuild @omvazque @skundu692 @mpuccio @dmallick2 @smaff92 @prottayCMT /PWGLF/TableProducer/Resonances @alibuild @omvazque @skundu692 @mpuccio @dmallick2 @smaff92 @prottayCMT -/PWGLF/Tasks/Strangeness @alibuild @omvazque @skundu692 @mpuccio @ercolessi @romainschotter -/PWGLF/TableProducer/Strangeness @alibuild @omvazque @mpuccio @skundu692 @ercolessi @romainschotter -/PWGLF/TableProducer/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT -/PWGLF/Tasks/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT -/PWGLF/Utils @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT +/PWGLF/Tasks/Strangeness @alibuild @omvazque @skundu692 @mpuccio @ercolessi @romainschotter @lhusova +/PWGLF/TableProducer/Strangeness @alibuild @omvazque @mpuccio @skundu692 @ercolessi @romainschotter @lhusova +/PWGLF/TableProducer/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova +/PWGLF/Tasks/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova +/PWGLF/Utils @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova # PWG-MM (fused with LF, LF conveners included. Directories to be merged in the future) /PWGMM @alibuild @omvazque @mpuccio @skundu692 @aalkin @jgcn @@ -71,6 +84,6 @@ /Tutorials/PWGEM @alibuild @mikesas @rbailhac @dsekihat @ivorobye @feisenhu /Tutorials/PWGHF @alibuild @vkucera @fcolamar @fgrosa @gluparel @xinyepeng /Tutorials/PWGJE @alibuild @lhavener @maoyx @nzardosh @raymondEhlers @mfasDa @fjonasALICE -/Tutorials/PWGLF @alibuild @alcaliva @lbariogl @chiarapinto @BongHwi @lbarnby @ercolessi @iravasen @njacazio @romainschotter @skundu692 +/Tutorials/PWGLF @alibuild @alcaliva @lbariogl @chiarapinto @BongHwi @lbarnby @ercolessi @iravasen @njacazio @romainschotter @skundu692 @lhusova /Tutorials/PWGMM @alibuild @aalkin @ddobrigk /Tutorials/PWGUD @alibuild @pbuehler @amatyja diff --git a/Common/TableProducer/CMakeLists.txt b/Common/TableProducer/CMakeLists.txt index ea9b96c496f..69cd6084a09 100644 --- a/Common/TableProducer/CMakeLists.txt +++ b/Common/TableProducer/CMakeLists.txt @@ -98,8 +98,8 @@ o2physics_add_dpl_workflow(fwdtrackextension SOURCES fwdtrackextension.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats - O2::DetectorsBase - O2::DetectorsCommonDataFormats + O2::GlobalTracking + O2::MCHTracking COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-to-collision-associator diff --git a/Common/TableProducer/PID/pidTPC.cxx b/Common/TableProducer/PID/pidTPC.cxx index ebb66f8934a..1cdc936a175 100644 --- a/Common/TableProducer/PID/pidTPC.cxx +++ b/Common/TableProducer/PID/pidTPC.cxx @@ -103,17 +103,17 @@ struct tpcPid { // TPC PID Response o2::pid::tpc::Response* response; + // CCDB accessor + Service ccdb; + // Network correction for TPC PID response OnnxModel network; - o2::ccdb::CcdbApi ccdbApi; std::map metadata; - std::map nullmetadata; std::map headers; std::vector speciesNetworkFlags = std::vector(9); std::string networkVersion; // Input parameters - Service ccdb; Configurable paramfile{"param-file", "", "Path to the parametrization object, if empty the parametrization is not taken from file"}; Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable ccdbPath{"ccdbPath", "Analysis/PID/TPC/Response", "Path of the TPC parametrization on the CCDB"}; @@ -242,21 +242,18 @@ struct tpcPid { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - ccdbApi.init(url); if (time != 0) { LOGP(info, "Initialising TPC PID response for fixed timestamp {} and reco pass {}:", time, recoPass.value); ccdb->setTimestamp(time); - response = ccdb->getSpecific(path, time, metadata); - headers = ccdbApi.retrieveHeaders(path, metadata, time); + response = ccdb->getSpecific(path, time, metadata, &headers); if (!response) { LOGF(warning, "Unable to find TPC parametrisation for specified pass name - falling back to latest object"); - response = ccdb->getForTimeStamp(path, time); - headers = ccdbApi.retrieveHeaders(path, metadata, time); - networkVersion = headers["NN-Version"]; + response = ccdb->getForTimeStamp(path, time, &headers); if (!response) { LOGF(fatal, "Unable to find any TPC object corresponding to timestamp {}!", time); } } + networkVersion = headers["NN-Version"]; LOG(info) << "Successfully retrieved TPC PID object from CCDB for timestamp " << time << ", period " << headers["LPMProductionTag"] << ", recoPass " << headers["RecoPassName"]; metadata["RecoPassName"] = headers["RecoPassName"]; // Force pass number for NN request to match retrieved BB response->PrintAll(); @@ -274,8 +271,7 @@ struct tpcPid { if (ccdbTimestamp > 0) { /// Fetching network for specific timestamp LOG(info) << "Fetching network for timestamp: " << ccdbTimestamp.value; - bool retrieveSuccess = ccdbApi.retrieveBlob(networkPathCCDB.value, ".", metadata, ccdbTimestamp.value, false, networkPathLocally.value); - headers = ccdbApi.retrieveHeaders(networkPathCCDB.value, metadata, ccdbTimestamp.value); + bool retrieveSuccess = ccdb->getCCDBAccessor().retrieveBlob(networkPathCCDB.value, ".", metadata, ccdbTimestamp.value, false, networkPathLocally.value, "", "", &headers); networkVersion = headers["NN-Version"]; if (retrieveSuccess) { network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); @@ -318,17 +314,15 @@ struct tpcPid { } else { LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); - headers = ccdbApi.retrieveHeaders(ccdbPath.value, metadata, bc.timestamp()); - networkVersion = headers["NN-Version"]; + response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata, &headers); if (!response) { LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); - headers = ccdbApi.retrieveHeaders(ccdbPath.value, nullmetadata, bc.timestamp()); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); + response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp(), &headers); if (!response) { LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } } + networkVersion = headers["NN-Version"]; LOG(info) << "Successfully retrieved TPC PID object from CCDB for timestamp " << bc.timestamp() << ", period " << headers["LPMProductionTag"] << ", recoPass " << headers["RecoPassName"]; metadata["RecoPassName"] = headers["RecoPassName"]; // Force pass number for NN request to match retrieved BB response->PrintAll(); @@ -336,14 +330,13 @@ struct tpcPid { if (bc.timestamp() < network.getValidityFrom() || bc.timestamp() > network.getValidityUntil()) { // fetches network only if the runnumbers change LOG(info) << "Fetching network for timestamp: " << bc.timestamp(); - bool retrieveSuccess = ccdbApi.retrieveBlob(networkPathCCDB.value, ".", metadata, bc.timestamp(), false, networkPathLocally.value); - headers = ccdbApi.retrieveHeaders(networkPathCCDB.value, metadata, bc.timestamp()); + bool retrieveSuccess = ccdb->getCCDBAccessor().retrieveBlob(networkPathCCDB.value, ".", metadata, bc.timestamp(), false, networkPathLocally.value, "", "", &headers); networkVersion = headers["NN-Version"]; if (retrieveSuccess) { network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); std::vector dummyInput(network.getNumInputNodes(), 1.); network.evalModel(dummyInput); - LOGP(info, "Retrieved NN corrections for production tag {}, pass number {}, NN-Version number{}", headers["LPMProductionTag"], headers["RecoPassName"], headers["NN-Version"]); + LOGP(info, "Retrieved NN corrections for production tag {}, pass number {}, NN-Version number {}", headers["LPMProductionTag"], headers["RecoPassName"], headers["NN-Version"]); } else { LOG(fatal) << "No valid NN object found matching retrieved Bethe-Bloch parametrisation for pass " << metadata["RecoPassName"] << ". Please ensure that the requested pass has dedicated NN corrections available"; } @@ -553,12 +546,10 @@ struct tpcPid { } else { LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); - headers = ccdbApi.retrieveHeaders(ccdbPath.value, metadata, bc.timestamp()); + response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata, &headers); if (!response) { LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); - headers = ccdbApi.retrieveHeaders(ccdbPath.value, nullmetadata, bc.timestamp()); + response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp(), &headers); if (!response) { LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } @@ -651,12 +642,11 @@ struct tpcPid { } else { LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); - headers = ccdbApi.retrieveHeaders(ccdbPath.value, metadata, bc.timestamp()); + response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata, &headers); + if (!response) { LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); - headers = ccdbApi.retrieveHeaders(ccdbPath.value, nullmetadata, bc.timestamp()); + response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp(), &headers); if (!response) { LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } @@ -737,10 +727,10 @@ struct tpcPid { } else { LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); + response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata, &headers); if (!response) { LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); + response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp(), &headers); if (!response) { LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } diff --git a/Common/TableProducer/PID/pidTPCService.cxx b/Common/TableProducer/PID/pidTPCService.cxx index 6ad86916c1f..974f29b2106 100644 --- a/Common/TableProducer/PID/pidTPCService.cxx +++ b/Common/TableProducer/PID/pidTPCService.cxx @@ -47,7 +47,6 @@ struct pidTpcService { // CCDB boilerplate declarations o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Service ccdb; - o2::ccdb::CcdbApi ccdbApi; o2::aod::pid::pidTPCProducts products; o2::aod::pid::pidTPCConfigurables pidTPCopts; @@ -61,25 +60,24 @@ struct pidTpcService { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - ccdbApi.init(ccdburl.value); // task-specific - pidTPC.init(ccdb, ccdbApi, initContext, pidTPCopts, metadataInfo); + pidTPC.init(ccdb, initContext, pidTPCopts, metadataInfo); } void processTracksIU(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs) { - pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + pidTPC.process(ccdb, bcs, collisions, tracks, static_cast(nullptr), products); } void processTracksMCIU(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const&) { - pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + pidTPC.process(ccdb, bcs, collisions, tracks, static_cast(nullptr), products); } void processTracksIUWithTracksQA(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs, aod::TracksQAVersion const& tracksQA) { - pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, tracksQA, products); + pidTPC.process(ccdb, bcs, collisions, tracks, tracksQA, products); } PROCESS_SWITCH(pidTpcService, processTracksIU, "Process TracksIU (Run 3)", true); diff --git a/Common/TableProducer/PID/pidTPCServiceRun2.cxx b/Common/TableProducer/PID/pidTPCServiceRun2.cxx index 184fb4eb6e0..642f3bf08b7 100644 --- a/Common/TableProducer/PID/pidTPCServiceRun2.cxx +++ b/Common/TableProducer/PID/pidTPCServiceRun2.cxx @@ -47,7 +47,6 @@ struct pidTpcServiceRun2 { // CCDB boilerplate declarations o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Service ccdb; - o2::ccdb::CcdbApi ccdbApi; o2::aod::pid::pidTPCProducts products; o2::aod::pid::pidTPCConfigurables pidTPCopts; @@ -61,20 +60,19 @@ struct pidTpcServiceRun2 { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - ccdbApi.init(ccdburl.value); // task-specific - pidTPC.init(ccdb, ccdbApi, initContext, pidTPCopts, metadataInfo); + pidTPC.init(ccdb, initContext, pidTPCopts, metadataInfo); } void processTracks(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs) { - pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + pidTPC.process(ccdb, bcs, collisions, tracks, static_cast(nullptr), products); } void processTracksMC(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const&) { - pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + pidTPC.process(ccdb, bcs, collisions, tracks, static_cast(nullptr), products); } PROCESS_SWITCH(pidTpcServiceRun2, processTracks, "Process Tracks", true); diff --git a/Common/TableProducer/fwdtrackextension.cxx b/Common/TableProducer/fwdtrackextension.cxx index c554b2c4fbf..5ffdf73bf7a 100644 --- a/Common/TableProducer/fwdtrackextension.cxx +++ b/Common/TableProducer/fwdtrackextension.cxx @@ -10,21 +10,30 @@ // or submit itself to any jurisdiction. // -// Task performing forward track DCA computation +// \file fwdtrackextension.cxx +// \brief Task performing forward track DCA computation. +// \author Maurice Coquet, maurice.louis.coquet@cern.ch // +#include "Common/Core/fwdtrackUtilities.h" #include "Common/DataModel/TrackSelectionTables.h" +#include +#include +#include +#include #include #include #include #include #include +#include #include #include #include +#include #include using namespace o2; @@ -34,30 +43,68 @@ using namespace o2::framework::expressions; using SMatrix55 = ROOT::Math::SMatrix>; using SMatrix5 = ROOT::Math::SVector; +using MuonsWithCov = soa::Join; + struct FwdTrackExtension { - Produces extendedTrackQuantities; + Produces fwdDCA; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable configCcdbUrl{"configCcdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable refitGlobalMuon{"refitGlobalMuon", false, "Recompute parameters of global muons"}; + + Service fCCDB; + o2::parameters::GRPMagField* grpmag = nullptr; // for run 3, we access GRPMagField from GLO/Config/GRPMagField + int fCurrentRun; // needed to detect if the run changed and trigger update of magnetic field - void process(aod::FwdTracks const& tracks, aod::Collisions const&) + void init(o2::framework::InitContext&) { - for (auto& track : tracks) { + // Load geometry + fCCDB->setURL(configCcdbUrl); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + + if (!o2::base::GeometryManager::isGeometryLoaded()) { + LOGF(info, "Load geometry from CCDB"); + fCCDB->get(geoPath); + } + } + + void process(MuonsWithCov const& tracks, aod::MFTTracks const& /*...*/, o2::aod::BCsWithTimestamps const& /*...*/, aod::Collisions const& /*...*/) + { + for (const auto& track : tracks) { + const auto trackType = track.trackType(); float dcaX = -999; float dcaY = -999; if (track.has_collision()) { - if (track.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack || track.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalForwardTrack || track.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - - auto const& collision = track.collision(); - double chi2 = track.chi2(); - SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); - std::vector v1; - SMatrix55 tcovs(v1.begin(), v1.end()); - o2::track::TrackParCovFwd pars1{track.z(), tpars, tcovs, chi2}; - pars1.propagateToZlinear(collision.posZ()); + auto const& collision = track.collision(); + auto bc = collision.template bc_as(); + if (fCurrentRun != bc.runNumber()) { + grpmag = fCCDB->getForTimeStamp(grpmagPath, bc.timestamp()); + if (grpmag != nullptr) { + LOGF(info, "Init field from GRP"); + o2::base::Propagator::initFieldFromGRP(grpmag); + } + LOGF(info, "Set field for muons"); + o2::mch::TrackExtrap::setField(); + fCurrentRun = bc.runNumber(); + } + const float zField = grpmag->getNominalL3Field(); - dcaX = (pars1.getX() - collision.posX()); - dcaY = (pars1.getY() - collision.posY()); + o2::track::TrackParCovFwd fwdtrack = o2::aod::fwdtrackutils::getTrackParCovFwdShift(track, 0.0); + if (refitGlobalMuon && (trackType == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack || trackType == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalForwardTrack)) { + auto muontrack = track.template matchMCHTrack_as(); + auto mfttrack = track.template matchMFTTrack_as(); + o2::dataformats::GlobalFwdTrack propmuon = o2::aod::fwdtrackutils::propagateMuon(muontrack, muontrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, 0.f, zField); + SMatrix5 tpars(mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()); + SMatrix55 tcovs{}; + o2::track::TrackParCovFwd mft{mfttrack.z(), tpars, tcovs, mfttrack.chi2()}; + fwdtrack = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuon, mft); } + auto proptrack = o2::aod::fwdtrackutils::propagateTrackParCovFwd(fwdtrack, trackType, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, 0.f, zField); + dcaX = (proptrack.getX() - collision.posX()); + dcaY = (proptrack.getY() - collision.posY()); } - extendedTrackQuantities(dcaX, dcaY); + fwdDCA(dcaX, dcaY); } } }; diff --git a/Common/TableProducer/zdcExtraTableProducer.cxx b/Common/TableProducer/zdcExtraTableProducer.cxx index 500854b196b..24e34f058df 100644 --- a/Common/TableProducer/zdcExtraTableProducer.cxx +++ b/Common/TableProducer/zdcExtraTableProducer.cxx @@ -58,17 +58,18 @@ struct ZdcExtraTableProducer { // Event selections Configurable cfgEvSelSel8{"cfgEvSelSel8", true, "Event selection: sel8"}; Configurable cfgEvSelVtxZ{"cfgEvSelVtxZ", 10, "Event selection: zVtx"}; - Configurable cfgEvSelsDoOccupancySel{"cfgEvSelsDoOccupancySel", true, "Event selection: do occupancy selection"}; + Configurable cfgEvSelsDoOccupancySel{"cfgEvSelsDoOccupancySel", false, "Event selection: do occupancy selection"}; Configurable cfgEvSelsMaxOccupancy{"cfgEvSelsMaxOccupancy", 10000, "Event selection: set max occupancy"}; - Configurable cfgEvSelsNoSameBunchPileupCut{"cfgEvSelsNoSameBunchPileupCut", true, "Event selection: no same bunch pileup cut"}; - Configurable cfgEvSelsIsGoodZvtxFT0vsPV{"cfgEvSelsIsGoodZvtxFT0vsPV", true, "Event selection: is good ZVTX FT0 vs PV"}; - Configurable cfgEvSelsNoCollInTimeRangeStandard{"cfgEvSelsNoCollInTimeRangeStandard", true, "Event selection: no collision in time range standard"}; - Configurable cfgEvSelsIsVertexITSTPC{"cfgEvSelsIsVertexITSTPC", true, "Event selection: is vertex ITSTPC"}; - Configurable cfgEvSelsIsGoodITSLayersAll{"cfgEvSelsIsGoodITSLayersAll", true, "Event selection: is good ITS layers all"}; + Configurable cfgEvSelsNoSameBunchPileupCut{"cfgEvSelsNoSameBunchPileupCut", false, "Event selection: no same bunch pileup cut"}; + Configurable cfgEvSelsIsGoodZvtxFT0vsPV{"cfgEvSelsIsGoodZvtxFT0vsPV", false, "Event selection: is good ZVTX FT0 vs PV"}; + Configurable cfgEvSelsNoCollInTimeRangeStandard{"cfgEvSelsNoCollInTimeRangeStandard", false, "Event selection: no collision in time range standard"}; + Configurable cfgEvSelsIsVertexITSTPC{"cfgEvSelsIsVertexITSTPC", false, "Event selection: is vertex ITSTPC"}; + Configurable cfgEvSelsIsGoodITSLayersAll{"cfgEvSelsIsGoodITSLayersAll", false, "Event selection: is good ITS layers all"}; // Calibration settings Configurable cfgCalibrationDownscaling{"cfgCalibrationDownscaling", 1.f, "Percentage of events to be saved to derived table"}; - HistogramRegistry registry{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Output settings + Configurable cfgSaveQaHistos{"cfgSaveQaHistos", false, "Flag to save QA histograms"}; enum SelectionCriteria { evSel_zvtx, @@ -83,8 +84,27 @@ struct ZdcExtraTableProducer { nEventSelections }; + HistogramRegistry registry{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(InitContext const&) { + + registry.add("hEventCount", "Number of Event; Cut; #Events Passed Cut", {HistType::kTH1D, {{nEventSelections, 0, nEventSelections}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_allEvents + 1, "All events"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_zvtx + 1, "vtxZ"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_sel8 + 1, "Sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_occupancy + 1, "kOccupancy"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoSameBunchPileup + 1, "kNoSameBunchPileup"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoCollInTimeRangeStandard + 1, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsVertexITSTPC + 1, "kIsVertexITSTPC"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayersAll + 1, "kIsGoodITSLayersAll"); + + // Skip histogram registration if QA flag is false + if (!cfgSaveQaHistos) { + return; + } + registry.add("ZNApmc", "ZNApmc; ZNA PMC; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); registry.add("ZNCpmc", "ZNCpmc; ZNC PMC; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); registry.add("ZNApm1", "ZNApm1; ZNA PM1; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); @@ -100,17 +120,6 @@ struct ZdcExtraTableProducer { registry.add("ZNACentroid", "ZNA Centroid; X; Y", {HistType::kTH2F, {{50, -1.5, 1.5}, {50, -1.5, 1.5}}}); registry.add("ZNCCentroid", "ZNC Centroid; X; Y", {HistType::kTH2F, {{50, -1.5, 1.5}, {50, -1.5, 1.5}}}); - - registry.add("hEventCount", "Number of Event; Cut; #Events Passed Cut", {HistType::kTH1D, {{nEventSelections, 0, nEventSelections}}}); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_allEvents + 1, "All events"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_zvtx + 1, "vtxZ"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_sel8 + 1, "Sel8"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_occupancy + 1, "kOccupancy"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoSameBunchPileup + 1, "kNoSameBunchPileup"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoCollInTimeRangeStandard + 1, "kNoCollInTimeRangeStandard"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsVertexITSTPC + 1, "kIsVertexITSTPC"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayersAll + 1, "kIsGoodITSLayersAll"); } template @@ -176,7 +185,7 @@ struct ZdcExtraTableProducer { void process(ColEvSels const& cols, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcs*/) { // collision-based event selection - int nTowers = 4; // number of ZDC towers + constexpr int NTowers = 4; // number of ZDC towers for (auto const& collision : cols) { const auto& foundBC = collision.foundBC_as(); @@ -185,6 +194,24 @@ struct ZdcExtraTableProducer { uint8_t evSelection = eventSelected(collision); + // add event selection + if (cfgEvSelSel8 && !(evSelection & (1 << evSel_sel8))) + continue; + if (!(evSelection & (1 << evSel_zvtx))) + continue; + if (cfgEvSelsDoOccupancySel && !(evSelection & (1 << evSel_occupancy))) + continue; + if (cfgEvSelsNoSameBunchPileupCut && !(evSelection & (1 << evSel_kNoSameBunchPileup))) + continue; + if (cfgEvSelsIsGoodZvtxFT0vsPV && !(evSelection & (1 << evSel_kIsGoodZvtxFT0vsPV))) + continue; + if (cfgEvSelsNoCollInTimeRangeStandard && !(evSelection & (1 << evSel_kNoCollInTimeRangeStandard))) + continue; + if (cfgEvSelsIsVertexITSTPC && !(evSelection & (1 << evSel_kIsVertexITSTPC))) + continue; + if (cfgEvSelsIsGoodITSLayersAll && !(evSelection & (1 << evSel_kIsGoodITSLayersAll))) + continue; + float centrality = collision.centFT0C(); // To assure that ZN have a genuine signal (tagged by the relative TDC) @@ -196,6 +223,7 @@ struct ZdcExtraTableProducer { // double tdcZNC = zdc.timeZNC(); double tdcZNA = zdc.timeZNA(); + // OR we can select a narrow window in both ZN TDCs using the configurable parameters if (tdcCut) { // a narrow TDC window is set if ((tdcZNC >= tdcZNmincut) && (tdcZNC <= tdcZNmaxcut)) { @@ -219,29 +247,34 @@ struct ZdcExtraTableProducer { double pmqZNA[4] = {}; // if (isZNChit) { - for (int it = 0; it < nTowers; it++) { + for (int it = 0; it < NTowers; it++) { pmqZNC[it] = (zdc.energySectorZNC())[it]; sumZNC += pmqZNC[it]; } - registry.get(HIST("ZNCpmc"))->Fill(pmcZNC); - registry.get(HIST("ZNCpm1"))->Fill(pmqZNC[0]); - registry.get(HIST("ZNCpm2"))->Fill(pmqZNC[1]); - registry.get(HIST("ZNCpm3"))->Fill(pmqZNC[2]); - registry.get(HIST("ZNCpm4"))->Fill(pmqZNC[3]); - registry.get(HIST("ZNCsumq"))->Fill(sumZNC); + + if (cfgSaveQaHistos) { + registry.get(HIST("ZNCpmc"))->Fill(pmcZNC); + registry.get(HIST("ZNCpm1"))->Fill(pmqZNC[0]); + registry.get(HIST("ZNCpm2"))->Fill(pmqZNC[1]); + registry.get(HIST("ZNCpm3"))->Fill(pmqZNC[2]); + registry.get(HIST("ZNCpm4"))->Fill(pmqZNC[3]); + registry.get(HIST("ZNCsumq"))->Fill(sumZNC); + } } if (isZNAhit) { - for (int it = 0; it < nTowers; it++) { + for (int it = 0; it < NTowers; it++) { pmqZNA[it] = (zdc.energySectorZNA())[it]; sumZNA += pmqZNA[it]; } // - registry.get(HIST("ZNApmc"))->Fill(pmcZNA); - registry.get(HIST("ZNApm1"))->Fill(pmqZNA[0]); - registry.get(HIST("ZNApm2"))->Fill(pmqZNA[1]); - registry.get(HIST("ZNApm3"))->Fill(pmqZNA[2]); - registry.get(HIST("ZNApm4"))->Fill(pmqZNA[3]); - registry.get(HIST("ZNAsumq"))->Fill(sumZNA); + if (cfgSaveQaHistos) { + registry.get(HIST("ZNApmc"))->Fill(pmcZNA); + registry.get(HIST("ZNApm1"))->Fill(pmqZNA[0]); + registry.get(HIST("ZNApm2"))->Fill(pmqZNA[1]); + registry.get(HIST("ZNApm3"))->Fill(pmqZNA[2]); + registry.get(HIST("ZNApm4"))->Fill(pmqZNA[3]); + registry.get(HIST("ZNAsumq"))->Fill(sumZNA); + } } // Q-vectors (centroid) calculation @@ -257,8 +290,7 @@ struct ZdcExtraTableProducer { float numXZNA = 0., numYZNA = 0., denZNA = 0.; // Calculate weighted sums of the x and y coordinates - constexpr int kNTowers = 4; // number of ZDC towers - for (int i = 0; i < kNTowers; i++) { + for (int i = 0; i < NTowers; i++) { if (pmqZNC[i] > 0.) { float wZNC = std::pow(pmqZNC[i], kAlpha); numXZNC -= X[i] * wZNC; // numerator x (minus sign due to opposite orientation of ZNC) @@ -307,8 +339,14 @@ struct ZdcExtraTableProducer { centroidZNA[0] = 999.; centroidZNA[1] = 999.; } - registry.get(HIST("ZNCCentroid"))->Fill(centroidZNC[0], centroidZNC[1]); - registry.get(HIST("ZNACentroid"))->Fill(centroidZNA[0], centroidZNA[1]); + if (cfgSaveQaHistos) { + if (isZNChit) { + registry.get(HIST("ZNCCentroid"))->Fill(centroidZNC[0], centroidZNC[1]); + } + if (isZNAhit) { + registry.get(HIST("ZNACentroid"))->Fill(centroidZNA[0], centroidZNA[1]); + } + } auto vz = collision.posZ(); auto vx = collision.posX(); diff --git a/Common/Tasks/integrationTestCCDB.cxx b/Common/Tasks/integrationTestCCDB.cxx index c7096d5774c..d1fe98d142c 100644 --- a/Common/Tasks/integrationTestCCDB.cxx +++ b/Common/Tasks/integrationTestCCDB.cxx @@ -103,12 +103,12 @@ struct integrationTestCCDB { lut = 0x0; const AxisSpec axis{1, 0.0f, 1.0f, ""}; histos.add("hDFs", "hDFs", HistType::kTH1F, {axis}); + + mRunNumber = 0; } void process(aod::BCsWithTimestamps const& bcs) { - mRunNumber = 0; - auto bc = bcs.begin(); // first element histos.fill(HIST("hDFs"), 0.5f); diff --git a/Common/Tools/EventSelectionModule.h b/Common/Tools/EventSelectionModule.h index 344ad7578da..f808b70fb85 100644 --- a/Common/Tools/EventSelectionModule.h +++ b/Common/Tools/EventSelectionModule.h @@ -1514,10 +1514,14 @@ class EventSelectionModule // apply int7-like selections bool sel7 = 0; - // TODO apply other cuts for sel8 - // TODO introduce sel1 etc? + // Combination of bits for Run 3 event selection decisions + // TODO apply other cuts for sel8? // TODO introduce array of sel[0]... sel[8] or similar? - bool sel8 = bitcheck64(bcselEntry.selection, aod::evsel::kIsTriggerTVX) && bitcheck64(bcselEntry.selection, aod::evsel::kNoTimeFrameBorder) && bitcheck64(bcselEntry.selection, aod::evsel::kNoITSROFrameBorder); + bool sel8 = false; + if (lastRun < 568873) // pre-2026 data & MC: require all three bits: TVX, TF and ROF border cuts + sel8 = bitcheck64(bcselEntry.selection, aod::evsel::kIsTriggerTVX) && bitcheck64(bcselEntry.selection, aod::evsel::kNoTimeFrameBorder) && bitcheck64(bcselEntry.selection, aod::evsel::kNoITSROFrameBorder); + else // for pp 2026: sel8 without kNoITSROFrameBorder bit, because the cross-ROF reconstruction for ITS will be On (the switch by a runNumber is a temporary solution) + sel8 = bitcheck64(bcselEntry.selection, aod::evsel::kIsTriggerTVX) && bitcheck64(bcselEntry.selection, aod::evsel::kNoTimeFrameBorder); // fill counters histos.template get(HIST("eventselection/hColCounterAll"))->Fill(Form("%d", bc.runNumber()), 1); diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx index c7a669f816b..44d7cbe79de 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx @@ -384,7 +384,7 @@ Double_t multGlauberNBDFitter::ContinuousNBD(Double_t n, Double_t mu, Double_t k return F; } -void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange, Double_t lHiRange, TH3D* lNpNcEcc, TH2F* lEcc2DPlot) +void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange, Double_t lHiRange, TH3D* lNpNcEcc, TH2F* lEcc2DPlot, TH3D* lNpNcB, TH2F* lB2DPlot, TH2F* lNancestor2DPlot, Double_t fProbabilityCutoff) { cout << "Calculating , in centrality bins..." << endl; cout << "Range to calculate: " << lLoRange << " to " << lHiRange << endl; @@ -415,28 +415,56 @@ void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCol } // bypass to zero for (int ibin = 0; ibin < fNNpNcPairs; ibin++) { - if (ibin % 2000 == 0) + if (ibin % 200 == 0) cout << "At NpNc pair #" << ibin << " of " << fNNpNcPairs << "..." << endl; Double_t lNAncestors0 = (Int_t)(fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff)); Double_t lNAncestors1 = TMath::Floor(fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff) + 0.5); Double_t lNAncestors2 = (fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff)); - TH1D* hEccentricity = 0x0; + // define ancestors officially + Double_t lNancestors = lNAncestors0; + if (fAncestorMode == 1) + lNancestors = lNAncestors1; + if (fAncestorMode == 2) + lNancestors = lNAncestors2; + // eccentricity handling + TH1D* hEccentricity = 0x0; if (lNpNcEcc) { // locate the histogram that corresponds to the eccentricity distribution in this NpNc pair lNpNcEcc->GetXaxis()->SetRange(lNpNcEcc->GetXaxis()->FindBin(fNpart[ibin]), lNpNcEcc->GetXaxis()->FindBin(fNpart[ibin])); lNpNcEcc->GetYaxis()->SetRange(lNpNcEcc->GetYaxis()->FindBin(fNcoll[ibin]), lNpNcEcc->GetYaxis()->FindBin(fNcoll[ibin])); hEccentricity = reinterpret_cast(lNpNcEcc->Project3D("z")); hEccentricity->SetName(Form("hEccentricity_%i", ibin)); + + // normalize into unitary fractions + Double_t eccIntegral = hEccentricity->Integral(1, hEccentricity->GetNbinsX() + 1); + if (eccIntegral > 1e-6) { // no counts + hEccentricity->Scale(1. / eccIntegral); + } else { + hEccentricity->Scale(0.0); + } + } + + // impact parameter handling + TH1D* hImpactParameter = 0x0; + if (lNpNcB) { + // locate the histogram that corresponds to the eccentricity distribution in this NpNc pair + lNpNcB->GetXaxis()->SetRange(lNpNcB->GetXaxis()->FindBin(fNpart[ibin]), lNpNcB->GetXaxis()->FindBin(fNpart[ibin])); + lNpNcB->GetYaxis()->SetRange(lNpNcB->GetYaxis()->FindBin(fNcoll[ibin]), lNpNcB->GetYaxis()->FindBin(fNcoll[ibin])); + hImpactParameter = reinterpret_cast(lNpNcB->Project3D("z")); + hImpactParameter->SetName(Form("hImpactParameter_%i", ibin)); + + // normalize into unitary fractions + Double_t bIntegral = hImpactParameter->Integral(1, hImpactParameter->GetNbinsX() + 1); + if (bIntegral > 1e-6) { // no counts + hImpactParameter->Scale(1. / bIntegral); + } else { + hImpactParameter->Scale(0.0); + } } for (Long_t lMultValue = 1; lMultValue < lHiRange; lMultValue++) { - Double_t lNancestors = lNAncestors0; - if (fAncestorMode == 1) - lNancestors = lNAncestors1; - if (fAncestorMode == 2) - lNancestors = lNAncestors2; Double_t lNancestorCount = fContent[ibin]; Double_t lThisMu = (((Double_t)lNancestors)) * fMu; Double_t lThisk = (((Double_t)lNancestors)) * fk; @@ -447,11 +475,20 @@ void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCol if (lMultValue > 1e-6) lMult = fAncestorMode != 2 ? fNBD->Eval(lMultValue) : ContinuousNBD(lMultValue, lThisMu, lThisk); Double_t lProbability = lNancestorCount * lMult; + + if (lProbability < fProbabilityCutoff) { + continue; // skip if probability of contributing too small + } + Double_t lMultValueToFill = lMultValue; if (hPercentileMap) lMultValueToFill = hPercentileMap->GetBinContent(hPercentileMap->FindBin(lMultValue)); lNPartProf->Fill(lMultValueToFill, fNpart[ibin], lProbability); lNCollProf->Fill(lMultValueToFill, fNcoll[ibin], lProbability); + if (lNancestor2DPlot) { + // fill cross-check histogram with lNancestorCount at lNancestors value + lNancestor2DPlot->Fill(lMultValueToFill, lNancestors, lProbability); + } if (lNPart2DPlot) lNPart2DPlot->Fill(lMultValueToFill, fNpart[ibin], lProbability); if (lNColl2DPlot) @@ -462,6 +499,12 @@ void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCol lEcc2DPlot->Fill(lMultValueToFill, hEccentricity->GetBinCenter(ib), lProbability * hEccentricity->GetBinContent(ib)); } } + if (lNpNcB) { + // collapse the entire impact parameter distribution for this combo + for (int ib = 1; ib < hImpactParameter->GetNbinsX() + 1; ib++) { + lB2DPlot->Fill(lMultValueToFill, hImpactParameter->GetBinCenter(ib), lProbability * hImpactParameter->GetBinContent(ib)); + } + } } } } diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.h b/Common/Tools/Multiplicity/multGlauberNBDFitter.h index 889398fad1a..598ef312ce9 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.h +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.h @@ -78,7 +78,8 @@ class multGlauberNBDFitter : public TNamed Double_t ContinuousNBD(Double_t n, Double_t mu, Double_t k); // For estimating Npart, Ncoll in multiplicity bins - void CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange = -1, Double_t lHiRange = -1, TH3D* lNpNcEcc = 0x0, TH2F* lEcc2DPlot = 0x0); + // also viable: eccentricity, impact parameter, ancestor cross-check plot + void CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange = -1, Double_t lHiRange = -1, TH3D* lNpNcEcc = 0x0, TH2F* lEcc2DPlot = 0x0, TH3D* lNpNcB = 0x0, TH2F* lB2DPlot = 0x0, TH2F* lNancestor2DPlot = 0x0, Double_t fProbabilityCutoff = -1); // void Print(Option_t *option="") const; diff --git a/Common/Tools/PID/pidTPCModule.h b/Common/Tools/PID/pidTPCModule.h index 990ab5b7266..efe9dc56ded 100644 --- a/Common/Tools/PID/pidTPCModule.h +++ b/Common/Tools/PID/pidTPCModule.h @@ -209,7 +209,6 @@ class pidTPCModule // Network correction for TPC PID response ml::OnnxModel network; std::map metadata; - std::map nullmetadata; std::map headers; std::vector speciesNetworkFlags = std::vector(9); std::string networkVersion; @@ -226,8 +225,8 @@ class pidTPCModule Str_dEdx_correction str_dedx_correction; //__________________________________________________ - template - void init(TCCDB& ccdb, TCCDBApi& ccdbApi, TContext& context, TpidTPCOpts const& external_pidtpcopts, TMetadataInfo const& metadataInfo) + template + void init(TCCDB& ccdb, TContext& context, TpidTPCOpts const& external_pidtpcopts, TMetadataInfo const& metadataInfo) { // read in configurations from the task where it's used pidTPCopts = external_pidtpcopts; @@ -369,17 +368,15 @@ class pidTPCModule if (time != 0) { LOGP(info, "Initialising TPC PID response for fixed timestamp {} and reco pass {}:", time, pidTPCopts.recoPass.value); ccdb->setTimestamp(time); - response = ccdb->template getSpecific(path, time, metadata); - headers = ccdbApi.retrieveHeaders(path, metadata, time); + response = ccdb->template getSpecific(path, time, metadata, &headers); if (!response) { LOGF(warning, "Unable to find TPC parametrisation for specified pass name - falling back to latest object"); - response = ccdb->template getForTimeStamp(path, time); - headers = ccdbApi.retrieveHeaders(path, metadata, time); - networkVersion = headers["NN-Version"]; + response = ccdb->template getForTimeStamp(path, time, &headers); if (!response) { LOGF(fatal, "Unable to find any TPC object corresponding to timestamp {}!", time); } } + networkVersion = headers["NN-Version"]; LOG(info) << "Successfully retrieved TPC PID object from CCDB for timestamp " << time << ", period " << headers["LPMProductionTag"] << ", recoPass " << headers["RecoPassName"]; metadata["RecoPassName"] = headers["RecoPassName"]; // Force pass number for NN request to match retrieved BB o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp(pidTPCopts.cfgPathGrpLhcIf.value, time); @@ -407,8 +404,7 @@ class pidTPCModule if (pidTPCopts.ccdbTimestamp > 0) { /// Fetching network for specific timestamp LOG(info) << "Fetching network for timestamp: " << pidTPCopts.ccdbTimestamp.value; - bool retrieveSuccess = ccdbApi.retrieveBlob(pidTPCopts.networkPathCCDB.value, ".", metadata, pidTPCopts.ccdbTimestamp.value, false, pidTPCopts.networkPathLocally.value); - headers = ccdbApi.retrieveHeaders(pidTPCopts.networkPathCCDB.value, metadata, pidTPCopts.ccdbTimestamp.value); + bool retrieveSuccess = ccdb->getCCDBAccessor().retrieveBlob(pidTPCopts.networkPathCCDB.value, ".", metadata, pidTPCopts.ccdbTimestamp.value, false, pidTPCopts.networkPathLocally.value, "", "", &headers); networkVersion = headers["NN-Version"]; if (retrieveSuccess) { network.initModel(pidTPCopts.networkPathLocally.value, pidTPCopts.enableNetworkOptimizations.value, pidTPCopts.networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); @@ -439,8 +435,8 @@ class pidTPCModule } // end init //__________________________________________________ - template - std::vector createNetworkPrediction(TCCDB& ccdb, TCCDBApi& ccdbApi, soa::Join const& collisions, M const& mults, T const& tracks, B const& bcs, const size_t size) + template + std::vector createNetworkPrediction(TCCDB& ccdb, soa::Join const& collisions, M const& mults, T const& tracks, B const& bcs, const size_t size) { std::vector network_prediction; @@ -455,13 +451,11 @@ class pidTPCModule } else { LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), pidTPCopts.recoPass.value); } - response = ccdb->template getSpecific(pidTPCopts.ccdbPath.value, bc.timestamp(), metadata); - headers = ccdbApi.retrieveHeaders(pidTPCopts.ccdbPath.value, metadata, bc.timestamp()); + response = ccdb->template getSpecific(pidTPCopts.ccdbPath.value, bc.timestamp(), metadata, &headers); networkVersion = headers["NN-Version"]; if (!response) { LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); - headers = ccdbApi.retrieveHeaders(pidTPCopts.ccdbPath.value, nullmetadata, bc.timestamp()); - response = ccdb->template getForTimeStamp(pidTPCopts.ccdbPath.value, bc.timestamp()); + response = ccdb->template getForTimeStamp(pidTPCopts.ccdbPath.value, bc.timestamp(), &headers); if (!response) { LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } @@ -485,14 +479,13 @@ class pidTPCModule if (bc.timestamp() < network.getValidityFrom() || bc.timestamp() > network.getValidityUntil()) { // fetches network only if the runnumbers change LOG(info) << "Fetching network for timestamp: " << bc.timestamp(); - bool retrieveSuccess = ccdbApi.retrieveBlob(pidTPCopts.networkPathCCDB.value, ".", metadata, bc.timestamp(), false, pidTPCopts.networkPathLocally.value); - headers = ccdbApi.retrieveHeaders(pidTPCopts.networkPathCCDB.value, metadata, bc.timestamp()); + bool retrieveSuccess = ccdb->getCCDBAccessor().retrieveBlob(pidTPCopts.networkPathCCDB.value, ".", metadata, bc.timestamp(), false, pidTPCopts.networkPathLocally.value, "", "", &headers); networkVersion = headers["NN-Version"]; if (retrieveSuccess) { network.initModel(pidTPCopts.networkPathLocally.value, pidTPCopts.enableNetworkOptimizations.value, pidTPCopts.networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); std::vector dummyInput(network.getNumInputNodes(), 1.); network.evalModel(dummyInput); - LOGP(info, "Retrieved NN corrections for production tag {}, pass number {}, NN-Version number{}", headers["LPMProductionTag"], headers["RecoPassName"], headers["NN-Version"]); + LOGP(info, "Retrieved NN corrections for production tag {}, pass number {}, NN-Version number {}", headers["LPMProductionTag"], headers["RecoPassName"], headers["NN-Version"]); } else { LOG(fatal) << "No valid NN object found matching retrieved Bethe-Bloch parametrisation for pass " << metadata["RecoPassName"] << ". Please ensure that the requested pass has dedicated NN corrections available"; } @@ -677,7 +670,7 @@ class pidTPCModule nSigma = (tpcSignal / expSignal - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 2]); } } else { - LOGF(fatal, "Network output-dimensions incompatible!"); + LOGF(fatal, "Network output dimensions incompatible!"); } } else { nSigma = response->GetNumberOfSigmaMCTunedAtMultiplicity(multTPC, trk, pid, tpcSignal); @@ -689,8 +682,8 @@ class pidTPCModule }; //__________________________________________________ - template - void process(TCCDB& ccdb, TCCDBApi& ccdbApi, TBCs const& bcs, soa::Join const& cols, TTracks const& tracks, TTracksQA const& tracksQA, TProducts& products) + template + void process(TCCDB& ccdb, TBCs const& bcs, soa::Join const& cols, TTracks const& tracks, TTracksQA const& tracksQA, TProducts& products) { if (tracks.size() == 0) { return; // empty protection @@ -753,7 +746,7 @@ class pidTPCModule std::vector network_prediction; if (pidTPCopts.useNetworkCorrection) { - network_prediction = createNetworkPrediction(ccdb, ccdbApi, cols, pidmults, tracks, bcs, tracksForNet_size); + network_prediction = createNetworkPrediction(ccdb, cols, pidmults, tracks, bcs, tracksForNet_size); } uint64_t count_tracks = 0; @@ -883,12 +876,10 @@ class pidTPCModule } else { LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), pidTPCopts.recoPass.value); } - response = ccdb->template getSpecific(pidTPCopts.ccdbPath.value, bc.timestamp(), metadata); - headers = ccdbApi.retrieveHeaders(pidTPCopts.ccdbPath.value, metadata, bc.timestamp()); + response = ccdb->template getSpecific(pidTPCopts.ccdbPath.value, bc.timestamp(), metadata, &headers); if (!response) { LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); - response = ccdb->template getForTimeStamp(pidTPCopts.ccdbPath.value, bc.timestamp()); - headers = ccdbApi.retrieveHeaders(pidTPCopts.ccdbPath.value, nullmetadata, bc.timestamp()); + response = ccdb->template getForTimeStamp(pidTPCopts.ccdbPath.value, bc.timestamp(), &headers); if (!response) { LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } diff --git a/Common/Tools/TrackTuner.h b/Common/Tools/TrackTuner.h index 665fd395b24..01ca6930d89 100644 --- a/Common/Tools/TrackTuner.h +++ b/Common/Tools/TrackTuner.h @@ -189,6 +189,10 @@ struct TrackTuner : o2::framework::ConfigurableGroup { LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: 564356 <= runNumber && runNumber <= 564445 +++"; LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 5]: OO, 5.36 TeV 2025, period LHC25af: CCDB path Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25af +++"; LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: 564468 <= runNumber && runNumber <= 564472 +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 6]: pp, 5.36 TeV 2024, period LHC24ap: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2024/ppRef/polarity_positive +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: 559348 <= runNumber && runNumber <= 559387 +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 7]: pp, 5.36 TeV 2024, period LHC24aq: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2024/ppRef/polarity_negative +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: 559408 <= runNumber && runNumber <= 559456 +++"; LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; LOG(info) << ""; @@ -234,6 +238,22 @@ struct TrackTuner : o2::framework::ConfigurableGroup { pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25af"; LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> OO, 5.36 TeV 2025, period LHC25af: CCDB path " << pathInputFile; LOG(info) << " >>> Run list: 564468 <= runNumber && runNumber <= 564472"; + } else if (559348 <= runNumber && runNumber <= 559387) { + /// + /// [CASE 6]: pp, 5.36 TeV 2024, period LHC24ap: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2024/ppRef/polarity_positive + /// Run list: 559348 <= runNumber && runNumber <= 559387 + /// + pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/pp2024/ppRef/polarity_positive"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> pp, 5.36 TeV 2024, period LHC24ap: CCDB path " << pathInputFile; + LOG(info) << " >>> Run list: 559348 <= runNumber && runNumber <= 559387"; + } else if (559408 <= runNumber && runNumber <= 559456) { + /// + /// [CASE 7]: pp, 5.36 TeV 2024, period LHC24aq: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2024/ppRef/polarity_negative + /// Run list: 559408 <= runNumber && runNumber <= 559456 + /// + pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/pp2024/ppRef/polarity_negative"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> pp, 5.36 TeV 2024, period LHC24aq: CCDB path " << pathInputFile; + LOG(info) << " >>> Run list: 559408 <= runNumber && runNumber <= 559456"; } else { LOG(fatal) << "runNumber " << runNumber << " not supported for the autodetection. Please switch to manual configuration of the TrackTuner object. Aborting..."; } @@ -735,19 +755,24 @@ struct TrackTuner : o2::framework::ConfigurableGroup { dcaZResMC = evalGraph(ptMC, grDcaZResVsPtPionMC[phiBin].get()); dcaZResData = evalGraph(ptMC, grDcaZResVsPtPionData[phiBin].get()); - // For Q/Pt corrections, files on CCDB will be used if both qOverPtMC and qOverPtData are null + // Local Q/Pt resolution: either the constant configurable value, or evaluated per-track from graphs + double smearQOverPtMC = qOverPtMC; + double smearQOverPtData = qOverPtData; if (updateCurvature || updateCurvatureIU) { - if ((qOverPtMC < 0) || (qOverPtData < 0)) { - if (debugInfo) { - LOG(info) << "### q/pt smearing: qOverPtMC=" << qOverPtMC << ", qOverPtData=" << qOverPtData << ". One of them is negative. Retrieving then values from graphs from input .root file"; - } + if ((smearQOverPtMC < 0) || (smearQOverPtData < 0)) { /// check that input graphs for q/pt smearing are correctly retrieved if (!grOneOverPtPionData.get() || !grOneOverPtPionMC.get()) { LOG(fatal) << "### q/pt smearing: input graphs not correctly retrieved. Aborting."; } - qOverPtMC = std::max(0.0, evalGraph(ptMC, grOneOverPtPionMC.get())); - qOverPtData = std::max(0.0, evalGraph(ptMC, grOneOverPtPionData.get())); - } // qOverPtMC, qOverPtData block ends here + smearQOverPtMC = std::max(0.0, evalGraph(ptMC, grOneOverPtPionMC.get())); + smearQOverPtData = std::max(0.0, evalGraph(ptMC, grOneOverPtPionData.get())); + if (debugInfo) { + LOG(info) << "### q/pt graph-based smearing: pT=" << ptMC + << " sigma(1/pT)_MC=" << smearQOverPtMC + << " sigma(1/pT)_Data=" << smearQOverPtData + << " ratio(Data/MC)=" << (smearQOverPtMC > 0. ? smearQOverPtData / smearQOverPtMC : -1.); + } + } // smearQOverPtMC, smearQOverPtData block ends here } // updateCurvature, updateCurvatureIU block ends here if (updateTrackDCAs) { @@ -816,7 +841,7 @@ struct TrackTuner : o2::framework::ConfigurableGroup { // double dpt1o =pt1o-pt1mc; deltaQpt = trackParQPtMCRec - trackParQPtMC; // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); - deltaQptTuned = deltaQpt * (qOverPtMC > 0. ? (qOverPtData / qOverPtMC) : 1.); + deltaQptTuned = deltaQpt * (smearQOverPtMC > 0. ? (smearQOverPtData / smearQOverPtMC) : 1.); // double pt1n = pt1mc+dpt1n; trackParQPtTuned = trackParQPtMC + deltaQptTuned; trackParCov.setQ2Pt(trackParQPtTuned); @@ -824,36 +849,36 @@ struct TrackTuner : o2::framework::ConfigurableGroup { // updating track cov matrix elements for 1/Pt at innermost update point // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt sigma1PtY = trackParCov.getSigma1PtY(); - if (dcaXYResMC > 0. && qOverPtMC > 0.) { - sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (qOverPtData / qOverPtMC)); + if (dcaXYResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtY, 10); } // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt sigma1PtZ = trackParCov.getSigma1PtZ(); - if (dcaZResMC > 0. && qOverPtMC > 0.) { - sigma1PtZ *= ((dcaZResData / dcaZResMC) * (qOverPtData / qOverPtMC)); + if (dcaZResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtZ, 11); } // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt sigma1PtSnp = trackParCov.getSigma1PtSnp(); - if (qOverPtMC > 0.) { - sigma1PtSnp *= (qOverPtData / qOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtSnp *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtSnp, 12); } // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt sigma1PtTgl = trackParCov.getSigma1PtTgl(); - if (qOverPtMC > 0.) { - sigma1PtTgl *= (qOverPtData / qOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtTgl *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtTgl, 13); } // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt sigma1Pt2 = trackParCov.getSigma1Pt2(); - if (qOverPtMC > 0.) { - sigma1Pt2 *= (qOverPtData / qOverPtMC) * (qOverPtData / qOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1Pt2 *= (smearQOverPtData / smearQOverPtMC) * (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1Pt2, 14); } } // updateCurvatureIU block ends here @@ -949,7 +974,7 @@ struct TrackTuner : o2::framework::ConfigurableGroup { } deltaQpt = trackParQPtMCRec - trackParQPtMC; // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); - deltaQptTuned = deltaQpt * (qOverPtMC > 0. ? (qOverPtData / qOverPtMC) : 1.); + deltaQptTuned = deltaQpt * (smearQOverPtMC > 0. ? (smearQOverPtData / smearQOverPtMC) : 1.); // double pt1n = pt1mc+dpt1n; trackParQPtTuned = trackParQPtMC + deltaQptTuned; trackParCov.setQ2Pt(trackParQPtTuned); @@ -1010,36 +1035,36 @@ struct TrackTuner : o2::framework::ConfigurableGroup { if ((updateCurvature) && (!updateCurvatureIU)) { // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt sigma1PtY = trackParCov.getSigma1PtY(); - if (dcaXYResMC > 0. && qOverPtMC > 0.) { - sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (qOverPtData / qOverPtMC)); + if (dcaXYResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtY, 10); } // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt sigma1PtZ = trackParCov.getSigma1PtZ(); - if (dcaZResMC > 0. && qOverPtMC > 0.) { - sigma1PtZ *= ((dcaZResData / dcaZResMC) * (qOverPtData / qOverPtMC)); + if (dcaZResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtZ, 11); } // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt sigma1PtSnp = trackParCov.getSigma1PtSnp(); - if (qOverPtMC > 0.) { - sigma1PtSnp *= (qOverPtData / qOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtSnp *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtSnp, 12); } // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt sigma1PtTgl = trackParCov.getSigma1PtTgl(); - if (qOverPtMC > 0.) { - sigma1PtTgl *= (qOverPtData / qOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtTgl *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtTgl, 13); } // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt sigma1Pt2 = trackParCov.getSigma1Pt2(); - if (qOverPtMC > 0.) { - sigma1Pt2 *= (qOverPtData / qOverPtMC) * (qOverPtData / qOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1Pt2 *= (smearQOverPtData / smearQOverPtMC) * (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1Pt2, 14); } } // ---> track cov matrix elements for 1/Pt ends here diff --git a/DPG/Tasks/AOTEvent/lumiQa.cxx b/DPG/Tasks/AOTEvent/lumiQa.cxx index 254e58f0b67..fa244f31861 100644 --- a/DPG/Tasks/AOTEvent/lumiQa.cxx +++ b/DPG/Tasks/AOTEvent/lumiQa.cxx @@ -9,24 +9,29 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "CCDB/BasicCCDBManager.h" -#include "Framework/HistogramRegistry.h" -#include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsFT0/Digit.h" -#include "TList.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include + #include "TH1.h" +#include "TList.h" using namespace o2; using namespace o2::framework; using BCsRun3 = soa::Join; struct LumiQaTask { + Configurable confTimeBinWidthInSec{"TimeBinWidthInSec", 60., "Width of time bins in seconds"}; // o2-linter: disable=name/configurable (temporary fix) Service ccdb; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; int lastRunNumber = -1; + double maxSec = 1; + double minSec = 0; TH1* hCalibT0C = nullptr; static const int nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; std::bitset bcPatternB; @@ -40,6 +45,7 @@ struct LumiQaTask { ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); + const AxisSpec axisMultZNA{2000, 0., 400., "ZNA multiplicity"}; const AxisSpec axisMultZNC{2000, 0., 400., "ZNC multiplicity"}; const AxisSpec axisMultT0M{1000, 0., 270000., "T0M multiplicity"}; @@ -116,9 +122,30 @@ struct LumiQaTask { LOGF(info, "hCalibZeqFT0C histogram is not available for run=%d at timestamp=%llu", runNumber, ts); return; } + + if (runNumber >= 500000) { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), runNumber); + auto tsSOR = runInfo.sor; + auto tsEOR = runInfo.eor; + minSec = floor(tsSOR / 1000.); + maxSec = ceil(tsEOR / 1000.); + } + + int nTimeBins = static_cast((maxSec - minSec) / confTimeBinWidthInSec); + double timeInterval = nTimeBins * confTimeBinWidthInSec; + + const AxisSpec axisBCs{nBCsPerOrbit, 0., static_cast(nBCsPerOrbit), ""}; + const AxisSpec axisSeconds{nTimeBins, 0, timeInterval, "seconds"}; + histos.add("hSecondsBcsTCE", "", kTH2D, {axisSeconds, axisBCs}); + histos.add("hSecondsBcsZNA", "", kTH2D, {axisSeconds, axisBCs}); + histos.add("hSecondsBcsZNC", "", kTH2D, {axisSeconds, axisBCs}); + histos.add("hSecondsBcsZEM", "", kTH2D, {axisSeconds, axisBCs}); } for (const auto& bc : bcs) { + int64_t ts = bc.timestamp(); + double secFromSOR = ts / 1000. - minSec; + double bcInOrbit = bc.globalBC() % nBCsPerOrbit; if (bc.has_zdc()) { float timeZNA = bc.zdc().timeZNA(); float timeZNC = bc.zdc().timeZNC(); @@ -159,12 +186,15 @@ struct LumiQaTask { if (fabs(timeZNA - meanTimeZNA) < 2) { histos.get(HIST("hCounterZNA"))->Fill(srun, 1); + histos.fill(HIST("hSecondsBcsZNA"), secFromSOR, bcInOrbit); } if (fabs(timeZNC - meanTimeZNC) < 2) { histos.get(HIST("hCounterZNC"))->Fill(srun, 1); + histos.fill(HIST("hSecondsBcsZNC"), secFromSOR, bcInOrbit); } if (fabs(timeZNA - meanTimeZNA) < 2 || fabs(timeZNC - meanTimeZNC) < 2) { histos.get(HIST("hCounterZEM"))->Fill(srun, 1); + histos.fill(HIST("hSecondsBcsZEM"), secFromSOR, bcInOrbit); } } @@ -211,6 +241,7 @@ struct LumiQaTask { histos.fill(HIST("hCentT0CselTVXTCEB"), centT0C); histos.get(HIST("hCounterTCE"))->Fill(srun, 1); + histos.fill(HIST("hSecondsBcsTCE"), secFromSOR, bcInOrbit); } } }; diff --git a/DPG/Tasks/AOTTrack/D0CalibTables.h b/DPG/Tasks/AOTTrack/D0CalibTables.h index 33c9efdc2dd..973582d8ba2 100644 --- a/DPG/Tasks/AOTTrack/D0CalibTables.h +++ b/DPG/Tasks/AOTTrack/D0CalibTables.h @@ -444,6 +444,8 @@ DECLARE_SOA_COLUMN(Eta, eta, float); / DECLARE_SOA_COLUMN(Phi, phi, float); //! D0-candidate phi DECLARE_SOA_COLUMN(InvMassD0, invMassD0, float); //! invariant mass (D0 hypothesis) DECLARE_SOA_COLUMN(InvMassD0bar, invMassD0bar, float); //! invariant mass (D0bar hypothesis) +DECLARE_SOA_COLUMN(CosThetaStarD0, cosThetaStarD0, float); //! D0-candidate cost* (Helicity frame, D0 mass hypothesis) +DECLARE_SOA_COLUMN(CosThetaStarD0bar, cosThetaStarD0bar, float); //! D0-candidate cost* (Helicity frame, D0bar mass hypthesis) DECLARE_SOA_COLUMN(DecLength, decLength, uint8_t); //! compressed decay length DECLARE_SOA_COLUMN(DecLengthXY, decLengthXY, uint8_t); //! compressed decay length XY DECLARE_SOA_COLUMN(NormDecLength, normDecLength, uint8_t); //! compressed normalised decay length @@ -472,6 +474,8 @@ DECLARE_SOA_TABLE(D0CalibCands, "AOD", "D0CALIBCAND", hf_calib::Phi, hf_calib::InvMassD0, hf_calib::InvMassD0bar, + hf_calib::CosThetaStarD0, + hf_calib::CosThetaStarD0bar, hf_calib::DecLength, hf_calib::DecLengthXY, hf_calib::NormDecLength, diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx index 76267171742..f2865d65be9 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx @@ -38,6 +38,7 @@ #include #include +#include using namespace o2; using namespace o2::framework; @@ -57,24 +58,28 @@ struct HmpidTableProducer { Produces hmpidAnalysis; - // using TrackCandidates = soa::Join; + // configurable for quality requirements + Configurable requireITS{"requireITS", true, "Require ITS track"}; + Configurable requireTPC{"requireTPC", true, "Require TPC track"}; + Configurable requireTOF{"requireTOF", true, "Require TOF track"}; - using CollisionCandidates = o2::soa::Join; + using CollisionCandidates = o2::soa::Join; using TrackCandidates = soa::Join; - // using CentralityClass = o2::soa::Join; - void init(o2::framework::InitContext&) { // Configure CCDB ccdb->setURL(ccdbConfig.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); histos.add("eventCounter", "eventCounter", kTH1F, {axisEvtCounter}); + histos.add("goodEventCounter", "goodEventCounter", kTH1F, {axisEvtCounter}); + histos.add("eventsHmpid", "eventsWithHmpid", kTH1F, {axisEvtCounter}); } // function to manage ccdb @@ -87,50 +92,75 @@ struct HmpidTableProducer { mCCDBRunNumber = bc.runNumber(); } - void process(soa::Join::iterator const& col, - const aod::HMPIDs& hmpids, - TrackCandidates const&, - aod::BCsWithTimestamps const&) + void processEvent(CollisionCandidates::iterator const& col, + aod::BCsWithTimestamps const&) { histos.fill(HIST("eventCounter"), 0.5); + if (col.sel8()) { + histos.fill(HIST("goodEventCounter"), 0.5); + } + // initialize CCDB for current BC initCCDB(col.bc_as()); + } + PROCESS_SWITCH(HmpidTableProducer, processEvent, "Process event level - collisions", true); + + void processHmpid( + aod::HMPIDs const& hmpids, + TrackCandidates const&, + CollisionCandidates const&, + aod::BCsWithTimestamps const&) + { + // --- Static set to track unique collisions with HMPID tracks --- + static std::unordered_set collisionsWithHmpid; - for (const auto& t : hmpids) { + for (auto const& t : hmpids) { - // global tracks associated to hmpid tracks + // Access the global track associated to the HMPID track const auto& globalTrack = t.track_as(); - if (!globalTrack.isGlobalTrack()) - continue; - if (!globalTrack.hasITS() || !globalTrack.hasTPC() || !globalTrack.hasTOF()) + + if (!globalTrack.has_collision()) continue; - // verify accessible collision - if (!globalTrack.has_collision()) { + // Access the associated collision + const auto& col = globalTrack.collision_as(); + initCCDB(col.bc_as()); + uint32_t collId = col.globalIndex(); + + // --- Track quality selection --- + if ((requireITS && !globalTrack.hasITS()) || + (requireTPC && !globalTrack.hasTPC()) || + (requireTOF && !globalTrack.hasTOF())) { continue; } + // Count collisions with at least one valid HMPID track + if (collisionsWithHmpid.insert(collId).second) { + histos.fill(HIST("eventsHmpid"), 0.5); + } + + float centrality = col.centFV0A(); + float hmpidPhotsCharge2[o2::aod::kDimPhotonsCharge]; for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { hmpidPhotsCharge2[i] = t.hmpidPhotsCharge()[i]; } - float centrality = col.centFV0A(); - - /////FILL TABLE - hmpidAnalysis( - t.hmpidSignal(), globalTrack.phi(), globalTrack.eta(), t.hmpidMom(), - globalTrack.p(), t.hmpidXTrack(), t.hmpidYTrack(), t.hmpidXMip(), - t.hmpidYMip(), t.hmpidNPhotons(), t.hmpidQMip(), (t.hmpidClusSize() % 1000000) / 1000, - t.hmpidClusSize() / 1000000, hmpidPhotsCharge2, globalTrack.eta(), globalTrack.phi(), - globalTrack.px(), globalTrack.py(), globalTrack.pz(), globalTrack.itsNCls(), - globalTrack.tpcNClsFound(), globalTrack.tpcNClsCrossedRows(), globalTrack.tpcChi2NCl(), globalTrack.itsChi2NCl(), - globalTrack.dcaXY(), globalTrack.dcaZ(), globalTrack.tpcNSigmaPi(), globalTrack.tofNSigmaPi(), - globalTrack.tpcNSigmaKa(), globalTrack.tofNSigmaKa(), globalTrack.tpcNSigmaPr(), globalTrack.tofNSigmaPr(), - globalTrack.tpcNSigmaDe(), globalTrack.tofNSigmaDe(), centrality); - } + /////FILL HMPID CUSTOM TABLE + hmpidAnalysis(t.hmpidSignal(), t.hmpidMom(), + globalTrack.p(), t.hmpidXTrack(), t.hmpidYTrack(), t.hmpidXMip(), + t.hmpidYMip(), t.hmpidNPhotons(), t.hmpidQMip(), (t.hmpidClusSize() % 1000000) / 1000, + t.hmpidClusSize() / 1000000, hmpidPhotsCharge2, globalTrack.eta(), globalTrack.phi(), + globalTrack.px(), globalTrack.py(), globalTrack.pz(), globalTrack.itsNCls(), + globalTrack.tpcNClsFound(), globalTrack.tpcNClsCrossedRows(), globalTrack.tpcChi2NCl(), globalTrack.itsChi2NCl(), + globalTrack.dcaXY(), globalTrack.dcaZ(), globalTrack.tpcNSigmaPi(), globalTrack.tofNSigmaPi(), + globalTrack.tpcNSigmaKa(), globalTrack.tofNSigmaKa(), globalTrack.tpcNSigmaPr(), globalTrack.tofNSigmaPr(), + globalTrack.tpcNSigmaDe(), globalTrack.tofNSigmaDe(), centrality); + } // end loop on hmpid table entries } + + PROCESS_SWITCH(HmpidTableProducer, processHmpid, "Process hmpid entries - tracks", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfg) { return WorkflowSpec{adaptAnalysisTask(cfg)}; } diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/tableHMPID.h b/DPG/Tasks/AOTTrack/PID/HMPID/tableHMPID.h index 045282d3e0e..dff3a00ed4f 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/tableHMPID.h +++ b/DPG/Tasks/AOTTrack/PID/HMPID/tableHMPID.h @@ -23,8 +23,6 @@ inline constexpr int kDimPhotonsCharge = 10; namespace variables_table { DECLARE_SOA_COLUMN(ChAngle, chAngle, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Eta, eta, float); DECLARE_SOA_COLUMN(MomentumHmpid, momentumHmpid, float); DECLARE_SOA_COLUMN(MomentumTrack, momentumTrack, float); DECLARE_SOA_COLUMN(XTrack, xTrack, float); @@ -60,15 +58,12 @@ DECLARE_SOA_COLUMN(TpcNSigmaPr, tpcNSigmaPr, float); DECLARE_SOA_COLUMN(TofNSigmaPr, tofNSigmaPr, float); DECLARE_SOA_COLUMN(TpcNSigmaDe, tpcNSigmaDe, float); DECLARE_SOA_COLUMN(TofNSigmaDe, tofNSigmaDe, float); - DECLARE_SOA_COLUMN(Centrality, centrality, float); } // namespace variables_table DECLARE_SOA_TABLE(HmpidAnalysis, "AOD", "HMPIDANALYSIS", variables_table::ChAngle, - variables_table::Phi, - variables_table::Eta, variables_table::MomentumHmpid, variables_table::MomentumTrack, variables_table::XTrack, diff --git a/DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx b/DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx index a8bd2c6d321..04db9d2fd1c 100644 --- a/DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx +++ b/DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx @@ -41,6 +41,11 @@ #include #include +#include +#include // IWYU pragma: keep (do not replace with Math/Vector3Dfwd.h) +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include #include #include @@ -412,6 +417,7 @@ struct DerivedDataCreatorD0Calibration { } float invMassD0{0.f}, invMassD0bar{0.f}; + float cosThetaStarD0{0.f}, cosThetaStarD0bar{0.f}; std::vector bdtScoresD0{0.f, 1.f, 1.f}, bdtScoresD0bar{0.f, 1.f, 1.f}; // always selected a priori if (massHypo == D0MassHypo::D0 || massHypo == D0MassHypo::D0AndD0Bar) { invMassD0 = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); @@ -424,6 +430,14 @@ struct DerivedDataCreatorD0Calibration { std::vector featuresCandD0 = {dcaPos.getY(), dcaNeg.getY(), chi2PCA, cosPaD0, cosPaXYD0, decLenXYD0, decLenD0, dcaPos.getY() * dcaNeg.getY(), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaPi(), trackPos.tofNSigmaPi()), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaKa()), trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaKa(), trackPos.tofNSigmaKa()), trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaPi(), trackNeg.tofNSigmaPi())}; if (!mlResponse.isSelectedMl(featuresCandD0, ptD0, bdtScoresD0)) { massHypo -= D0MassHypo::D0; + } else { // selected, we compute cost* + ROOT::Math::PxPyPzMVector const fourVecPi = ROOT::Math::PxPyPzMVector(pVecPos[0], pVecPos[1], pVecPos[2], o2::constants::physics::MassPiPlus); + ROOT::Math::PxPyPzMVector const fourVecMother = ROOT::Math::PxPyPzMVector(pVecD0[0], pVecD0[1], pVecD0[2], invMassD0); + ROOT::Math::Boost const boost{fourVecMother.BoostToCM()}; + ROOT::Math::PxPyPzMVector const fourVecPiCM = boost(fourVecPi); + ROOT::Math::XYZVector const threeVecPiCM = fourVecPiCM.Vect(); + ROOT::Math::XYZVector const helicityVec = fourVecMother.Vect(); + cosThetaStarD0 = helicityVec.Dot(threeVecPiCM) / std::sqrt(threeVecPiCM.Mag2()) / std::sqrt(helicityVec.Mag2()); } } } @@ -439,6 +453,14 @@ struct DerivedDataCreatorD0Calibration { std::vector featuresCandD0bar = {dcaPos.getY(), dcaNeg.getY(), chi2PCA, cosPaD0, cosPaXYD0, decLenXYD0, decLenD0, dcaPos.getY() * dcaNeg.getY(), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaPi(), trackNeg.tofNSigmaPi()), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaKa(), trackPos.tofNSigmaKa()), trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaKa()), trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaPi(), trackPos.tofNSigmaPi())}; if (!mlResponse.isSelectedMl(featuresCandD0bar, ptD0, bdtScoresD0bar)) { massHypo -= D0MassHypo::D0Bar; + } else { // selected, we compute cost* + ROOT::Math::PxPyPzMVector const fourVecPi = ROOT::Math::PxPyPzMVector(pVecNeg[0], pVecNeg[1], pVecNeg[2], o2::constants::physics::MassPiPlus); + ROOT::Math::PxPyPzMVector const fourVecMother = ROOT::Math::PxPyPzMVector(pVecD0[0], pVecD0[1], pVecD0[2], invMassD0bar); + ROOT::Math::Boost const boost{fourVecMother.BoostToCM()}; + ROOT::Math::PxPyPzMVector const fourVecPiCM = boost(fourVecPi); + ROOT::Math::XYZVector const threeVecPiCM = fourVecPiCM.Vect(); + ROOT::Math::XYZVector const helicityVec = fourVecMother.Vect(); + cosThetaStarD0bar = helicityVec.Dot(threeVecPiCM) / std::sqrt(threeVecPiCM.Mag2()) / std::sqrt(helicityVec.Mag2()); } } } @@ -813,6 +835,8 @@ struct DerivedDataCreatorD0Calibration { phiD0, invMassD0, invMassD0bar, + cosThetaStarD0, + cosThetaStarD0bar, getCompressedDecayLength(decLenD0), getCompressedDecayLength(decLenXYD0), getCompressedNormDecayLength(decLenD0 / errorDecayLengthD0), diff --git a/DPG/Tasks/ITS/filterTracks.cxx b/DPG/Tasks/ITS/filterTracks.cxx index b97c48d4f5c..446a792e3f4 100644 --- a/DPG/Tasks/ITS/filterTracks.cxx +++ b/DPG/Tasks/ITS/filterTracks.cxx @@ -55,15 +55,15 @@ DECLARE_SOA_COLUMN(Pz, pz, float); //! track pz // DECLARE_SOA_COLUMN(Z, z, float); //! track z position at the DCA to the primary vertex // DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); //! track distance of closest approach at the primary vertex: in xy plane // DECLARE_SOA_COLUMN(DcaZ, dcaz, float); //! track distance of closest approach at the primary vertex: along z (beam line) direction -DECLARE_SOA_COLUMN(Charge, charge, int); //! track sign, not really charge -DECLARE_SOA_COLUMN(NsigmaTPCpi, nsigmaTPCpi, float); //! TPC nsigma w.r.t. pion mass hypothesis -DECLARE_SOA_COLUMN(NsigmaTPCka, nsigmaTPCka, float); //! TPC nsigma w.r.t. kaon mass hypothesis -DECLARE_SOA_COLUMN(NsigmaTPCpr, nsigmaTPCpr, float); //! TPC nsigma w.r.t. proton mass hypothesis -DECLARE_SOA_COLUMN(NsigmaTOFpi, nsigmaTOFpi, float); //! TOF nsigma w.r.t. pion mass hypothesis -DECLARE_SOA_COLUMN(NsigmaTOFka, nsigmaTOFka, float); //! TOF nsigma w.r.t. kaon mass hypothesis -DECLARE_SOA_COLUMN(NsigmaTOFpr, nsigmaTOFpr, float); //! TOF nsigma w.r.t. proton mass hypothesis -DECLARE_SOA_COLUMN(TpcNCluster, tpcNCluster, int); //! TOF nsigma w.r.t. proton mass hypothesis - +DECLARE_SOA_COLUMN(Charge, charge, int); //! track sign, not really charge +DECLARE_SOA_COLUMN(NsigmaTPCpi, nsigmaTPCpi, float); //! TPC nsigma w.r.t. pion mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTPCka, nsigmaTPCka, float); //! TPC nsigma w.r.t. kaon mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTPCpr, nsigmaTPCpr, float); //! TPC nsigma w.r.t. proton mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTOFpi, nsigmaTOFpi, float); //! TOF nsigma w.r.t. pion mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTOFka, nsigmaTOFka, float); //! TOF nsigma w.r.t. kaon mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTOFpr, nsigmaTOFpr, float); //! TOF nsigma w.r.t. proton mass hypothesis +DECLARE_SOA_COLUMN(TpcNCluster, tpcNCluster, int); //! TOF nsigma w.r.t. proton mass hypothesis +DECLARE_SOA_COLUMN(EventIsGoodITS123, eventIsGoodITS0123, uint8_t); //! flag to store bit of o2::aod::evsel::kIsGoodITSLayer0123 ///// MC INFO DECLARE_SOA_COLUMN(MainHfMotherPdgCode, mainHfMotherPdgCode, int); //! mother pdg code for particles coming from HF, skipping intermediate resonance states. Not trustable when mother is not HF. Not suited for Sc->Lc decays, since Sc are never pointed to DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! is phyiscal primary according to ALICE definition @@ -92,7 +92,8 @@ DECLARE_SOA_TABLE(FilterColl, "AOD", "FILTERCOLL", o2::aod::collision::Chi2, o2::aod::collision::NumContrib, o2::aod::collision::CollisionTime, - o2::aod::collision::CollisionTimeRes); + o2::aod::collision::CollisionTimeRes, + aod::filtertracks::EventIsGoodITS123); DECLARE_SOA_TABLE(FilterCollLite, "AOD", "FILTERCOLLLITE", o2::aod::collision::PosX, o2::aod::collision::PosY, @@ -105,14 +106,16 @@ DECLARE_SOA_TABLE(FilterCollLite, "AOD", "FILTERCOLLLITE", o2::aod::collision::CovZZ, o2::aod::collision::Chi2, o2::aod::collision::NumContrib, - o2::aod::collision::CollisionTime); + o2::aod::collision::CollisionTime, + aod::filtertracks::EventIsGoodITS123); DECLARE_SOA_TABLE(FilterCollPos, "AOD", "FILTERCOLLPOS", o2::aod::collision::PosX, o2::aod::collision::PosY, o2::aod::collision::PosZ, o2::aod::collision::Chi2, o2::aod::collision::NumContrib, - o2::aod::collision::CollisionTime); + o2::aod::collision::CollisionTime, + aod::filtertracks::EventIsGoodITS123); DECLARE_SOA_TABLE(FiltTrackColIdx, "AOD", "FILTTRACKCOLIDX", o2::aod::track::CollisionId); DECLARE_SOA_TABLE(FilterTrack, "AOD", "FILTERTRACK", @@ -166,7 +169,7 @@ DECLARE_SOA_TABLE(GenParticles, "AOD", "GENPARTICLES", } // namespace o2::aod struct FilterTracks { - const static int nStudiedParticlesMc = 3; + static const int nStudiedParticlesMc = 3; Produces filteredTracksCollIdx; Produces filteredTracksTableExtra; @@ -307,30 +310,30 @@ struct FilterTracks { for (auto const& track : tracks) { fillTableData(track); if (produceCollTableExtraLite == 2) { - filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); - }; + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)); + } } } else { auto lowPtTracksThisColl = lowPtTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (auto const& track : lowPtTracksThisColl) { fillTableData(track); if (produceCollTableExtraLite == 2) { - filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); - }; + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)); + } } auto midPtTracksThisColl = midPtTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (auto const& track : midPtTracksThisColl) { fillTableData(track); if (produceCollTableExtraLite == 2) { - filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); - }; + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)); + } } auto highPtTracksThisColl = highPtTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (auto const& track : highPtTracksThisColl) { fillTableData(track); if (produceCollTableExtraLite == 2) { - filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); - }; + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)); + } } } } @@ -338,11 +341,11 @@ struct FilterTracks { void processCollisions(FilterCollisionsWithEvSel::iterator const& collision) { if (produceCollTableFull) - filterCollTable(collision.bcId(), collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ(), collision.flags(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes()); + filterCollTable(collision.bcId(), collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ(), collision.flags(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes(), collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)); if (produceCollTableLite) - filterCollLiteTable(collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + filterCollLiteTable(collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)); if (produceCollTableExtraLite == 1) - filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime(), collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)); } PROCESS_SWITCH(FilterTracks, processCollisions, "process collisions", true); diff --git a/EventFiltering/CMakeLists.txt b/EventFiltering/CMakeLists.txt index b8f6e14a9d8..8d5bf4622dc 100644 --- a/EventFiltering/CMakeLists.txt +++ b/EventFiltering/CMakeLists.txt @@ -69,7 +69,7 @@ o2physics_add_dpl_workflow(je-hf-filter o2physics_add_dpl_workflow(fje-filter SOURCES PWGJE/fullJetFilter.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib Boost::system + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(lf-strangeness-filter diff --git a/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx index a517e00f62a..c67c9f767f8 100644 --- a/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx @@ -27,6 +27,7 @@ #include "Framework/runDataProcessing.h" #include +#include "TDatabasePDG.h" #include #include #include @@ -87,6 +88,14 @@ struct MeanptFluctuationsAnalysis { Configurable cfgEvSelUseGoodZvtxFT0vsPV{"cfgEvSelUseGoodZvtxFT0vsPV", true, "GoodZvertex and FT0 vs PV cut"}; Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 1, "Centrlaity estimatore choice: 1-->FT0C, 2-->FT0A; 3-->FT0M, 4-->FV0A"}; + // pT dep DCAxy and DCAz cuts + Configurable cfgUsePtDepDCAxy{"cfgUsePtDepDCAxy", true, "Use pt-dependent DCAxy cut"}; + Configurable cfgUsePtDepDCAz{"cfgUsePtDepDCAz", true, "Use pt-dependent DCAz cut"}; + O2_DEFINE_CONFIGURABLE(cfgDCAxyFunc, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"); + O2_DEFINE_CONFIGURABLE(cfgDCAzFunc, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAz cut"); + TF1* fPtDepDCAxy = nullptr; + TF1* fPtDepDCAz = nullptr; + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") O2_DEFINE_CONFIGURABLE(cfgEvSelV0AT0ACut, bool, true, "V0A T0A 5 sigma cut") struct : ConfigurableGroup { @@ -141,6 +150,8 @@ struct MeanptFluctuationsAnalysis { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; std::vector>> subSampleMcGen; std::vector>> subSample; + std::vector>> subSampleMcGenV2; + std::vector>> subSampleV2; TRandom3* fRndm = new TRandom3(0); // filtering collisions and tracks*********** @@ -153,6 +164,7 @@ struct MeanptFluctuationsAnalysis { using EventCandidatesMC = soa::Join; Preslice perCollision = aod::track::collisionId; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; // Event selection cuts - Alex TF1* fMultPVCutLow = nullptr; @@ -183,6 +195,8 @@ struct MeanptFluctuationsAnalysis { histos.add("hDcaZ", ";#it{dca}_{Z}", kTH1F, {{1000, -5, 5}}); histos.add("his2DdcaXYvsPt", "", {HistType::kTH2D, {ptAxis, {1000, -1, 1}}}); histos.add("his2DdcaZvsPt", "", {HistType::kTH2D, {ptAxis, {1000, -1, 1}}}); + histos.add("his2DdcaXYvsPtBeforePtDepSel", "", {HistType::kTH2D, {ptAxis, {1000, -1, 1}}}); + histos.add("his2DdcaZvsPtBeforePtDepSel", "", {HistType::kTH2D, {ptAxis, {1000, -1, 1}}}); histos.add("hMeanPt", "", kTProfile, {centAxis}); histos.add("Hist2D_globalTracks_PVTracks", "", {HistType::kTH2D, {nchAxis, nchAxis}}); histos.add("Hist2D_cent_nch", "", {HistType::kTH2D, {nchAxis, centAxis}}); @@ -236,6 +250,7 @@ struct MeanptFluctuationsAnalysis { histos.add("MCGenerated/hPtParticleVsTrack", "", kTH2F, {ptAxis, ptAxis}); histos.add("MCGenerated/hEtaParticleVsTrack", "", kTH2F, {{100, -2.01, 2.01}, {100, -2.01, 2.01}}); histos.add("MCGenerated/hPhiParticleVsTrack", "", kTH2F, {{100, 0., o2::constants::math::TwoPI}, {100, 0., o2::constants::math::TwoPI}}); + histos.add("MCGenerated/hNgenVsNrec", "Gen multiplicity vs. Rec multiplicity in MC", kTH2F, {multAxis, multAxis}); // Analysis Profiles for central val histos.add("MCGenerated/AnalysisProfiles/Prof_mean_t1", "", {HistType::kTProfile2D, {centAxis, multAxis}}); @@ -245,16 +260,39 @@ struct MeanptFluctuationsAnalysis { histos.add("MCGenerated/AnalysisProfiles/Hist2D_Nch_centrality", "", {HistType::kTH2D, {centAxis, multAxis}}); histos.add("MCGenerated/AnalysisProfiles/Hist2D_meanpt_centrality", "", {HistType::kTH2D, {centAxis, meanpTAxis}}); + histos.add("MCGenerated/AnalysisProfilesV2/Prof_mean_t1", "", {HistType::kTProfile, {multAxis}}); + histos.add("MCGenerated/AnalysisProfilesV2/Prof_var_t1", "", {HistType::kTProfile, {multAxis}}); + histos.add("MCGenerated/AnalysisProfilesV2/Prof_skew_t1", "", {HistType::kTProfile, {multAxis}}); + histos.add("MCGenerated/AnalysisProfilesV2/Prof_kurt_t1", "", {HistType::kTProfile, {multAxis}}); + histos.add("AnalysisProfilesV2/Prof_mean_t1", "", {HistType::kTProfile2D, {multAxis, multAxis}}); + histos.add("AnalysisProfilesV2/Prof_var_t1", "", {HistType::kTProfile2D, {multAxis, multAxis}}); + histos.add("AnalysisProfilesV2/Prof_skew_t1", "", {HistType::kTProfile2D, {multAxis, multAxis}}); + histos.add("AnalysisProfilesV2/Prof_kurt_t1", "", {HistType::kTProfile2D, {multAxis, multAxis}}); + // Analysis Profiles for error subSampleMcGen.resize(cfgNsubSample); + subSampleMcGenV2.resize(cfgNsubSample); + subSampleV2.resize(cfgNsubSample); for (int i = 0; i < cfgNsubSample; i++) { subSampleMcGen[i].resize(4); + subSampleMcGenV2[i].resize(4); + subSampleV2[i].resize(4); } for (int i = 0; i < cfgNsubSample; i++) { subSampleMcGen[i][0] = std::get>(histos.add(Form("MCGenerated/AnalysisProfiles/subSample_%d/Prof_mean_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); subSampleMcGen[i][1] = std::get>(histos.add(Form("MCGenerated/AnalysisProfiles/subSample_%d/Prof_var_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); subSampleMcGen[i][2] = std::get>(histos.add(Form("MCGenerated/AnalysisProfiles/subSample_%d/Prof_skew_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); subSampleMcGen[i][3] = std::get>(histos.add(Form("MCGenerated/AnalysisProfiles/subSample_%d/Prof_kurt_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); + + subSampleMcGenV2[i][0] = std::get>(histos.add(Form("MCGenerated/AnalysisProfilesV2/subSample_%d/Prof_mean_t1", i), "", {HistType::kTProfile, {multAxis}})); + subSampleMcGenV2[i][1] = std::get>(histos.add(Form("MCGenerated/AnalysisProfilesV2/subSample_%d/Prof_var_t1", i), "", {HistType::kTProfile, {multAxis}})); + subSampleMcGenV2[i][2] = std::get>(histos.add(Form("MCGenerated/AnalysisProfilesV2/subSample_%d/Prof_skew_t1", i), "", {HistType::kTProfile, {multAxis}})); + subSampleMcGenV2[i][3] = std::get>(histos.add(Form("MCGenerated/AnalysisProfilesV2/subSample_%d/Prof_kurt_t1", i), "", {HistType::kTProfile, {multAxis}})); + + subSampleV2[i][0] = std::get>(histos.add(Form("AnalysisProfilesV2/subSample_%d/Prof_mean_t1", i), "", {HistType::kTProfile2D, {multAxis, multAxis}})); + subSampleV2[i][1] = std::get>(histos.add(Form("AnalysisProfilesV2/subSample_%d/Prof_var_t1", i), "", {HistType::kTProfile2D, {multAxis, multAxis}})); + subSampleV2[i][2] = std::get>(histos.add(Form("AnalysisProfilesV2/subSample_%d/Prof_skew_t1", i), "", {HistType::kTProfile2D, {multAxis, multAxis}})); + subSampleV2[i][3] = std::get>(histos.add(Form("AnalysisProfilesV2/subSample_%d/Prof_kurt_t1", i), "", {HistType::kTProfile2D, {multAxis, multAxis}})); } } @@ -300,6 +338,13 @@ struct MeanptFluctuationsAnalysis { cfgFuncParas.fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); } + if (cfgUsePtDepDCAxy) { + fPtDepDCAxy = new TF1("ptDepDCAxy", Form("%s", cfgDCAxyFunc->c_str()), 0.001, 1000); + } + if (cfgUsePtDepDCAz) { + fPtDepDCAz = new TF1("ptDepDCAz", Form("%s", cfgDCAzFunc->c_str()), 0.001, 1000); + } + } //! end init function template @@ -513,9 +558,11 @@ struct MeanptFluctuationsAnalysis { if (!mcParticle.has_mcCollision()) continue; - int pdgCode = std::abs(mcParticle.pdgCode()); - bool extraPDGType = (pdgCode != PDG_t::kK0Short && pdgCode != PDG_t::kLambda0); - if (extraPDGType && pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != kKPlus && pdgCode != PDG_t::kProton) + // charged check + auto pdgEntry = TDatabasePDG::Instance()->GetParticle(mcParticle.pdgCode()); + if (!pdgEntry) + continue; + if (pdgEntry->Charge() == 0) continue; if (mcParticle.isPhysicalPrimary()) { @@ -558,6 +605,11 @@ struct MeanptFluctuationsAnalysis { histos.fill(HIST("MCGenerated/AnalysisProfiles/Hist2D_Nch_centrality"), cent, nChgen); histos.fill(HIST("MCGenerated/AnalysisProfiles/Hist2D_meanpt_centrality"), cent, meanTerm1gen); + histos.get(HIST("MCGenerated/AnalysisProfilesV2/Prof_mean_t1"))->Fill(nChgen, meanTerm1gen); + histos.get(HIST("MCGenerated/AnalysisProfilesV2/Prof_var_t1"))->Fill(nChgen, varianceTerm1gen); + histos.get(HIST("MCGenerated/AnalysisProfilesV2/Prof_skew_t1"))->Fill(nChgen, skewnessTerm1gen); + histos.get(HIST("MCGenerated/AnalysisProfilesV2/Prof_kurt_t1"))->Fill(nChgen, kurtosisTerm1gen); + // selecting subsample and filling profiles float lRandomMc = fRndm->Rndm(); int sampleIndexMc = static_cast(cfgNsubSample * lRandomMc); @@ -565,12 +617,17 @@ struct MeanptFluctuationsAnalysis { subSampleMcGen[sampleIndexMc][1]->Fill(cent, nChgen, varianceTerm1gen); subSampleMcGen[sampleIndexMc][2]->Fill(cent, nChgen, skewnessTerm1gen); subSampleMcGen[sampleIndexMc][3]->Fill(cent, nChgen, kurtosisTerm1gen); + + subSampleMcGenV2[sampleIndexMc][0]->Fill(nChgen, meanTerm1gen); + subSampleMcGenV2[sampleIndexMc][1]->Fill(nChgen, varianceTerm1gen); + subSampleMcGenV2[sampleIndexMc][2]->Fill(nChgen, skewnessTerm1gen); + subSampleMcGenV2[sampleIndexMc][3]->Fill(nChgen, kurtosisTerm1gen); } //------------------------------------------------------------------------------------------- } PROCESS_SWITCH(MeanptFluctuationsAnalysis, processMCGen, "Process Generated MC data", true); - void processMCRec(MyMCRecCollisions::iterator const& collision, MyMCTracks const& tracks, aod::McCollisions const&, aod::McParticles const&) + void processMCRec(MyMCRecCollisions::iterator const& collision, MyMCTracks const& tracks, aod::McCollisions const&, aod::McParticles const& mcParticles) { histos.fill(HIST("MCGenerated/hMC"), 5.5); @@ -618,6 +675,32 @@ struct MeanptFluctuationsAnalysis { histos.fill(HIST("Hist2D_globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), centralityFT0C); + // Calculating generated no of particles for the collision event + double noGen = 0.0; + auto mcColl = collision.mcCollision(); + // Slice particles belonging only to this MC collision + auto particlesThisEvent = mcParticles.sliceBy(perMcCollision, mcColl.globalIndex()); + + for (const auto& mcParticle : particlesThisEvent) { + if (!mcParticle.has_mcCollision()) + continue; + + // charged check + auto pdgEntry = TDatabasePDG::Instance()->GetParticle(mcParticle.pdgCode()); + if (!pdgEntry) + continue; + if (pdgEntry->Charge() == 0) + continue; + + if (mcParticle.isPhysicalPrimary()) { + if ((mcParticle.pt() > cfgCutPtLower) && (mcParticle.pt() < cfgCutPreSelPt) && (std::abs(mcParticle.eta()) < cfgCutPreSelEta)) { + if (mcParticle.pt() > cfgCutPtLower && mcParticle.pt() < cfgCutPtUpper) { + noGen = noGen + 1.0; + } + } + } + } //! end particle loop + // variables double pTsum = 0.0; double nN = 0.0; @@ -649,6 +732,16 @@ struct MeanptFluctuationsAnalysis { continue; } + histos.fill(HIST("his2DdcaXYvsPtBeforePtDepSel"), track.pt(), track.dcaXY()); + histos.fill(HIST("his2DdcaZvsPtBeforePtDepSel"), track.pt(), track.dcaZ()); + + if (cfgUsePtDepDCAxy && !(std::abs(track.dcaXY()) < fPtDepDCAxy->Eval(track.pt()))) { + continue; + } + if (cfgUsePtDepDCAz && !(std::abs(track.dcaZ()) < fPtDepDCAz->Eval(track.pt()))) { + continue; + } + if (particle.isPhysicalPrimary()) { if ((particle.pt() > cfgCutPtLower) && (particle.pt() < cfgCutPreSelPt) && (std::abs(particle.eta()) < cfgCutPreSelEta)) { histos.fill(HIST("hP"), track.p()); @@ -679,6 +772,8 @@ struct MeanptFluctuationsAnalysis { } } // end track loop + histos.fill(HIST("MCGenerated/hNgenVsNrec"), noGen, nCh); + // MeanPt if (nN > 0.0f) histos.fill(HIST("hMeanPt"), cent, pTsum / nN); @@ -698,6 +793,11 @@ struct MeanptFluctuationsAnalysis { histos.fill(HIST("AnalysisProfiles/Hist2D_Nch_centrality"), cent, nCh); histos.fill(HIST("AnalysisProfiles/Hist2D_meanpt_centrality"), cent, meanTerm1); + histos.get(HIST("AnalysisProfilesV2/Prof_mean_t1"))->Fill(noGen, nCh, meanTerm1); + histos.get(HIST("AnalysisProfilesV2/Prof_var_t1"))->Fill(noGen, nCh, varianceTerm1); + histos.get(HIST("AnalysisProfilesV2/Prof_skew_t1"))->Fill(noGen, nCh, skewnessTerm1); + histos.get(HIST("AnalysisProfilesV2/Prof_kurt_t1"))->Fill(noGen, nCh, kurtosisTerm1); + // selecting subsample and filling profiles float lRandom = fRndm->Rndm(); int sampleIndex = static_cast(cfgNsubSample * lRandom); @@ -705,6 +805,11 @@ struct MeanptFluctuationsAnalysis { subSample[sampleIndex][1]->Fill(cent, nCh, varianceTerm1); subSample[sampleIndex][2]->Fill(cent, nCh, skewnessTerm1); subSample[sampleIndex][3]->Fill(cent, nCh, kurtosisTerm1); + + subSampleV2[sampleIndex][0]->Fill(noGen, nCh, meanTerm1); + subSampleV2[sampleIndex][1]->Fill(noGen, nCh, varianceTerm1); + subSampleV2[sampleIndex][2]->Fill(noGen, nCh, skewnessTerm1); + subSampleV2[sampleIndex][3]->Fill(noGen, nCh, kurtosisTerm1); } //------------------------------------------------------------------------------------------- } @@ -776,6 +881,16 @@ struct MeanptFluctuationsAnalysis { continue; } + histos.fill(HIST("his2DdcaXYvsPtBeforePtDepSel"), track.pt(), track.dcaXY()); + histos.fill(HIST("his2DdcaZvsPtBeforePtDepSel"), track.pt(), track.dcaZ()); + + if (cfgUsePtDepDCAxy && !(std::abs(track.dcaXY()) < fPtDepDCAxy->Eval(track.pt()))) { + continue; + } + if (cfgUsePtDepDCAz && !(std::abs(track.dcaZ()) < fPtDepDCAz->Eval(track.pt()))) { + continue; + } + histos.fill(HIST("hP"), track.p()); histos.fill(HIST("hPt"), track.pt()); histos.fill(HIST("hEta"), track.eta()); diff --git a/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx index d339999e23e..d0c34878282 100644 --- a/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx @@ -544,17 +544,26 @@ struct HolderMcEvent { }; struct HolderEvent { + static constexpr std::pair RangeCentrality = {0., 100.}; + std::int32_t runNumber = 0; std::int32_t runIndex = 0; std::int32_t runGroupIndex = 0; double vz = 0.; - std::int32_t nGlobalTracks = 0; - std::int32_t nPvContributors = 0; - double meanDcaXy = 0.; - double meanSquareDcaXy = 0.; - double meanDcaZ = 0.; - double meanSquareDcaZ = 0.; - std::int32_t nTofBeta = 0; + std::int32_t nGlobalTracksP = 0; + std::int32_t nGlobalTracksM = 0; + std::int32_t nPvContributorsP = 0; + std::int32_t nPvContributorsM = 0; + double meanDcaXyP = 0.; + double meanDcaXyM = 0.; + double meanSquareDcaXyP = 0.; + double meanSquareDcaXyM = 0.; + double meanDcaZP = 0.; + double meanDcaZM = 0.; + double meanSquareDcaZP = 0.; + double meanSquareDcaZM = 0.; + std::int32_t nTofBetaP = 0; + std::int32_t nTofBetaM = 0; double centrality = 0.; std::int32_t subgroupIndex = 0; std::int32_t nChPMc = 0; @@ -576,13 +585,20 @@ struct HolderEvent { runIndex = 0; runGroupIndex = 0; vz = 0.; - nGlobalTracks = 0; - nPvContributors = 0; - meanDcaXy = 0.; - meanSquareDcaXy = 0.; - meanDcaZ = 0.; - meanSquareDcaZ = 0.; - nTofBeta = 0; + nGlobalTracksP = 0; + nGlobalTracksM = 0; + nPvContributorsP = 0; + nPvContributorsM = 0; + meanDcaXyP = 0.; + meanDcaXyM = 0.; + meanSquareDcaXyP = 0.; + meanSquareDcaXyM = 0.; + meanDcaZP = 0.; + meanDcaZM = 0.; + meanSquareDcaZP = 0.; + meanSquareDcaZM = 0.; + nTofBetaP = 0; + nTofBetaM = 0; centrality = 0.; subgroupIndex = 0; nChPMc = 0; @@ -619,7 +635,7 @@ struct HolderMcParticle { struct HolderTrack { static constexpr double TruncationAbsNSigmaPid = 999.; - static constexpr double truncateNSigmaPid(const double value) { return (!(std::fabs(value) < TruncationAbsNSigmaPid) ? -TruncationAbsNSigmaPid : value); } + static constexpr double truncateNSigmaPid(const double value) { return (!(std::abs(value) < TruncationAbsNSigmaPid) ? -TruncationAbsNSigmaPid : value); } double dcaXY = 0.; double dcaZ = 0.; @@ -719,9 +735,9 @@ struct PartNumFluc { struct : ConfigurableGroup { Configurable cfgFlagRejectionRunBad{"cfgFlagRejectionRunBad", true, "Bad run rejection flag"}; - Configurable cfgFlagRejectionRunBadMc{"cfgFlagRejectionRunBadMc", true, "MC bad run rejection flag"}; + Configurable cfgFlagRejectionRunBadMc{"cfgFlagRejectionRunBadMc", false, "MC bad run rejection flag"}; Configurable cfgLabelFlagsRct{"cfgLabelFlagsRct", "CBT_hadronPID", "RCT flags label"}; - Configurable cfgBitsSelectionEvent{"cfgBitsSelectionEvent", 0b10000000001101110100000000000000000000000000000000ULL, "Event selection bits"}; + Configurable cfgBitsSelectionEvent{"cfgBitsSelectionEvent", 0b10000000001101000000000000000000000000000000000000ULL, "Event selection bits"}; Configurable cfgFlagInelEvent{"cfgFlagInelEvent", true, "Flag of requiring inelastic event"}; Configurable cfgFlagInelEventMc{"cfgFlagInelEventMc", false, "Flag of requiring inelastic MC event"}; Configurable cfgCutMaxAbsVertexZ{"cfgCutMaxAbsVertexZ", 6., "Maximum absolute vertex z position (cm)"}; @@ -741,6 +757,7 @@ struct PartNumFluc { Configurable cfgCutMaxTpcNClsSharedRatio{"cfgCutMaxTpcNClsSharedRatio", 0.25, "Maximum ratio of shared clusters over clusters TPC"}; Configurable cfgCutMinTpcNCrossedRows{"cfgCutMinTpcNCrossedRows", 75, "Minimum number of crossed rows TPC"}; Configurable cfgCutMinTpcNCrossedRowsRatio{"cfgCutMinTpcNCrossedRowsRatio", 0.8, "Minimum ratio of crossed rows over findable clusters TPC"}; + Configurable cfgFlagRecalibrationDca{"cfgFlagRecalibrationDca", false, "DCA recalibration flag"}; Configurable cfgCutMaxAbsNSigmaDcaXy{"cfgCutMaxAbsNSigmaDcaXy", 2.5, "Maximum absolute nSigma of DCAxy (cm)"}; Configurable cfgCutMaxAbsNSigmaDcaZ{"cfgCutMaxAbsNSigmaDcaZ", 2.5, "Maximum absolute nSigma of DCAz (cm)"}; Configurable cfgCutMinPt{"cfgCutMinPt", 0.4, "Minimum pT (GeV/c)"}; @@ -833,7 +850,7 @@ struct PartNumFluc { LOG(fatal) << "Invalid ccdb_object!"; } - const TGraph* const gRunNumberGroupIndex = static_cast(ccdbObject->FindObject("gRunNumberGroupIndex")); + const TGraph* const gRunNumberGroupIndex = dynamic_cast(ccdbObject->FindObject("gRunNumberGroupIndex")); if (!gRunNumberGroupIndex || gRunNumberGroupIndex->IsA() != TGraph::Class()) { LOG(fatal) << "Invalid gRunNumberGroupIndex!"; } @@ -897,59 +914,63 @@ struct PartNumFluc { break; } - holderCcdb.fPtMeanDcaXyP.resize(nRunGroups); - holderCcdb.fPtMeanDcaXyM.resize(nRunGroups); - holderCcdb.fPtMeanDcaZP.resize(nRunGroups); - holderCcdb.fPtMeanDcaZM.resize(nRunGroups); - holderCcdb.fPtSigmaDcaXyP.resize(nRunGroups); - holderCcdb.fPtSigmaDcaXyM.resize(nRunGroups); - holderCcdb.fPtSigmaDcaZP.resize(nRunGroups); - holderCcdb.fPtSigmaDcaZM.resize(nRunGroups); - for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup = static_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); - if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { - LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; - } - holderCcdb.fPtMeanDcaXyP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtMeanDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtMeanDcaXyP[iRunGroup] || holderCcdb.fPtMeanDcaXyP[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtMeanDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaXyP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaXyP[iRunGroup]->GetExpFormula("clingp") << "\""; - holderCcdb.fPtMeanDcaXyM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtMeanDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtMeanDcaXyM[iRunGroup] || holderCcdb.fPtMeanDcaXyM[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtMeanDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaXyM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaXyM[iRunGroup]->GetExpFormula("clingp") << "\""; - holderCcdb.fPtMeanDcaZP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtMeanDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtMeanDcaZP[iRunGroup] || holderCcdb.fPtMeanDcaZP[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtMeanDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaZP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaZP[iRunGroup]->GetExpFormula("clingp") << "\""; - holderCcdb.fPtMeanDcaZM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtMeanDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtMeanDcaZM[iRunGroup] || holderCcdb.fPtMeanDcaZM[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtMeanDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaZM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaZM[iRunGroup]->GetExpFormula("clingp") << "\""; - holderCcdb.fPtSigmaDcaXyP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtSigmaDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtSigmaDcaXyP[iRunGroup] || holderCcdb.fPtSigmaDcaXyP[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtSigmaDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaXyP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaXyP[iRunGroup]->GetExpFormula("clingp") << "\""; - holderCcdb.fPtSigmaDcaXyM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtSigmaDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtSigmaDcaXyM[iRunGroup] || holderCcdb.fPtSigmaDcaXyM[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtSigmaDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaXyM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaXyM[iRunGroup]->GetExpFormula("clingp") << "\""; - holderCcdb.fPtSigmaDcaZP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtSigmaDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtSigmaDcaZP[iRunGroup] || holderCcdb.fPtSigmaDcaZP[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtSigmaDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaZP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaZP[iRunGroup]->GetExpFormula("clingp") << "\""; - holderCcdb.fPtSigmaDcaZM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("fPtSigmaDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); - if (!holderCcdb.fPtSigmaDcaZM[iRunGroup] || holderCcdb.fPtSigmaDcaZM[iRunGroup]->IsA() != TFormula::Class()) { - LOG(fatal) << "Invalid " << Form("fPtSigmaDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; - } - LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaZM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaZM[iRunGroup]->GetExpFormula("clingp") << "\""; + if (groupTrack.cfgFlagRecalibrationDca.value) { + LOG(info) << "Enabling DCA recalibration."; + + holderCcdb.fPtMeanDcaXyP.resize(nRunGroups); + holderCcdb.fPtMeanDcaXyM.resize(nRunGroups); + holderCcdb.fPtMeanDcaZP.resize(nRunGroups); + holderCcdb.fPtMeanDcaZM.resize(nRunGroups); + holderCcdb.fPtSigmaDcaXyP.resize(nRunGroups); + holderCcdb.fPtSigmaDcaXyM.resize(nRunGroups); + holderCcdb.fPtSigmaDcaZP.resize(nRunGroups); + holderCcdb.fPtSigmaDcaZM.resize(nRunGroups); + for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { + const TList* const lRunGroup = dynamic_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); + if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { + LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; + } + holderCcdb.fPtMeanDcaXyP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtMeanDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtMeanDcaXyP[iRunGroup] || holderCcdb.fPtMeanDcaXyP[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtMeanDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaXyP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaXyP[iRunGroup]->GetExpFormula("clingp") << "\""; + holderCcdb.fPtMeanDcaXyM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtMeanDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtMeanDcaXyM[iRunGroup] || holderCcdb.fPtMeanDcaXyM[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtMeanDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaXyM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaXyM[iRunGroup]->GetExpFormula("clingp") << "\""; + holderCcdb.fPtMeanDcaZP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtMeanDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtMeanDcaZP[iRunGroup] || holderCcdb.fPtMeanDcaZP[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtMeanDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaZP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaZP[iRunGroup]->GetExpFormula("clingp") << "\""; + holderCcdb.fPtMeanDcaZM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtMeanDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtMeanDcaZM[iRunGroup] || holderCcdb.fPtMeanDcaZM[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtMeanDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtMeanDcaZM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtMeanDcaZM[iRunGroup]->GetExpFormula("clingp") << "\""; + holderCcdb.fPtSigmaDcaXyP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtSigmaDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtSigmaDcaXyP[iRunGroup] || holderCcdb.fPtSigmaDcaXyP[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtSigmaDcaXyP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaXyP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaXyP[iRunGroup]->GetExpFormula("clingp") << "\""; + holderCcdb.fPtSigmaDcaXyM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtSigmaDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtSigmaDcaXyM[iRunGroup] || holderCcdb.fPtSigmaDcaXyM[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtSigmaDcaXyM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaXyM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaXyM[iRunGroup]->GetExpFormula("clingp") << "\""; + holderCcdb.fPtSigmaDcaZP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtSigmaDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtSigmaDcaZP[iRunGroup] || holderCcdb.fPtSigmaDcaZP[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtSigmaDcaZP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaZP[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaZP[iRunGroup]->GetExpFormula("clingp") << "\""; + holderCcdb.fPtSigmaDcaZM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("fPtSigmaDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + if (!holderCcdb.fPtSigmaDcaZM[iRunGroup] || holderCcdb.fPtSigmaDcaZM[iRunGroup]->IsA() != TFormula::Class()) { + LOG(fatal) << "Invalid " << Form("fPtSigmaDcaZM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; + } + LOG(info) << "Reading from CCDB: " << holderCcdb.fPtSigmaDcaZM[iRunGroup]->GetName() << " \"" << holderCcdb.fPtSigmaDcaZM[iRunGroup]->GetExpFormula("clingp") << "\""; + } } if (groupTrack.cfgFlagRecalibrationNSigmaPi.value || groupTrack.cfgFlagRecalibrationNSigmaKa.value || groupTrack.cfgFlagRecalibrationNSigmaPr.value) { @@ -961,26 +982,26 @@ struct PartNumFluc { holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP.resize(nRunGroups); holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup = static_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); + const TList* const lRunGroup = dynamic_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; } - holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPiP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPiP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTpcNSigmaPiP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPiM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPiM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTpcNSigmaPiM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPiP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPiP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTofNSigmaPiP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPiM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPiM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTofNSigmaPiM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } @@ -996,26 +1017,26 @@ struct PartNumFluc { holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP.resize(nRunGroups); holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup = static_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); + const TList* const lRunGroup = dynamic_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; } - holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaKaP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaKaP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTpcNSigmaKaP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaKaM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaKaM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTpcNSigmaKaM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaKaP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaKaP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTofNSigmaKaP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaKaM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaKaM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTofNSigmaKaM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } @@ -1031,26 +1052,26 @@ struct PartNumFluc { holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP.resize(nRunGroups); holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup = static_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); + const TList* const lRunGroup = dynamic_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; } - holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPrP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPrP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTpcNSigmaPrP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPrM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPrM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTpcNSigmaPrM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPrP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPrP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTofNSigmaPrP%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP[iRunGroup]->GetName(); - holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPrM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPrM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1))); if (!holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM[iRunGroup] || !holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM[iRunGroup]->InheritsFrom(TH3::Class())) { LOG(fatal) << "Invalid " << Form("hCentralityPtEtaShiftTofNSigmaPrM%s_runGroup%d", doprocessMc.value ? "_mc" : "", iRunGroup + 1) << "!"; } @@ -1060,25 +1081,37 @@ struct PartNumFluc { } hrCounter.add("hNEvents", ";;No. of Events", {HistType::kTH1D, {{10 + aod::evsel::EventSelectionFlags::kNsel, -0.5, 9.5 + static_cast(aod::evsel::EventSelectionFlags::kNsel), "Selection"}}}); - hrCounter.add("hNMcEvents", ";;No. of MC Events", {HistType::kTH1D, {{10, -0.5, 9.5, "Selection"}}}); + if (doprocessMc.value) { + hrCounter.add("hNMcEvents", ";;No. of MC Events", {HistType::kTH1D, {{10, -0.5, 9.5, "Selection"}}}); + } if (groupAnalysis.cfgFlagQaRun.value) { LOG(info) << "Enabling run QA."; - HistogramConfigSpec hcsQaRun(HistType::kTProfile, {{static_cast(holderCcdb.runNumbersIndicesGroupIndices.size()), -0.5, holderCcdb.runNumbersIndicesGroupIndices.size() - 0.5, "Run Index"}}); + const HistogramConfigSpec hcsQaRun(HistType::kTProfile, {{static_cast(holderCcdb.runNumbersIndicesGroupIndices.size()), -0.5, holderCcdb.runNumbersIndicesGroupIndices.size() - 0.5, "Run Index"}}); hrQaRun.add("QaRun/pRunIndexVx", ";;#LT#it{V}_{#it{x}}#GT (cm)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexVy", ";;#LT#it{V}_{#it{y}}#GT (cm)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexVz", ";;#LT#it{V}_{#it{z}}#GT (cm)", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexMultFt0a", ";;FT0A #LTMultiplicity#GT", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexMultFt0c", ";;FT0C #LTMultiplicity#GT", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexNGlobalTracks", ";;#LTnGlobalTracks#GT", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexNPvContributors", ";;#LTnPvContributors#GT", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexMeanDcaXy", ";;#LT#LTDCA_{#it{xy}}#GT_{event}#GT (cm)", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexSigmaDcaXy", ";;#LT#it{#sigma}(DCA_{#it{xy}})_{event}#GT (cm)", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexMeanDcaZ", ";;#LT#LTDCA_{#it{z}}#GT_{event}#GT (cm)", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexSigmaDcaZ", ";;#LT#it{#sigma}(DCA_{#it{z}})_{event}#GT (cm)", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexNTofBeta", ";;#LTnTofBeta#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMultiplicityFt0a", ";;FT0A #LTMultiplicity#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMultiplicityFt0c", ";;FT0C #LTMultiplicity#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexCentralityFt0a", ";;FT0A #LTCentrality#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexCentralityFt0c", ";;FT0C #LTCentrality#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexCentralityFt0m", ";;FT0M #LTCentrality#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNGlobalTracks_p", ";;#LTnGlobalTracks#GT (#it{q}>0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNGlobalTracks_m", ";;#LTnGlobalTracks#GT (#it{q}<0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNPvContributors_p", ";;#LTnPvContributors#GT (#it{q}>0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNPvContributors_m", ";;#LTnPvContributors#GT (#it{q}<0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMeanDcaXy_p", ";;#LT#LTDCA_{#it{xy}}#GT_{event}#GT (cm) (#it{q}>0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMeanDcaXy_m", ";;#LT#LTDCA_{#it{xy}}#GT_{event}#GT (cm) (#it{q}<0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexSigmaDcaXy_p", ";;#LT#it{#sigma}(DCA_{#it{xy}})_{event}#GT (cm) (#it{q}>0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexSigmaDcaXy_m", ";;#LT#it{#sigma}(DCA_{#it{xy}})_{event}#GT (cm) (#it{q}<0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMeanDcaZ_p", ";;#LT#LTDCA_{#it{z}}#GT_{event}#GT (cm) (#it{q}>0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMeanDcaZ_m", ";;#LT#LTDCA_{#it{z}}#GT_{event}#GT (cm) (#it{q}<0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexSigmaDcaZ_p", ";;#LT#it{#sigma}(DCA_{#it{z}})_{event}#GT (cm) (#it{q}>0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexSigmaDcaZ_m", ";;#LT#it{#sigma}(DCA_{#it{z}})_{event}#GT (cm) (#it{q}<0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNTofBeta_p", ";;#LTnTofBeta#GT (#it{q}>0)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNTofBeta_m", ";;#LTnTofBeta#GT (#it{q}<0)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexItsNCls_p", ";;ITS #LTnClusters#GT (#it{q}>0)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexItsNCls_m", ";;ITS #LTnClusters#GT (#it{q}<0)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexItsChi2NCls_p", ";;ITS #LT#it{#chi}^{2}/nClusters#GT (#it{q}>0)", hcsQaRun); @@ -1124,28 +1157,28 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagQaEvent.value) { LOG(info) << "Enabling event QA."; - AxisSpec asRunIndex(static_cast(holderCcdb.runNumbersIndicesGroupIndices.size()), -0.5, holderCcdb.runNumbersIndicesGroupIndices.size() - 0.5, "Run Index"); - AxisSpec asNGlobalTracks(180, -0.5, 179.5, "nGlobalTracks"); + const AxisSpec asNTracks(200, -0.5, 199.5); + const HistogramConfigSpec hcsQaEvent(HistType::kTHnSparseD, {asNTracks, asNTracks}); - hrQaEvent.add("QaEvent/hRunIndexVxVy", "", {HistType::kTHnSparseF, {asRunIndex, {150, -0.15, 0.15, "#it{V}_{#it{x}} (cm)"}, {150, -0.15, 0.15, "#it{V}_{#it{y}} (cm)"}}}); - hrQaEvent.add("QaEvent/hRunIndexVz", "", {HistType::kTH2F, {asRunIndex, {300, -15., 15., "#it{V}_{#it{z}} (cm)"}}}); - hrQaEvent.add("QaEvent/hRunIndexNPvContributorsNGlobalTracks", "", {HistType::kTHnSparseF, {asRunIndex, {180, -0.5, 179.5, "nPvContributors"}, asNGlobalTracks}}); - hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaXy", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -0.5, 0.5, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaXy_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaZ", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaZ_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hRunIndexNTofBetaNGlobalTracks", "", {HistType::kTHnSparseF, {asRunIndex, {60, -0.5, 59.5, "nTofBeta"}, asNGlobalTracks}}); - hrQaEvent.add("QaEvent/hRunIndexNTofBetaNGlobalTracks_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, {60, -0.5, 59.5, "nTofBeta"}, asNGlobalTracks}}); + hrQaEvent.add("QaEvent/hVxVy", "", {HistType::kTHnSparseD, {{150, -0.15, 0.15, "#it{V}_{#it{x}} (cm)"}, {150, -0.15, 0.15, "#it{V}_{#it{y}} (cm)"}}}); + hrQaEvent.add("QaEvent/hVz", "", {HistType::kTH1D, {{300, -15., 15., "#it{V}_{#it{z}} (cm)"}}}); + hrQaEvent.add("QaEvent/hNPvContributorsNGlobalTracks", ";nPvContributors;nGlobalTracks;", hcsQaEvent); + hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaXy", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {250, -0.25, 0.25, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaXy_nPvContributorsCut", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {250, -0.25, 0.25, "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaZ", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaZ_nPvContributorsCut", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hNTofBetaNGlobalTracks", ";nTofBeta;nGlobalTracks;", hcsQaEvent); + hrQaEvent.add("QaEvent/hNTofBetaNGlobalTracks_nPvContributorsCut", ";nTofBeta;nGlobalTracks;", hcsQaEvent); } if (groupAnalysis.cfgFlagQaCentrality.value) { LOG(info) << "Enabling centrality QA."; - AxisSpec asCentrality(20, 0., 100., "Centrality (%)"); + const AxisSpec asCentrality(20, 0., 100., "Centrality (%)"); - hrQaCentrality.add("QaCentrality/hCentralityFt0a", "", {HistType::kTHnSparseF, {asCentrality, {1600, 0., 8000., "FT0A Multiplicity"}}}); - hrQaCentrality.add("QaCentrality/hCentralityFt0c", "", {HistType::kTHnSparseF, {asCentrality, {400, 0., 2000., "FT0C Multiplicity"}}}); - hrQaCentrality.add("QaCentrality/hCentralityFt0m", "", {HistType::kTHnSparseF, {asCentrality, {2000, 0., 10000., "FT0M Multiplicity"}}}); + hrQaCentrality.add("QaCentrality/hCentralityFt0a", "", {HistType::kTHnSparseF, {asCentrality, {12000, 0., 12000., "FT0A Multiplicity"}}}); + hrQaCentrality.add("QaCentrality/hCentralityFt0c", "", {HistType::kTHnSparseF, {asCentrality, {3000, 0., 3000., "FT0C Multiplicity"}}}); + hrQaCentrality.add("QaCentrality/hCentralityFt0m", "", {HistType::kTHnSparseF, {asCentrality, {15000, 0., 15000., "FT0M Multiplicity"}}}); } if (groupAnalysis.cfgFlagQaTrack.value) { @@ -1155,37 +1188,36 @@ struct PartNumFluc { hrQaTrack.add("QaTrack/hItsNCls_m", "", {HistType::kTH1D, {{10, -0.5, 9.5, "ITS nClusters"}}}); hrQaTrack.add("QaTrack/hItsChi2NCls_p", "", {HistType::kTH1D, {{80, 0., 40., "ITS #it{#chi}^{2}/nClusters"}}}); hrQaTrack.add("QaTrack/hItsChi2NCls_m", "", {HistType::kTH1D, {{80, 0., 40., "ITS #it{#chi}^{2}/nClusters"}}}); - hrQaTrack.add("QaTrack/hTpcNClsNClsShared_p", "", {HistType::kTH2D, {{180, -0.5, 179.5, "TPC nClusters"}, {180, -0.5, 179.5, "TPC nSharedClusters"}}}); - hrQaTrack.add("QaTrack/hTpcNClsNClsShared_m", "", {HistType::kTH2D, {{180, -0.5, 179.5, "TPC nClusters"}, {180, -0.5, 179.5, "TPC nSharedClusters"}}}); + hrQaTrack.add("QaTrack/hTpcNClsNClsShared_p", "", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nClusters"}, {180, -0.5, 179.5, "TPC nSharedClusters"}}}); + hrQaTrack.add("QaTrack/hTpcNClsNClsShared_m", "", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nClusters"}, {180, -0.5, 179.5, "TPC nSharedClusters"}}}); hrQaTrack.add("QaTrack/hTpcChi2NCls_p", "", {HistType::kTH1D, {{100, 0., 5., "TPC #it{#chi}^{2}/nClusters"}}}); hrQaTrack.add("QaTrack/hTpcChi2NCls_m", "", {HistType::kTH1D, {{100, 0., 5., "TPC #it{#chi}^{2}/nClusters"}}}); - hrQaTrack.add("QaTrack/hTpcNClsFindableNCrossedRows_p", "", {HistType::kTH2D, {{180, -0.5, 179.5, "TPC nFindableClusters"}, {180, -0.5, 179.5, "TPC nCrossedRows"}}}); - hrQaTrack.add("QaTrack/hTpcNClsFindableNCrossedRows_m", "", {HistType::kTH2D, {{180, -0.5, 179.5, "TPC nFindableClusters"}, {180, -0.5, 179.5, "TPC nCrossedRows"}}}); + hrQaTrack.add("QaTrack/hTpcNClsFindableNCrossedRows_p", "", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nFindableClusters"}, {180, -0.5, 179.5, "TPC nCrossedRows"}}}); + hrQaTrack.add("QaTrack/hTpcNClsFindableNCrossedRows_m", "", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nFindableClusters"}, {180, -0.5, 179.5, "TPC nCrossedRows"}}}); } if (groupAnalysis.cfgFlagQaDca.value) { LOG(info) << "Enabling DCA QA."; - AxisSpec asPt(200, 0., 2., "#it{p}_{T} (GeV/#it{c})"); - AxisSpec asDca(400, -1., 1.); + const AxisSpec asPt(200, 0., 2., "#it{p}_{T} (GeV/#it{c})"); - hrQaDca.add("QaDca/hPtDcaXy_p", ";;DCA_{#it{xy}} (cm)", {HistType::kTH2D, {asPt, asDca}}); - hrQaDca.add("QaDca/hPtDcaXy_m", ";;DCA_{#it{xy}} (cm)", {HistType::kTH2D, {asPt, asDca}}); + hrQaDca.add("QaDca/hPtDcaXy_p", "", {HistType::kTHnSparseD, {asPt, {500, -0.5, 0.5, "DCA_{#it{xy}} (cm)"}}}); + hrQaDca.add("QaDca/hPtDcaXy_m", "", {HistType::kTHnSparseD, {asPt, {500, -0.5, 0.5, "DCA_{#it{xy}} (cm)"}}}); hrQaDca.add("QaDca/pPtDcaXy_p", ";;#LTDCA_{#it{xy}}#GT (cm)", {HistType::kTProfile, {asPt}}); hrQaDca.add("QaDca/pPtDcaXy_m", ";;#LTDCA_{#it{xy}}#GT (cm)", {HistType::kTProfile, {asPt}}); - hrQaDca.add("QaDca/hPtDcaZ_p", ";;DCA_{#it{z}} (cm)", {HistType::kTH2D, {asPt, asDca}}); - hrQaDca.add("QaDca/hPtDcaZ_m", ";;DCA_{#it{z}} (cm)", {HistType::kTH2D, {asPt, asDca}}); + hrQaDca.add("QaDca/hPtDcaZ_p", "", {HistType::kTHnSparseD, {asPt, {500, -1., 1., "DCA_{#it{z}} (cm)"}}}); + hrQaDca.add("QaDca/hPtDcaZ_m", "", {HistType::kTHnSparseD, {asPt, {500, -1., 1., "DCA_{#it{z}} (cm)"}}}); hrQaDca.add("QaDca/pPtDcaZ_p", ";;#LTDCA_{#it{z}}#GT (cm)", {HistType::kTProfile, {asPt}}); hrQaDca.add("QaDca/pPtDcaZ_m", ";;#LTDCA_{#it{z}}#GT (cm)", {HistType::kTProfile, {asPt}}); } if (groupAnalysis.cfgFlagQaAcceptance.value || groupAnalysis.cfgFlagQaAcceptancePi.value || groupAnalysis.cfgFlagQaAcceptanceKa.value || groupAnalysis.cfgFlagQaAcceptancePr.value) { - AxisSpec asPt(250, 0., 2.5, "#it{p}_{T} (GeV/#it{c})"); + const AxisSpec asPt(250, 0., 2.5, "#it{p}_{T} (GeV/#it{c})"); if (groupAnalysis.cfgFlagQaAcceptance.value) { LOG(info) << "Enabling acceptance QA."; - HistogramConfigSpec hcsQaAcceptance(HistType::kTHnSparseF, {{300, -1.5, 1.5, "#it{#eta}"}, asPt}); + const HistogramConfigSpec hcsQaAcceptance(HistType::kTHnSparseD, {{300, -1.5, 1.5, "#it{#eta}"}, asPt}); hrQaAcceptance.add("QaAcceptance/hEtaPt_tpcEdgeP", "", hcsQaAcceptance); hrQaAcceptance.add("QaAcceptance/hEtaPt_tpcEdgeM", "", hcsQaAcceptance); @@ -1194,7 +1226,7 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagQaAcceptancePi.value || groupAnalysis.cfgFlagQaAcceptanceKa.value || groupAnalysis.cfgFlagQaAcceptancePr.value) { - HistogramConfigSpec hcsQaAcceptance(HistType::kTH2D, {{300, -1.5, 1.5, "#it{y}"}, asPt}); + const HistogramConfigSpec hcsQaAcceptance(HistType::kTHnSparseD, {{300, -1.5, 1.5, "#it{y}"}, asPt}); if (groupAnalysis.cfgFlagQaAcceptancePi.value) { LOG(info) << "Enabling pion acceptance QA."; @@ -1215,7 +1247,7 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagQaAcceptancePr.value) { - LOG(info) << "Enabling proton acceptance QA."; + LOG(info) << "Enabling (anti)proton acceptance QA."; hrQaAcceptance.add("QaAcceptance/hRapidityPt_tpcEdgePrP", "", hcsQaAcceptance); hrQaAcceptance.add("QaAcceptance/hRapidityPt_tpcEdgePrM", "", hcsQaAcceptance); @@ -1226,7 +1258,7 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagQaPhi.value || groupAnalysis.cfgFlagQaPhiPi.value || groupAnalysis.cfgFlagQaPhiKa.value || groupAnalysis.cfgFlagQaPhiPr.value) { - HistogramConfigSpec hcsQaPhi(HistType::kTHnSparseF, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}, {360, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}); + const HistogramConfigSpec hcsQaPhi(HistType::kTHnSparseF, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}, {360, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}); if (groupAnalysis.cfgFlagQaPhi.value) { LOG(info) << "Enabling phi QA."; @@ -1295,7 +1327,7 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagQaPhiPr.value) { - LOG(info) << "Enabling proton phi QA."; + LOG(info) << "Enabling (anti)proton phi QA."; if (doprocessMc.value) { hrQaPhi.add("QaPhi/hCentralityPtEtaPhiMc_mcPrP", "", hcsQaPhi); @@ -1318,39 +1350,38 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagQaPid.value || groupAnalysis.cfgFlagQaPidPi.value || groupAnalysis.cfgFlagQaPidKa.value || groupAnalysis.cfgFlagQaPidPr.value) { - AxisSpec asCentrality({0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"); + const AxisSpec asCentrality({0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"); if (groupAnalysis.cfgFlagQaPid.value) { LOG(info) << "Enabling PID QA."; - AxisSpec asPOverQ(350, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"); - AxisSpec asEta(48, -1.2, 1.2, "#it{#eta}"); + const AxisSpec asPOverQ(350, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"); + const AxisSpec asEta(48, -1.2, 1.2, "#it{#eta}"); hrQaPid.add("QaPid/hCentralityPOverQEtaTpcLnDeDx", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {240, 3., 9., "TPC ln(d#it{E}/d#it{x} (a.u.))"}}}); hrQaPid.add("QaPid/hCentralityPOverQEtaTofInverseBeta", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {120, 0.5, 3.5, "TOF 1/#it{#beta}"}}}); } if (groupAnalysis.cfgFlagQaPidPi.value || groupAnalysis.cfgFlagQaPidKa.value || groupAnalysis.cfgFlagQaPidPr.value) { - AxisSpec asPt(40, 0., 2., "#it{p}_{T} (GeV/#it{c})"); - AxisSpec asEta(32, -0.8, 0.8, "#it{#eta}"); + const HistogramConfigSpec hcsQaPid(HistType::kTHnSparseF, {asCentrality, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}, {200, -10., 10.}}); if (groupAnalysis.cfgFlagQaPidPi.value) { LOG(info) << "Enabling pion PID QA."; if (doprocessMc.value) { - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_mcPiP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_mcPiM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_mcPiP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_mcPiM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{#pi}"}}}); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_mcPiP", ";;;;TPC #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_mcPiM", ";;;;TPC #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_mcPiP", ";;;;TOF #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_mcPiM", ";;;;TOF #it{n}#it{#sigma}_{#pi};", hcsQaPid); } else if (doprocessRaw.value) { - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_p", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_m", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_tofPiP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_tofPiM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_tpcPiP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_tpcPiM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPi_p", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC-TOF #it{n}#it{#sigma}_{#pi}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPi_m", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC-TOF #it{n}#it{#sigma}_{#pi}"}}}); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_p", ";;;;TPC #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_m", ";;;;TPC #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_tofPiP", ";;;;TPC #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPi_tofPiM", ";;;;TPC #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_tpcPiP", ";;;;TOF #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPi_tpcPiM", ";;;;TOF #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPi_p", ";;;;TPC-TOF #it{n}#it{#sigma}_{#pi};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPi_m", ";;;;TPC-TOF #it{n}#it{#sigma}_{#pi};", hcsQaPid); } } @@ -1358,39 +1389,39 @@ struct PartNumFluc { LOG(info) << "Enabling kaon PID QA."; if (doprocessMc.value) { - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_mcKaP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_mcKaM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_mcKaP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_mcKaM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{K}"}}}); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_mcKaP", ";;;;TPC #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_mcKaM", ";;;;TPC #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_mcKaP", ";;;;TOF #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_mcKaM", ";;;;TOF #it{n}#it{#sigma}_{K};", hcsQaPid); } else if (doprocessRaw.value) { - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_p", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_m", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_tofKaP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_tofKaM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_tpcKaP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_tpcKaM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaKa_p", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC-TOF #it{n}#it{#sigma}_{K}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaKa_m", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC-TOF #it{n}#it{#sigma}_{K}"}}}); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_p", ";;;;TPC #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_m", ";;;;TPC #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_tofKaP", ";;;;TPC #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaKa_tofKaM", ";;;;TPC #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_tpcKaP", ";;;;TOF #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaKa_tpcKaM", ";;;;TOF #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaKa_p", ";;;;TPC-TOF #it{n}#it{#sigma}_{K};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaKa_m", ";;;;TPC-TOF #it{n}#it{#sigma}_{K};", hcsQaPid); } } if (groupAnalysis.cfgFlagQaPidPr.value) { - LOG(info) << "Enabling proton PID QA."; + LOG(info) << "Enabling (anti)proton PID QA."; if (doprocessMc.value) { - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_mcPrP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_mcPrM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_mcPrP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_mcPrM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{p}"}}}); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_mcPrP", ";;;;TPC #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_mcPrM", ";;;;TPC #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_mcPrP", ";;;;TOF #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_mcPrM", ";;;;TOF #it{n}#it{#sigma}_{p};", hcsQaPid); } else if (doprocessRaw.value) { - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_p", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_m", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_tofPrP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_tofPrM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_tpcPrP", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_tpcPrM", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TOF #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPr_p", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC-TOF #it{n}#it{#sigma}_{p}"}}}); - hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPr_m", "", {HistType::kTHnSparseF, {asCentrality, asPt, asEta, {200, -10., 10., "TPC-TOF #it{n}#it{#sigma}_{p}"}}}); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_p", ";;;;TPC #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_m", ";;;;TPC #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_tofPrP", ";;;;TPC #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcNSigmaPr_tofPrM", ";;;;TPC #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_tpcPrP", ";;;;TOF #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTofNSigmaPr_tpcPrM", ";;;;TOF #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPr_p", ";;;;TPC-TOF #it{n}#it{#sigma}_{p};", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtEtaTpcTofNSigmaPr_m", ";;;;TPC-TOF #it{n}#it{#sigma}_{p};", hcsQaPid); } } } @@ -1400,16 +1431,16 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagQaMc.value) { LOG(info) << "Enabling MC QA."; - AxisSpec asCentrality(20, 0., 100., "Centrality (%)"); + const AxisSpec asCentrality(20, 0., 100., "Centrality (%)"); - hrQaMc.add("QaMc/hCentralityVzVzMc", "", {HistType::kTH3F, {asCentrality, {200, -10., 10., "#it{V}_{#it{z}}^{Rec} (cm)"}, {200, -10., 10., "#it{V}_{#it{z}}^{Gen} (cm)"}}}); + hrQaMc.add("QaMc/hCentralityVzVzMc", "", {HistType::kTHnSparseF, {asCentrality, {200, -10., 10., "#it{V}_{#it{z}}^{Rec} (cm)"}, {200, -10., 10., "#it{V}_{#it{z}}^{Gen} (cm)"}}}); hrQaMc.add("QaMc/hCentralityPtEtaDeltaPt", "", {HistType::kTHnSparseF, {asCentrality, {100, 0., 2., "#it{p}_{T}^{Rec} (GeV/#it{c})"}, {120, -1.2, 1.2, "#it{#eta}_{Rec}"}, {100, -1., 1., "#it{p}_{T}^{Rec}#minus#it{p}_{T}^{Gen} (GeV/#it{c})"}}}); hrQaMc.add("QaMc/hCentralityPtEtaDeltaEta", "", {HistType::kTHnSparseF, {asCentrality, {100, 0., 2., "#it{p}_{T}^{Rec} (GeV/#it{c})"}, {120, -1.2, 1.2, "#it{#eta}_{Rec}"}, {100, -1., 1., "#it{#eta}_{Rec}#minus#it{#eta}_{Gen}"}}}); } } if (groupAnalysis.cfgFlagCalculationYieldPi.value || groupAnalysis.cfgFlagCalculationYieldKa.value || groupAnalysis.cfgFlagCalculationYieldPr.value) { - HistogramConfigSpec hcsCalculationYield(HistType::kTHnSparseF, {{static_cast(std::llrint(std::ceil(groupEvent.cfgCutMaxAbsVertexZ.value))) * 2, -std::ceil(groupEvent.cfgCutMaxAbsVertexZ.value), std::ceil(groupEvent.cfgCutMaxAbsVertexZ.value), "#it{V}_{#it{z}} (cm)"}, {{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}, {180, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}); + const HistogramConfigSpec hcsCalculationYield(HistType::kTHnSparseF, {{static_cast(std::llrint(std::ceil(groupEvent.cfgCutMaxAbsVertexZ.value))) * 2, -std::ceil(groupEvent.cfgCutMaxAbsVertexZ.value), std::ceil(groupEvent.cfgCutMaxAbsVertexZ.value), "#it{V}_{#it{z}} (cm)"}, {{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}}); if (groupAnalysis.cfgFlagCalculationYieldPi.value) { LOG(info) << "Enabling pion yield calculation."; @@ -1456,7 +1487,7 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagCalculationYieldPr.value) { - LOG(info) << "Enabling proton yield calculation."; + LOG(info) << "Enabling (anti)proton yield calculation."; if (doprocessMc.value) { hrCalculationYield.add("CalculationYield/hVzCentralityPtEtaMc_mcPrP", "", hcsCalculationYield); @@ -1480,7 +1511,7 @@ struct PartNumFluc { if (doprocessMc.value) { if (groupAnalysis.cfgFlagCalculationPurityPi.value || groupAnalysis.cfgFlagCalculationPurityKa.value || groupAnalysis.cfgFlagCalculationPurityPr.value) { - HistogramConfigSpec hcsCalculationPurity(HistType::kTProfile3D, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}); + const HistogramConfigSpec hcsCalculationPurity(HistType::kTProfile3D, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}); if (groupAnalysis.cfgFlagCalculationPurityPi.value) { LOG(info) << "Enabling pion purity calculation."; @@ -1513,7 +1544,7 @@ struct PartNumFluc { if (doprocessMc.value) { if (groupAnalysis.cfgFlagCalculationFractionPrimaryPi.value || groupAnalysis.cfgFlagCalculationFractionPrimaryKa.value || groupAnalysis.cfgFlagCalculationFractionPrimaryPr.value) { - HistogramConfigSpec hcsCalculationFractionPrimary(HistType::kTProfile3D, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}); + const HistogramConfigSpec hcsCalculationFractionPrimary(HistType::kTProfile3D, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}); if (groupAnalysis.cfgFlagCalculationFractionPrimaryPi.value) { LOG(info) << "Enabling pion primary fraction calculation."; @@ -1547,9 +1578,63 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagCalculationFluctuationCh.value || groupAnalysis.cfgFlagCalculationFluctuationKa.value || groupAnalysis.cfgFlagCalculationFluctuationPr.value) { static constexpr std::int32_t NDimensionsEfficiency = 4; - AxisSpec asCentrality(groupEvent.cfgAxisCentrality, "Centrality (%)"); - HistogramConfigSpec hcsCalculationFluctuation(HistType::kTH3D, {asCentrality, {40, -0.5, 39.5}, {40, -0.5, 39.5}}); - HistogramConfigSpec hcsFluctuationCalculator(HistType::kTH3D, {asCentrality, {groupEvent.cfgNSubgroups.value, -0.5, groupEvent.cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderVectors, -0.5, fluctuation_calculator_base::NOrderVectors - 0.5, "Order Vector Index"}}); + const AxisSpec asCentrality(groupEvent.cfgAxisCentrality, "Centrality (%)"); + const HistogramConfigSpec hcsCalculationFluctuation(HistType::kTHnSparseD, {asCentrality, {50, -0.5, 49.5}, {50, -0.5, 49.5}}); + const HistogramConfigSpec hcsFluctuationCalculator(HistType::kTH3D, {asCentrality, {groupEvent.cfgNSubgroups.value, -0.5, groupEvent.cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderVectors, -0.5, fluctuation_calculator_base::NOrderVectors - 0.5, "Order Vector Index"}}); + + if (groupAnalysis.cfgFlagCalculationFluctuationCh.value) { + LOG(info) << "Enabling charge number fluctuation calculation."; + + fluctuationCalculatorTrackChP = std::make_unique(); + fluctuationCalculatorTrackChM = std::make_unique(); + fluctuationCalculatorTrackChT = std::make_unique(); + fluctuationCalculatorTrackChN = std::make_unique(); + + if (doprocessMc.value) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM_mc", ";;#it{N}(h^{+});#it{N}(h^{#minus});", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM", ";;#it{N}(h^{+});#it{N}(h^{#minus});", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChN", "", hcsFluctuationCalculator); + } + + if (groupAnalysis.cfgFlagCalculationFluctuationKa.value) { + LOG(info) << "Enabling kaon number fluctuation calculation."; + + fluctuationCalculatorTrackKaP = std::make_unique(); + fluctuationCalculatorTrackKaM = std::make_unique(); + fluctuationCalculatorTrackKaT = std::make_unique(); + fluctuationCalculatorTrackKaN = std::make_unique(); + + if (doprocessMc.value) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM_mc", ";;#it{N}(K^{+});#it{N}(K^{#minus});", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM", ";;#it{N}(K^{+});#it{N}(K^{#minus});", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaN", "", hcsFluctuationCalculator); + } + + if (groupAnalysis.cfgFlagCalculationFluctuationPr.value) { + LOG(info) << "Enabling (anti)proton number fluctuation calculation."; + + fluctuationCalculatorTrackPrP = std::make_unique(); + fluctuationCalculatorTrackPrM = std::make_unique(); + fluctuationCalculatorTrackPrT = std::make_unique(); + fluctuationCalculatorTrackPrN = std::make_unique(); + + if (doprocessMc.value) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM_mc", ";;#it{N}(p);#it{N}(#bar{p});", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM", ";;#it{N}(p);#it{N}(#bar{p});", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrN", "", hcsFluctuationCalculator); + } if (groupAnalysis.cfgFlagCalculationFluctuationCh.value) { holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiP.resize(nRunGroups); @@ -1557,26 +1642,26 @@ struct PartNumFluc { holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiP.resize(nRunGroups); holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiM.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup = static_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); + const TList* const lRunGroup = dynamic_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; } - holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPiP_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPiP_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiP[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiP[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiP[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcPiP_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiP[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPiM_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPiM_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiM[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiM[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiM[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcPiM_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcPiM[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPiP_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPiP_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiP[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiP[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiP[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcTofPiP_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiP[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPiM_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPiM_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiM[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiM[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPiM[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcTofPiM_runGroup%d", iRunGroup + 1) << "!"; } @@ -1590,26 +1675,26 @@ struct PartNumFluc { holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaP.resize(nRunGroups); holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaM.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup = static_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); + const TList* const lRunGroup = dynamic_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; } - holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcKaP_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcKaP_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaP[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaP[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaP[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcKaP_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaP[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcKaM_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcKaM_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaM[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaM[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaM[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcKaM_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcKaM[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofKaP_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofKaP_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaP[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaP[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaP[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcTofKaP_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaP[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofKaM_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofKaM_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaM[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaM[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofKaM[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcTofKaM_runGroup%d", iRunGroup + 1) << "!"; } @@ -1623,86 +1708,32 @@ struct PartNumFluc { holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrP.resize(nRunGroups); holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrM.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup = static_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); + const TList* const lRunGroup = dynamic_cast(ccdbObject->FindObject(Form("lRunGroup_%d", iRunGroup + 1))); if (!lRunGroup || lRunGroup->IsA() != TList::Class()) { LOG(fatal) << "Invalid " << Form("lRunGroup_%d", iRunGroup + 1) << "!"; } - holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPrP_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPrP_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrP[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrP[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrP[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcPrP_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrP[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPrM_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcPrM_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrM[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrM[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrM[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcPrM_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcPrM[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrP[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPrP_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrP[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPrP_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrP[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrP[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrP[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcTofPrP_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrP[iRunGroup]->GetName(); - holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrM[iRunGroup] = static_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPrM_runGroup%d", iRunGroup + 1))); + holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrM[iRunGroup] = dynamic_cast(lRunGroup->FindObject(Form("hVzCentralityPtEtaEfficiencyTpcTofPrM_runGroup%d", iRunGroup + 1))); if (!holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrM[iRunGroup] || !holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrM[iRunGroup]->InheritsFrom(THnBase::Class()) || holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrM[iRunGroup]->GetNdimensions() != NDimensionsEfficiency) { LOG(fatal) << "Invalid " << Form("hVzCentralityPtEtaEfficiencyTpcTofPrM_runGroup%d", iRunGroup + 1) << "!"; } LOG(info) << "Reading from CCDB: " << holderCcdb.hVzCentralityPtEtaEfficiencyTpcTofPrM[iRunGroup]->GetName(); } } - - if (groupAnalysis.cfgFlagCalculationFluctuationCh.value) { - LOG(info) << "Enabling charge number fluctuation calculation."; - - fluctuationCalculatorTrackChP = std::make_unique(); - fluctuationCalculatorTrackChM = std::make_unique(); - fluctuationCalculatorTrackChT = std::make_unique(); - fluctuationCalculatorTrackChN = std::make_unique(); - - if (doprocessMc.value) { - hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM_mc", ";;#it{N}(h^{+});#it{N}(h^{#minus})", hcsCalculationFluctuation); - } - hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM", ";;#it{N}(h^{+});#it{N}(h^{#minus})", hcsCalculationFluctuation); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChP", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChM", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChT", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChN", "", hcsFluctuationCalculator); - } - - if (groupAnalysis.cfgFlagCalculationFluctuationKa.value) { - LOG(info) << "Enabling kaon number fluctuation calculation."; - - fluctuationCalculatorTrackKaP = std::make_unique(); - fluctuationCalculatorTrackKaM = std::make_unique(); - fluctuationCalculatorTrackKaT = std::make_unique(); - fluctuationCalculatorTrackKaN = std::make_unique(); - - if (doprocessMc.value) { - hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM_mc", ";;#it{N}(K^{+});#it{N}(K^{#minus})", hcsCalculationFluctuation); - } - hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM", ";;#it{N}(K^{+});#it{N}(K^{#minus})", hcsCalculationFluctuation); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaP", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaM", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaT", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaN", "", hcsFluctuationCalculator); - } - - if (groupAnalysis.cfgFlagCalculationFluctuationPr.value) { - LOG(info) << "Enabling (anti)proton number fluctuation calculation."; - - fluctuationCalculatorTrackPrP = std::make_unique(); - fluctuationCalculatorTrackPrM = std::make_unique(); - fluctuationCalculatorTrackPrT = std::make_unique(); - fluctuationCalculatorTrackPrN = std::make_unique(); - - if (doprocessMc.value) { - hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM_mc", ";;#it{N}(p);#it{N}(#bar{p})", hcsCalculationFluctuation); - } - hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM", ";;#it{N}(p);#it{N}(#bar{p})", hcsCalculationFluctuation); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrP", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrM", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrT", "", hcsFluctuationCalculator); - hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrN", "", hcsFluctuationCalculator); - } } } @@ -1747,15 +1778,22 @@ struct PartNumFluc { if (!groupTrack.cfgFlagRecalibrationNSigmaPr.value) { return 0.; } + } else { + return 0.; } static const std::array*, 2>, 2>, static_cast(ParticleSpecies::kNSpecies)> pointersVectorHistogramShiftNSigmaPid = {{{{{&holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP, &holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP}, {&holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM, &holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM}}}, {{{&holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP, &holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP}, {&holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM, &holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM}}}, {{{&holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP, &holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP}, {&holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM, &holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM}}}}}; + static const auto clampInAxis = [](const double value, const TAxis* const axis) { + const std::int32_t first = std::clamp(axis->GetFirst(), 1, axis->GetNbins()); + const std::int32_t last = std::clamp(axis->GetLast(), 1, axis->GetNbins()); + return first == last ? axis->GetBinCenter(first) : std::clamp(value, std::nextafter(axis->GetBinCenter(first), std::numeric_limits::infinity()), std::nextafter(axis->GetBinCenter(last), -std::numeric_limits::infinity())); + }; if (holderTrack.sign == 0) { return 0.; } const TH3* const hCentralityPtEtaShiftNSigmaPid = pointersVectorHistogramShiftNSigmaPid[static_cast(particleSpecies)][holderTrack.sign > 0 ? 0 : 1][pidStrategy == PidStrategy::kTpc ? 0 : 1]->at(std::abs(holderEvent.runGroupIndex) - 1); - return hCentralityPtEtaShiftNSigmaPid ? hCentralityPtEtaShiftNSigmaPid->Interpolate(std::max(std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetXaxis()->GetBinCenter(1), std::numeric_limits::infinity()), std::min(holderEvent.centrality, std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetXaxis()->GetBinCenter(hCentralityPtEtaShiftNSigmaPid->GetNbinsX()), -std::numeric_limits::infinity()))), std::max(std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetYaxis()->GetBinCenter(1), std::numeric_limits::infinity()), std::min(holderTrack.pt, std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetYaxis()->GetBinCenter(hCentralityPtEtaShiftNSigmaPid->GetNbinsY()), -std::numeric_limits::infinity()))), std::max(std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetZaxis()->GetBinCenter(1), std::numeric_limits::infinity()), std::min(holderTrack.eta, std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetZaxis()->GetBinCenter(hCentralityPtEtaShiftNSigmaPid->GetNbinsZ()), -std::numeric_limits::infinity())))) : 0.; + return hCentralityPtEtaShiftNSigmaPid ? hCentralityPtEtaShiftNSigmaPid->Interpolate(clampInAxis(holderEvent.centrality, hCentralityPtEtaShiftNSigmaPid->GetXaxis()), clampInAxis(holderTrack.pt, hCentralityPtEtaShiftNSigmaPid->GetYaxis()), clampInAxis(holderTrack.eta, hCentralityPtEtaShiftNSigmaPid->GetZaxis())) : 0.; } template @@ -1768,41 +1806,41 @@ struct PartNumFluc { if constexpr (pidStrategy == PidStrategy::kTpc) { if (doRejectingOthers) { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < std::min(groupTrack.cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][0]), std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][0]))))) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < std::min({groupTrack.cfgCutMaxAbsNSigmaPid.value, std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][0]), std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][0])}))) { return 0; } } else { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { return 0; } } } else if constexpr (pidStrategy == PidStrategy::kTof) { if (doRejectingOthers) { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < std::min(groupTrack.cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][1]), std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][1]))))) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < std::min({groupTrack.cfgCutMaxAbsNSigmaPid.value, std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][1]), std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][1])}))) { return 0; } } else { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { return 0; } } } else if constexpr (pidStrategy == PidStrategy::kTpcAndTof) { if (doRejectingOthers) { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < groupTrack.cfgCutMaxAbsNSigmaPid.value && std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < std::min(groupTrack.cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][1]), std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][1]))))) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < groupTrack.cfgCutMaxAbsNSigmaPid.value && std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < std::min({groupTrack.cfgCutMaxAbsNSigmaPid.value, std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][1]), std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][1])}))) { return 0; } } else { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < groupTrack.cfgCutMaxAbsNSigmaPid.value && std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][0]) < groupTrack.cfgCutMaxAbsNSigmaPid.value && std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][1]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { return 0; } } } else if constexpr (pidStrategy == PidStrategy::kTpcTof) { if (doRejectingOthers) { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][2]) < std::min(groupTrack.cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][2]), std::fabs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][2]))))) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][2]) < std::min({groupTrack.cfgCutMaxAbsNSigmaPid.value, std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 1) % static_cast(ParticleSpecies::kNSpecies)][2]), std::abs(*pointersNSigmaPid[(static_cast(particleSpecies) + 2) % static_cast(ParticleSpecies::kNSpecies)][2])}))) { return 0; } } else { - if (!(std::fabs(*pointersNSigmaPid[static_cast(particleSpecies)][2]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::abs(*pointersNSigmaPid[static_cast(particleSpecies)][2]) < groupTrack.cfgCutMaxAbsNSigmaPid.value)) { return 0; } } @@ -1819,14 +1857,14 @@ struct PartNumFluc { if (!(groupTrack.cfgCutMinPt.value < holderMcParticle.pt && holderMcParticle.pt < groupTrack.cfgCutMaxPt.value)) { return false; } - if (!(std::fabs(holderMcParticle.eta) < groupTrack.cfgCutMaxAbsEta.value)) { + if (!(std::abs(holderMcParticle.eta) < groupTrack.cfgCutMaxAbsEta.value)) { return false; } } else { if (!(groupTrack.cfgCutMinPt.value < holderTrack.pt && holderTrack.pt < groupTrack.cfgCutMaxPt.value)) { return false; } - if (!(std::fabs(holderTrack.eta) < groupTrack.cfgCutMaxAbsEta.value)) { + if (!(std::abs(holderTrack.eta) < groupTrack.cfgCutMaxAbsEta.value)) { return false; } } @@ -1835,18 +1873,27 @@ struct PartNumFluc { bool isGoodDca() { - if (holderTrack.sign == 0) { - return false; - } - const TFormula* const fPtMeanDcaXy = (holderTrack.sign > 0 ? holderCcdb.fPtMeanDcaXyP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtMeanDcaXyM.at(std::abs(holderEvent.runGroupIndex) - 1)); - const TFormula* const fPtSigmaDcaXy = (holderTrack.sign > 0 ? holderCcdb.fPtSigmaDcaXyP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtSigmaDcaXyM.at(std::abs(holderEvent.runGroupIndex) - 1)); - if (!fPtMeanDcaXy || !fPtSigmaDcaXy || !(std::fabs(holderTrack.dcaXY - fPtMeanDcaXy->Eval(holderTrack.pt)) < groupTrack.cfgCutMaxAbsNSigmaDcaXy.value * fPtSigmaDcaXy->Eval(holderTrack.pt))) { - return false; - } - const TFormula* const fPtMeanDcaZ = (holderTrack.sign > 0 ? holderCcdb.fPtMeanDcaZP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtMeanDcaZM.at(std::abs(holderEvent.runGroupIndex) - 1)); - const TFormula* const fPtSigmaDcaZ = (holderTrack.sign > 0 ? holderCcdb.fPtSigmaDcaZP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtSigmaDcaZM.at(std::abs(holderEvent.runGroupIndex) - 1)); - if (!fPtMeanDcaZ || !fPtSigmaDcaZ || !(std::fabs(holderTrack.dcaZ - fPtMeanDcaZ->Eval(holderTrack.pt)) < groupTrack.cfgCutMaxAbsNSigmaDcaZ.value * fPtSigmaDcaZ->Eval(holderTrack.pt))) { - return false; + if (!groupTrack.cfgFlagRecalibrationDca.value) { + if (!(std::abs(holderTrack.dcaXY) < groupTrack.cfgCutMaxAbsNSigmaDcaXy.value)) { + return false; + } + if (!(std::abs(holderTrack.dcaZ) < groupTrack.cfgCutMaxAbsNSigmaDcaZ.value)) { + return false; + } + } else { + if (holderTrack.sign == 0) { + return false; + } + const TFormula* const fPtMeanDcaXy = (holderTrack.sign > 0 ? holderCcdb.fPtMeanDcaXyP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtMeanDcaXyM.at(std::abs(holderEvent.runGroupIndex) - 1)); + const TFormula* const fPtSigmaDcaXy = (holderTrack.sign > 0 ? holderCcdb.fPtSigmaDcaXyP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtSigmaDcaXyM.at(std::abs(holderEvent.runGroupIndex) - 1)); + if (!fPtMeanDcaXy || !fPtSigmaDcaXy || !(std::abs(holderTrack.dcaXY - fPtMeanDcaXy->Eval(holderTrack.pt)) < groupTrack.cfgCutMaxAbsNSigmaDcaXy.value * fPtSigmaDcaXy->Eval(holderTrack.pt))) { + return false; + } + const TFormula* const fPtMeanDcaZ = (holderTrack.sign > 0 ? holderCcdb.fPtMeanDcaZP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtMeanDcaZM.at(std::abs(holderEvent.runGroupIndex) - 1)); + const TFormula* const fPtSigmaDcaZ = (holderTrack.sign > 0 ? holderCcdb.fPtSigmaDcaZP.at(std::abs(holderEvent.runGroupIndex) - 1) : holderCcdb.fPtSigmaDcaZM.at(std::abs(holderEvent.runGroupIndex) - 1)); + if (!fPtMeanDcaZ || !fPtSigmaDcaZ || !(std::abs(holderTrack.dcaZ - fPtMeanDcaZ->Eval(holderTrack.pt)) < groupTrack.cfgCutMaxAbsNSigmaDcaZ.value * fPtSigmaDcaZ->Eval(holderTrack.pt))) { + return false; + } } return true; } @@ -1920,25 +1967,41 @@ struct PartNumFluc { holderTrack.tofNSigmaPi = holderTrack.tofNSigmaKa = holderTrack.tofNSigmaPr = HolderTrack::truncateNSigmaPid(HolderTrack::TruncationAbsNSigmaPid); } if (holderTrack.hasTpcPid && holderTrack.hasTofPid) { - holderTrack.tpcTofNSigmaPi = HolderTrack::truncateNSigmaPid(std::copysign(std::hypot(holderTrack.tpcNSigmaPi, holderTrack.tofNSigmaPi), std::fabs(holderTrack.tpcNSigmaPi) >= std::fabs(holderTrack.tofNSigmaPi) ? holderTrack.tpcNSigmaPi : holderTrack.tofNSigmaPi)); - holderTrack.tpcTofNSigmaKa = HolderTrack::truncateNSigmaPid(std::copysign(std::hypot(holderTrack.tpcNSigmaKa, holderTrack.tofNSigmaKa), std::fabs(holderTrack.tpcNSigmaKa) >= std::fabs(holderTrack.tofNSigmaKa) ? holderTrack.tpcNSigmaKa : holderTrack.tofNSigmaKa)); - holderTrack.tpcTofNSigmaPr = HolderTrack::truncateNSigmaPid(std::copysign(std::hypot(holderTrack.tpcNSigmaPr, holderTrack.tofNSigmaPr), std::fabs(holderTrack.tpcNSigmaPr) >= std::fabs(holderTrack.tofNSigmaPr) ? holderTrack.tpcNSigmaPr : holderTrack.tofNSigmaPr)); + holderTrack.tpcTofNSigmaPi = HolderTrack::truncateNSigmaPid(std::copysign(std::hypot(holderTrack.tpcNSigmaPi, holderTrack.tofNSigmaPi), std::abs(holderTrack.tpcNSigmaPi) >= std::abs(holderTrack.tofNSigmaPi) ? holderTrack.tpcNSigmaPi : holderTrack.tofNSigmaPi)); + holderTrack.tpcTofNSigmaKa = HolderTrack::truncateNSigmaPid(std::copysign(std::hypot(holderTrack.tpcNSigmaKa, holderTrack.tofNSigmaKa), std::abs(holderTrack.tpcNSigmaKa) >= std::abs(holderTrack.tofNSigmaKa) ? holderTrack.tpcNSigmaKa : holderTrack.tofNSigmaKa)); + holderTrack.tpcTofNSigmaPr = HolderTrack::truncateNSigmaPid(std::copysign(std::hypot(holderTrack.tpcNSigmaPr, holderTrack.tofNSigmaPr), std::abs(holderTrack.tpcNSigmaPr) >= std::abs(holderTrack.tofNSigmaPr) ? holderTrack.tpcNSigmaPr : holderTrack.tofNSigmaPr)); } else { holderTrack.tpcTofNSigmaPi = holderTrack.tpcTofNSigmaKa = holderTrack.tpcTofNSigmaPr = HolderTrack::truncateNSigmaPid(HolderTrack::TruncationAbsNSigmaPid); } if constexpr (doInitingEvent) { - if (track.isPrimaryTrack()) { - holderEvent.nGlobalTracks++; - if (track.isPVContributor()) { - holderEvent.nPvContributors++; - } - holderEvent.meanDcaXy += holderTrack.dcaXY; - holderEvent.meanSquareDcaXy += std::pow(holderTrack.dcaXY, 2.); - holderEvent.meanDcaZ += holderTrack.dcaZ; - holderEvent.meanSquareDcaZ += std::pow(holderTrack.dcaZ, 2.); - if (holderTrack.hasTofPid) { - holderEvent.nTofBeta++; + if (holderTrack.sign > 0) { + if (track.isPrimaryTrack()) { + holderEvent.nGlobalTracksP++; + if (track.isPVContributor()) { + holderEvent.nPvContributorsP++; + } + holderEvent.meanDcaXyP += holderTrack.dcaXY; + holderEvent.meanSquareDcaXyP += std::pow(holderTrack.dcaXY, 2.); + holderEvent.meanDcaZP += holderTrack.dcaZ; + holderEvent.meanSquareDcaZP += std::pow(holderTrack.dcaZ, 2.); + if (holderTrack.hasTofPid) { + holderEvent.nTofBetaP++; + } + } + } else if (holderTrack.sign < 0) { + if (track.isPrimaryTrack()) { + holderEvent.nGlobalTracksM++; + if (track.isPVContributor()) { + holderEvent.nPvContributorsM++; + } + holderEvent.meanDcaXyM += holderTrack.dcaXY; + holderEvent.meanSquareDcaXyM += std::pow(holderTrack.dcaXY, 2.); + holderEvent.meanDcaZM += holderTrack.dcaZ; + holderEvent.meanSquareDcaZM += std::pow(holderTrack.dcaZ, 2.); + if (holderTrack.hasTofPid) { + holderEvent.nTofBetaM++; + } } } } @@ -1960,25 +2023,25 @@ struct PartNumFluc { hrQaRun.fill(HIST("QaRun/pRunIndexPhi_p"), holderEvent.runIndex, holderTrack.phi); if (holderTrack.hasTpcPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcDeDx_p"), holderEvent.runIndex, track.tpcSignal()); - if (std::fabs(holderTrack.tpcNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tpcNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPi_p"), holderEvent.runIndex, holderTrack.tpcNSigmaPi); } - if (std::fabs(holderTrack.tpcNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tpcNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaKa_p"), holderEvent.runIndex, holderTrack.tpcNSigmaKa); } - if (std::fabs(holderTrack.tpcNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tpcNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPr_p"), holderEvent.runIndex, holderTrack.tpcNSigmaPr); } } if (holderTrack.hasTofPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofInverseBeta_p"), holderEvent.runIndex, 1. / track.beta()); - if (std::fabs(holderTrack.tofNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tofNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPi_p"), holderEvent.runIndex, holderTrack.tofNSigmaPi); } - if (std::fabs(holderTrack.tofNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tofNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaKa_p"), holderEvent.runIndex, holderTrack.tofNSigmaKa); } - if (std::fabs(holderTrack.tofNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tofNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPr_p"), holderEvent.runIndex, holderTrack.tofNSigmaPr); } } @@ -1997,25 +2060,25 @@ struct PartNumFluc { hrQaRun.fill(HIST("QaRun/pRunIndexPhi_m"), holderEvent.runIndex, holderTrack.phi); if (holderTrack.hasTpcPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcDeDx_m"), holderEvent.runIndex, track.tpcSignal()); - if (std::fabs(holderTrack.tpcNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tpcNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPi_m"), holderEvent.runIndex, holderTrack.tpcNSigmaPi); } - if (std::fabs(holderTrack.tpcNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tpcNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaKa_m"), holderEvent.runIndex, holderTrack.tpcNSigmaKa); } - if (std::fabs(holderTrack.tpcNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tpcNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPr_m"), holderEvent.runIndex, holderTrack.tpcNSigmaPr); } } if (holderTrack.hasTofPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofInverseBeta_m"), holderEvent.runIndex, 1. / track.beta()); - if (std::fabs(holderTrack.tofNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tofNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPi_m"), holderEvent.runIndex, holderTrack.tofNSigmaPi); } - if (std::fabs(holderTrack.tofNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tofNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaKa_m"), holderEvent.runIndex, holderTrack.tofNSigmaKa); } - if (std::fabs(holderTrack.tofNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + if (std::abs(holderTrack.tofNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPr_m"), holderEvent.runIndex, holderTrack.tofNSigmaPr); } } @@ -2243,11 +2306,11 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagQaEvent.value) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexVxVy"), holderEvent.runIndex, collision.posX(), collision.posY()); - hrQaEvent.fill(HIST("QaEvent/hRunIndexVz"), holderEvent.runIndex, holderEvent.vz); + hrQaEvent.fill(HIST("QaEvent/hVxVy"), collision.posX(), collision.posY()); + hrQaEvent.fill(HIST("QaEvent/hVz"), holderEvent.vz); } - if (!(std::fabs(holderEvent.vz) < groupEvent.cfgCutMaxAbsVertexZ.value)) { + if (!(std::abs(holderEvent.vz) < groupEvent.cfgCutMaxAbsVertexZ.value)) { hrCounter.fill(HIST("hNEvents"), 6.); return false; } @@ -2256,8 +2319,17 @@ struct PartNumFluc { hrQaRun.fill(HIST("QaRun/pRunIndexVx"), holderEvent.runIndex, collision.posX()); hrQaRun.fill(HIST("QaRun/pRunIndexVy"), holderEvent.runIndex, collision.posY()); hrQaRun.fill(HIST("QaRun/pRunIndexVz"), holderEvent.runIndex, holderEvent.vz); - hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0a"), holderEvent.runIndex, collision.multZeqFT0A()); - hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0c"), holderEvent.runIndex, collision.multZeqFT0C()); + hrQaRun.fill(HIST("QaRun/pRunIndexMultiplicityFt0a"), holderEvent.runIndex, collision.multZeqFT0A()); + hrQaRun.fill(HIST("QaRun/pRunIndexMultiplicityFt0c"), holderEvent.runIndex, collision.multZeqFT0C()); + if (HolderEvent::RangeCentrality.first <= collision.centFT0A() && collision.centFT0A() <= HolderEvent::RangeCentrality.second) { + hrQaRun.fill(HIST("QaRun/pRunIndexCentralityFt0a"), holderEvent.runIndex, collision.centFT0A()); + } + if (HolderEvent::RangeCentrality.first <= collision.centFT0C() && collision.centFT0C() <= HolderEvent::RangeCentrality.second) { + hrQaRun.fill(HIST("QaRun/pRunIndexCentralityFt0c"), holderEvent.runIndex, collision.centFT0C()); + } + if (HolderEvent::RangeCentrality.first <= collision.centFT0M() && collision.centFT0M() <= HolderEvent::RangeCentrality.second) { + hrQaRun.fill(HIST("QaRun/pRunIndexCentralityFt0m"), holderEvent.runIndex, collision.centFT0M()); + } } for (const auto& track : tracks) { @@ -2267,35 +2339,50 @@ struct PartNumFluc { initTrack(track); } - if (holderEvent.nGlobalTracks > 0.) { - holderEvent.meanDcaXy /= holderEvent.nGlobalTracks; - holderEvent.meanSquareDcaXy /= holderEvent.nGlobalTracks; - holderEvent.meanDcaZ /= holderEvent.nGlobalTracks; - holderEvent.meanSquareDcaZ /= holderEvent.nGlobalTracks; + if (holderEvent.nGlobalTracksP > 0.) { + holderEvent.meanDcaXyP /= holderEvent.nGlobalTracksP; + holderEvent.meanSquareDcaXyP /= holderEvent.nGlobalTracksP; + holderEvent.meanDcaZP /= holderEvent.nGlobalTracksP; + holderEvent.meanSquareDcaZP /= holderEvent.nGlobalTracksP; + } + if (holderEvent.nGlobalTracksM > 0.) { + holderEvent.meanDcaXyM /= holderEvent.nGlobalTracksM; + holderEvent.meanSquareDcaXyM /= holderEvent.nGlobalTracksM; + holderEvent.meanDcaZM /= holderEvent.nGlobalTracksM; + holderEvent.meanSquareDcaZM /= holderEvent.nGlobalTracksM; } if (groupAnalysis.cfgFlagQaRun.value) { - hrQaRun.fill(HIST("QaRun/pRunIndexNGlobalTracks"), holderEvent.runIndex, holderEvent.nGlobalTracks); - hrQaRun.fill(HIST("QaRun/pRunIndexNPvContributors"), holderEvent.runIndex, holderEvent.nPvContributors); - if (holderEvent.nGlobalTracks > 0) { - hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaXy"), holderEvent.runIndex, holderEvent.meanDcaXy); - hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaXy"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaXy - std::pow(holderEvent.meanDcaXy, 2.))); - hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaZ"), holderEvent.runIndex, holderEvent.meanDcaZ); - hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaZ"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaZ - std::pow(holderEvent.meanDcaZ, 2.))); - } - hrQaRun.fill(HIST("QaRun/pRunIndexNTofBeta"), holderEvent.runIndex, holderEvent.nTofBeta); + hrQaRun.fill(HIST("QaRun/pRunIndexNGlobalTracks_p"), holderEvent.runIndex, holderEvent.nGlobalTracksP); + hrQaRun.fill(HIST("QaRun/pRunIndexNGlobalTracks_m"), holderEvent.runIndex, holderEvent.nGlobalTracksM); + hrQaRun.fill(HIST("QaRun/pRunIndexNPvContributors_p"), holderEvent.runIndex, holderEvent.nPvContributorsP); + hrQaRun.fill(HIST("QaRun/pRunIndexNPvContributors_m"), holderEvent.runIndex, holderEvent.nPvContributorsM); + if (holderEvent.nGlobalTracksP > 0) { + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaXy_p"), holderEvent.runIndex, holderEvent.meanDcaXyP); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaXy_p"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaXyP - std::pow(holderEvent.meanDcaXyP, 2.))); + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaZ_p"), holderEvent.runIndex, holderEvent.meanDcaZP); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaZ_p"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaZP - std::pow(holderEvent.meanDcaZP, 2.))); + } + if (holderEvent.nGlobalTracksM > 0) { + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaXy_m"), holderEvent.runIndex, holderEvent.meanDcaXyM); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaXy_m"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaXyM - std::pow(holderEvent.meanDcaXyM, 2.))); + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaZ_m"), holderEvent.runIndex, holderEvent.meanDcaZM); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaZ_m"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaZM - std::pow(holderEvent.meanDcaZM, 2.))); + } + hrQaRun.fill(HIST("QaRun/pRunIndexNTofBeta_p"), holderEvent.runIndex, holderEvent.nTofBetaP); + hrQaRun.fill(HIST("QaRun/pRunIndexNTofBeta_m"), holderEvent.runIndex, holderEvent.nTofBetaM); } if (groupAnalysis.cfgFlagQaEvent.value) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexNPvContributorsNGlobalTracks"), holderEvent.runIndex, holderEvent.nPvContributors, holderEvent.nGlobalTracks); - if (holderEvent.nGlobalTracks > 0) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaXy); - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaZ); + hrQaEvent.fill(HIST("QaEvent/hNPvContributorsNGlobalTracks"), holderEvent.nPvContributorsP + holderEvent.nPvContributorsM, holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM); + if (holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM > 0) { + hrQaEvent.fill(HIST("QaEvent/hNGlobalTracksMeanDcaXy"), holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM, (holderEvent.meanDcaXyP * holderEvent.nGlobalTracksP + holderEvent.meanDcaXyM * holderEvent.nGlobalTracksM) / (holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM)); + hrQaEvent.fill(HIST("QaEvent/hNGlobalTracksMeanDcaZ"), holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM, (holderEvent.meanDcaZP * holderEvent.nGlobalTracksP + holderEvent.meanDcaZM * holderEvent.nGlobalTracksM) / (holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM)); } - hrQaEvent.fill(HIST("QaEvent/hRunIndexNTofBetaNGlobalTracks"), holderEvent.runIndex, holderEvent.nTofBeta, holderEvent.nGlobalTracks); + hrQaEvent.fill(HIST("QaEvent/hNTofBetaNGlobalTracks"), holderEvent.nTofBetaP + holderEvent.nTofBetaM, holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM); } - if (!(holderEvent.nPvContributors - holderEvent.nGlobalTracks > groupEvent.cfgCutMinDeviationNPvContributors.value)) { + if (!(holderEvent.nPvContributorsP + holderEvent.nPvContributorsM - holderEvent.nGlobalTracksP - holderEvent.nGlobalTracksM > groupEvent.cfgCutMinDeviationNPvContributors.value)) { hrCounter.fill(HIST("hNEvents"), 7.); return false; } @@ -2303,11 +2390,11 @@ struct PartNumFluc { hrCounter.fill(HIST("hNEvents"), 1.); if (groupAnalysis.cfgFlagQaEvent.value) { - if (holderEvent.nGlobalTracks > 0) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaXy); - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaZ); + if (holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM > 0) { + hrQaEvent.fill(HIST("QaEvent/hNGlobalTracksMeanDcaXy_nPvContributorsCut"), holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM, (holderEvent.meanDcaXyP * holderEvent.nGlobalTracksP + holderEvent.meanDcaXyM * holderEvent.nGlobalTracksM) / (holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM)); + hrQaEvent.fill(HIST("QaEvent/hNGlobalTracksMeanDcaZ_nPvContributorsCut"), holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM, (holderEvent.meanDcaZP * holderEvent.nGlobalTracksP + holderEvent.meanDcaZM * holderEvent.nGlobalTracksM) / (holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM)); } - hrQaEvent.fill(HIST("QaEvent/hRunIndexNTofBetaNGlobalTracks_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nTofBeta, holderEvent.nGlobalTracks); + hrQaEvent.fill(HIST("QaEvent/hNTofBetaNGlobalTracks_nPvContributorsCut"), holderEvent.nTofBetaP + holderEvent.nTofBetaM, holderEvent.nGlobalTracksP + holderEvent.nGlobalTracksM); } if (groupAnalysis.cfgFlagQaCentrality.value) { @@ -2581,7 +2668,7 @@ struct PartNumFluc { return false; } - if (!(std::fabs(holderMcEvent.vz) < groupEvent.cfgCutMaxAbsVertexZMc.value)) { + if (!(std::abs(holderMcEvent.vz) < groupEvent.cfgCutMaxAbsVertexZMc.value)) { hrCounter.fill(HIST("hNMcEvents"), 4.); return false; } @@ -2916,9 +3003,9 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagQaPhi.value) { if (holderMcParticle.charge > 0) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } else if (holderMcParticle.charge < 0) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } } @@ -2926,7 +3013,7 @@ struct PartNumFluc { switch (holderMcParticle.pdgCode) { case PDG_t::kPiPlus: if (groupAnalysis.cfgFlagQaPhiPi.value) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcPiP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcPiP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } if (groupAnalysis.cfgFlagCalculationYieldPi.value) { hrCalculationYield.fill(HIST("CalculationYield/hVzCentralityPtEtaMc_mcPiP"), holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); @@ -2937,7 +3024,7 @@ struct PartNumFluc { break; case PDG_t::kPiMinus: if (groupAnalysis.cfgFlagQaPhiPi.value) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcPiM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcPiM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } if (groupAnalysis.cfgFlagCalculationYieldPi.value) { hrCalculationYield.fill(HIST("CalculationYield/hVzCentralityPtEtaMc_mcPiM"), holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); @@ -2948,7 +3035,7 @@ struct PartNumFluc { break; case PDG_t::kKPlus: if (groupAnalysis.cfgFlagQaPhiKa.value) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcKaP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcKaP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } if (groupAnalysis.cfgFlagCalculationYieldKa.value) { hrCalculationYield.fill(HIST("CalculationYield/hVzCentralityPtEtaMc_mcKaP"), holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); @@ -2962,7 +3049,7 @@ struct PartNumFluc { break; case PDG_t::kKMinus: if (groupAnalysis.cfgFlagQaPhiKa.value) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcKaM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcKaM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } if (groupAnalysis.cfgFlagCalculationYieldKa.value) { hrCalculationYield.fill(HIST("CalculationYield/hVzCentralityPtEtaMc_mcKaM"), holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); @@ -2976,7 +3063,7 @@ struct PartNumFluc { break; case PDG_t::kProton: if (groupAnalysis.cfgFlagQaPhiPr.value) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcPrP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcPrP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } if (groupAnalysis.cfgFlagCalculationYieldPr.value) { hrCalculationYield.fill(HIST("CalculationYield/hVzCentralityPtEtaMc_mcPrP"), holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); @@ -2990,7 +3077,7 @@ struct PartNumFluc { break; case PDG_t::kProtonBar: if (groupAnalysis.cfgFlagQaPhiPr.value) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcPrM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcPrM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); } if (groupAnalysis.cfgFlagCalculationYieldPr.value) { hrCalculationYield.fill(HIST("CalculationYield/hVzCentralityPtEtaMc_mcPrM"), holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); @@ -3053,19 +3140,19 @@ struct PartNumFluc { if ((groupAnalysis.cfgFlagQaPhi.value || groupAnalysis.cfgFlagQaPhiPi.value || groupAnalysis.cfgFlagQaPhiKa.value || groupAnalysis.cfgFlagQaPhiPr.value) && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary()) && holderTrack.hasTpcPid) { if (groupAnalysis.cfgFlagQaPhi.value) { if (holderTrack.sign > 0.) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_tpcP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_tpcP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); } else if (holderTrack.sign < 0.) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_tpcM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_tpcM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); } if (holderTrack.hasTofPid) { if (holderTrack.sign > 0.) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_tpcTofP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_tpcTofP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcTofP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcTofP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); } else if (holderTrack.sign < 0.) { - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_tpcTofM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_tpcTofM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcTofM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcTofM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); } } } @@ -3123,23 +3210,23 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagQaPhiPr.value) { switch (holderMcParticle.pdgCode) { case PDG_t::kProton: - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhiMc_mcTpcPrP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhi_mcTpcPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcPrP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); break; case PDG_t::kProtonBar: - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhiMc_mcTpcPrM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhi_mcTpcPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcPrM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); break; } if (holderTrack.hasTofPid) { switch (holderMcParticle.pdgCode) { case PDG_t::kProton: - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhiMc_mcTpcTofPrP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhi_mcTpcTofPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcTofPrP"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcTofPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); break; case PDG_t::kProtonBar: - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhiMc_mcTpcTofPrM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); - hrQaPhi.fill(HIST("QaPhi/hVzCentralityPtEtaPhi_mcTpcTofPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhiMc_mcTpcTofPrM"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.phi); + hrQaPhi.fill(HIST("QaPhi/hCentralityPtEtaPhi_mcTpcTofPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); break; } } diff --git a/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx b/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx index ce3b6eccf2e..ba43045979e 100644 --- a/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx @@ -13,11 +13,13 @@ /// \brief Analysis task for event-by-event radial-flow decorrelation measurement. /// \author Somadutta Bhatta -#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -25,6 +27,8 @@ #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/MathConstants.h" #include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "FT0Base/Geometry.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -35,6 +39,7 @@ #include "Framework/runDataProcessing.h" #include "MathUtils/Utils.h" #include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/PID.h" #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/TrackTPCITS.h" @@ -55,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -68,42 +74,34 @@ using namespace constants::math; struct RadialFlowDecorr { + static constexpr int KPidPionOne = 1; + static constexpr int KPidKaonTwo = 2; + static constexpr int KPidProtonThree = 3; + static constexpr int KConstTen = 10; + + static constexpr int KnFt0cCell = 96; static constexpr int KIntM = 3; static constexpr int KIntK = 3; - static constexpr int KNEta = 17; - static constexpr int KNpT = 3; - static constexpr float KFloatEpsilon = 1e-6f; static constexpr int KPiPlus = 211; static constexpr int KKPlus = 321; static constexpr int KProton = 2212; - - static constexpr float KCentTestMin = 10.f; - static constexpr float KCentTestMaxLo = 60.f; - static constexpr float KCentTestMaxHi = 70.f; - static constexpr float KCentCovCut = 1.0f; static constexpr float KBinOffset = 0.5f; - - static constexpr float KHalf = 0.5f; static constexpr float KPhiMin = 0.f; - static constexpr int KNbinsZvtx = 240; static constexpr float KZvtxMin = -12.f; static constexpr float KZvtxMax = 12.f; - static constexpr int KNbinsP = 100; static constexpr float KPMin = 0.f; static constexpr float KPMax = 10.f; static constexpr int KNbinsPt = 200; - static constexpr float KPtMin = 0.f; + static constexpr float KPtMin = 0.15f; static constexpr float KPtMax = 10.f; - static constexpr int KNbinsEta = 120; static constexpr float KEtaMin = -1.2f; static constexpr float KEtaMax = 1.2f; static constexpr int KNbinsPhi = 64; static constexpr float KEtaAxisMin = -0.8f; static constexpr float KEtaAxisMax = 0.8f; - static constexpr int KNbinsPhiFine = 16; static constexpr int KNbinsPtRes = 50; static constexpr float KPtResMax = 1.f; static constexpr int KNbinsEtaRes = 100; @@ -116,56 +114,72 @@ struct RadialFlowDecorr { static constexpr float KEtaFineMax = 1.f; static constexpr int KNbinsDca = 400; static constexpr float KDcaMax = 0.2f; - static constexpr int KNbinsPtCoarse = 50; - static constexpr float KPtMinDefault = 0.2f; - static constexpr float KPtMidMax = 3.0f; - static constexpr float KPtHighMax = 5.0f; - static constexpr float KPtFullMax = 10.0f; static constexpr float KCentMax = 90; - enum PID { kInclusive = 0, - kCombinedPID, - kNumPID }; + + enum PIDIdx { + kInclusiveIdx = 0, + kPiMinusIdx, + kPiPlusIdx, + kPiAllIdx, + kKaMinusIdx, + kKaPlusIdx, + kKaAllIdx, + kAntiPrIdx, + kPrIdx, + kPrAllIdx, + KNsp + }; + + inline static const std::vector pidSuffix = {"", "_PiMinus", "_PiPlus", "_PiAll", "_KaMinus", "_KaPlus", "_KaAll", "_AntiPr", "_Pr", "_PrAll"}; + + struct PIDMeanSigmaMap { + static constexpr int MaxCentBins = 100; + double meanTOF[KNsp][MaxCentBins] = {{0.0}}; + double sigmaTOF[KNsp][MaxCentBins] = {{1.0}}; // Default sigma = 1 + double meanTPC[KNsp][MaxCentBins] = {{0.0}}; + double sigmaTPC[KNsp][MaxCentBins] = {{1.0}}; // Default sigma = 1 + }; + + PIDMeanSigmaMap* pidMeanSigmaMap = nullptr; + enum ECentralityEstimator { kCentFT0C = 1, - kCentFT0A = 2, - kCentFT0M = 3, + kCentFT0M = 2, + kCentFDDM = 3, kCentFV0A = 4 }; enum SystemType { kPbPb = 1, - kOO = 2, - kpPb = 3, + kNeNe = 2, + kOO = 3, kpp = 4 }; static constexpr float KinvalidCentrality = -1.0f; - const std::vector pidSuffix = {"", "_PID"}; - - const std::vector etaLw = { + inline static const std::vector etaLw = { -0.8, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7}; - const std::vector etaUp = { + inline static const std::vector etaUp = { 0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}; - const std::vector pTLw = {KPtMinDefault, KPtMinDefault, KPtMinDefault}; - const std::vector pTUp = {KPtMidMax, KPtHighMax, KPtFullMax}; - Configurable cfgVtxZCut{"cfgVtxZCut", 10.f, "z-vertex range"}; Configurable cfgPtMin{"cfgPtMin", 0.2f, "min pT"}; - Configurable cfgPtMax{"cfgPtMax", 10.0f, "max pT"}; + Configurable cfgPtMax{"cfgPtMax", 5.0f, "max pT"}; Configurable cfgEtaCut{"cfgEtaCut", 0.8f, "|η| cut"}; - Configurable cfgDCAXY{"cfgDCAXY", 2.4f, "DCAxy cut"}; - Configurable cfgDCAZ{"cfgDCAZ", 3.2f, "DCAz cut"}; - Configurable cfgTPCClsMin{"cfgTPCClsMin", 70.f, "min TPC clusters"}; - Configurable cfgChi2TPCMax{"cfgChi2TPCMax", 4.0f, "max TPC χ²"}; - Configurable cfgPIDnSigmaCut{"cfgPIDnSigmaCut", 3.f, "TPC PID |nσ| cut"}; - Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable cfgCutTpcChi2NCl{"cfgCutTpcChi2NCl", 2.5f, "Maximum TPCchi2NCl"}; - Configurable cfgCutItsChi2NCl{"cfgCutItsChi2NCl", 36.0f, "Maximum ITSchi2NCl"}; Configurable cfgCutTracKDcaMaxZ{"cfgCutTracKDcaMaxZ", 2.0f, "Maximum DcaZ"}; Configurable cfgCutTracKDcaMaxXY{"cfgCutTracKDcaMaxXY", 0.2f, "Maximum DcaZ"}; + Configurable cfgPtDepDCAxy{"cfgPtDepDCAxy", false, "Use pt-dependent DCAxy cut"}; + Configurable cfgDcaXyP0{"cfgDcaXyP0", 0.0026f, "p0 for DCAxy"}; + Configurable cfgDcaXyP1{"cfgDcaXyP1", 0.005f, "p1 for DCAxy"}; + Configurable cfgDcaXyP2{"cfgDcaXyP2", 1.01f, "p2 for DCAxy"}; + + Configurable cfgPtDepDCAz{"cfgPtDepDCAz", false, "Use pt-dependent DCAz cut"}; + Configurable cfgDcaZP0{"cfgDcaZP0", 0.0026f, "p0 for DCAz"}; + Configurable cfgDcaZP1{"cfgDcaZP1", 0.005f, "p1 for DCAz"}; + Configurable cfgDcaZP2{"cfgDcaZP2", 1.01f, "p2 for DCAz"}; + Configurable cfgITScluster{"cfgITScluster", 1, "Minimum Number of ITS cluster"}; Configurable cfgTPCcluster{"cfgTPCcluster", 80, "Minimum Number of TPC cluster"}; Configurable cfgTPCnCrossedRows{"cfgTPCnCrossedRows", 70, "Minimum Number of TPC crossed-rows"}; @@ -174,24 +188,29 @@ struct RadialFlowDecorr { Configurable cfgnSigmaCutTPC{"cfgnSigmaCutTPC", 2.0f, "PID nSigma cut for TPC"}; Configurable cfgnSigmaCutTOF{"cfgnSigmaCutTOF", 2.0f, "PID nSigma cut for TOF"}; Configurable cfgnSigmaCutCombTPCTOF{"cfgnSigmaCutCombTPCTOF", 2.0f, "PID nSigma combined cut for TPC and TOF"}; + Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; Configurable cfgCutPtUpper{"cfgCutPtUpper", 10.0f, "Higher pT cut for inclusive hadron analysis"}; Configurable cfgCutPtUpperPID{"cfgCutPtUpperPID", 6.0f, "Higher pT cut for identified particle analysis"}; Configurable cfgCutEta{"cfgCutEta", 0.8f, "absolute Eta cut"}; - Configurable cfgCutEtaLeft{"cfgCutEtaLeft", 0.8f, "Left end of eta gap"}; - Configurable cfgCutEtaRight{"cfgCutEtaRight", 0.8f, "Right end of eta gap"}; - Configurable cfgNSubsample{"cfgNSubsample", 10, "Number of subsamples"}; - Configurable cfgCentralityChoice{"cfgCentralityChoice", 1, "Which centrality estimator? 1-->FT0C, 2-->FT0A, 3-->FT0M, 4-->FV0A"}; - Configurable cfgEvSelkNoSameBunchPileup{"cfgEvSelkNoSameBunchPileup", true, "Pileup removal"}; + Configurable cfgNsubsample{"cfgNsubsample", 10, "Number of subsamples"}; + Configurable cfgCentralityChoice{"cfgCentralityChoice", 1, "Which centrality estimator? 1-->FT0C, 2-->FT0M, 3-->FDDM, 4-->FV0A"}; + Configurable cfgEvSelNoSameBunchPileup{"cfgEvSelNoSameBunchPileup", true, "Pileup removal"}; Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; - Configurable cfgEvSelkNoITSROFrameBorder{"cfgEvSelkNoITSROFrameBorder", true, "ITSROFrame border event selection cut"}; - Configurable cfgEvSelkNoTimeFrameBorder{"cfgEvSelkNoTimeFrameBorder", true, "TimeFrame border event selection cut"}; Configurable cfgIsGoodZvtxFT0VsPV{"cfgIsGoodZvtxFT0VsPV", true, "Good Vertexing cut"}; - Configurable cfgNchPbMax{"cfgNchPbMax", 4000, "Max Nch range for PbPb collisions"}; - Configurable cfgNchOMax{"cfgNchOMax", 600, "Max Nch range for OO collisions"}; + Configurable cfgPupnSig{"cfgPupnSig", 6.0f, "Additional Pileup Cut"}; + Configurable cfgApplySigPupCut{"cfgApplySigPupCut", 0, "nSig Pileup Cut"}; + Configurable cfgApplyLinPupCut{"cfgApplyLinPupCut", 0, "Lin Pileup Cut"}; + Configurable cfgLinPupParam0{"cfgLinPupParam0", 3.0f, "(Upper) Linear Pileup Cut Const"}; + Configurable cfgLinPupParam1{"cfgLinPupParam1", 3.0f, "(Upper) Linear Pileup Slope"}; + Configurable cfgLinPupParam2{"cfgLinPupParam2", 3.0f, "(Lower) Linear Pileup Cut Const"}; + Configurable cfgLinPupParam3{"cfgLinPupParam3", 3.0f, "(Lower) Linear Pileup Slope"}; + + Configurable cfgNchPbMax{"cfgNchPbMax", 10000, "Max Nch range for PbPb collisions"}; + Configurable cfgNchOMax{"cfgNchOMax", 1000, "Max Nch range for OO collisions"}; - Configurable cfgSys{"cfgSys", 1, "Efficiency to be used for which system? 1-->PbPb, 2-->OO, 3-->pPb, 4-->pp"}; + Configurable cfgSys{"cfgSys", 1, "Efficiency to be used for which system? 1-->PbPb, 2-->NeNe, 3-->OO, 4-->pp"}; Configurable cfgFlat{"cfgFlat", false, "Whether to use flattening weights"}; Configurable cfgEff{"cfgEff", false, "Whether to use Efficiency weights"}; Configurable cfgZDC{"cfgZDC", false, "Whether to use ZDC for pileup histograms"}; @@ -199,26 +218,40 @@ struct RadialFlowDecorr { Configurable cfgCCDBurl{"cfgCCDBurl", "https://alice-ccdb.cern.ch", "ccdb url"}; Configurable cfgCCDBUserPath{"cfgCCDBUserPath", "/Users/s/somadutt", "Base CCDB path"}; - ConfigurableAxis cfgAxisCent{"cfgAxisCent", {0.0, 1.0, 3.0, 5.0, 10, 20, 30, 40, 50, 60, 70, 80, 100}, "centrality axis (percentile)"}; + ConfigurableAxis cfgAxisCent{"cfgAxisCent", {0.0, 1.0, 5.0, 10, 20, 40, 60, 80, 100}, "centrality axis (percentile)"}; const AxisSpec centAxis{cfgAxisCent, "Centrality (%)"}; - const AxisSpec centAxis1Per{101, -0.5, 100.5, - "Centrality (%)" - "Centrality (%)"}; + const AxisSpec centAxis1Per{100, 0.0, 100.0, "Centrality (%)"}; AxisSpec nChAxis{1, 0., 1., "Nch", "Nch"}; AxisSpec nChAxis2{1, 0., 1., "Nch", "Nch"}; - const AxisSpec vzAxis{5, -12.5, 12.5, - "Vz" - "Vz"}; + const AxisSpec vzAxis{5, -12.5, 12.5, "Vz"}; const AxisSpec chgAxis{3, -1.5, 1.5}; - ConfigurableAxis cfgpTAxis{"cfgpTAxis", {0.0, 0.2, 0.5, 1, 3, 5, 7.5, 10}, "pT axis for flattening"}; - const AxisSpec pTAxis{cfgpTAxis, "pT"}; - + const AxisSpec pTAxis{{0.0, 0.2, 0.5, 1, 3, 5, 7.5, 10}, "pT Axis"}; + const AxisSpec etaAxis{{-0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}, "Eta"}; + const AxisSpec phiAxis{KNbinsPhi, KPhiMin, TwoPI, "#phi"}; + const AxisSpec etaBinAxis{KNEta + 1, -0.5, KNEta + 0.5, "#eta bin Number"}; + const AxisSpec spBinAxis{KNsp + 1, -KBinOffset, static_cast(KNsp) + KBinOffset, "species index Number"}; + + const AxisSpec gapAxis{{-1.55, -1.45, -1.35, -1.25, -1.15, -1.05, -0.95, -0.85, + -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, + 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, + 0.85, 0.95, 1.05, 1.15, 1.25, 1.35, 1.45, 1.55}, + "Gap"}; + + const AxisSpec sumAxis{{-1.55, -1.45, -1.35, -1.25, -1.15, -1.05, -0.95, -0.85, + -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, + 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, + 0.85, 0.95, 1.05, 1.15, 1.25, 1.35, 1.45, 1.55}, + "Sum"}; + + Configurable cfgRunMCGetNSig{"cfgRunMCGetNSig", false, "Run MC pass to get mean of Nsig Plots"}; Configurable cfgRunGetEff{"cfgRunGetEff", false, "Run MC pass to build efficiency/fake maps"}; Configurable cfgRunGetMCFlat{"cfgRunGetMCFlat", false, "Run MC to Get Flattening Weights"}; Configurable cfgRunMCMean{"cfgRunMCMean", false, "Run MC mean(pT) & mean(Et)"}; Configurable cfgRunMCFluc{"cfgRunMCFluc", false, "Run MC fluctuations (C2, subevent)"}; + + Configurable cfgRunDataGetNSig{"cfgRunDataGetNSig", false, "Run MC pass to get mean of Nsig Plots"}; Configurable cfgRunGetDataFlat{"cfgRunGetDataFlat", false, "Run Data Get Flattening Weights"}; Configurable cfgRunDataMean{"cfgRunDataMean", false, "Run DATA mean(pT) & mean(Et)"}; Configurable cfgRunDataFluc{"cfgRunDataFluc", false, "Run DATA fluctuations (C2, subevent)"}; @@ -227,76 +260,367 @@ struct RadialFlowDecorr { Service pdg; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - std::array hEff{}; - std::array hFake{}; - std::array hFlatWeight{}; + struct InternalState { + std::array hEff{}; + std::array hFake{}; + std::array hFlatWeight{}; - TProfile3D* pmeanTruNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanRecoNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanRecoEffcorrNchEtabinPtbinStep2 = nullptr; + std::vector> mLimitsNchCent; + float mMinXNchCent = 0, mMaxXNchCent = 0; - TProfile3D* pmeanEtTruNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanEtRecoNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanEtRecoEffcorrNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanTruNchEtabinSpbinStep2 = nullptr; + TProfile3D* pmeanRecoNchEtabinSpbinStep2 = nullptr; + TProfile3D* pmeanRecoEffcorrNchEtabinSpbinStep2 = nullptr; - TProfile3D* pmeanMultTruNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanMultRecoNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanMultRecoEffcorrNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanMultTruNchEtabinSpbinStep2 = nullptr; + TProfile3D* pmeanMultRecoNchEtabinSpbinStep2 = nullptr; + TProfile3D* pmeanMultRecoEffcorrNchEtabinSpbinStep2 = nullptr; - TProfile3D* pmeanNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanEtNchEtabinPtbinStep2 = nullptr; - TProfile3D* pmeanMultNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanNchEtabinSpbinStep2 = nullptr; + TProfile3D* pmeanMultNchEtabinSpbinStep2 = nullptr; + + TProfile* pmeanFT0AmultpvStep2 = nullptr; + TProfile* pmeanFT0CmultpvStep2 = nullptr; + } state; + o2::ft0::Geometry ft0Det; - // Helper to calculate all three combined PID sigmas at once template - static std::tuple getAllCombinedNSigmas(const T& candidate) + void fillNSigmaBefCut(const T& track, float cent) { - return { - std::hypot(candidate.tpcNSigmaPr(), candidate.tofNSigmaPr()), // Proton - std::hypot(candidate.tpcNSigmaPi(), candidate.tofNSigmaPi()), // Pion - std::hypot(candidate.tpcNSigmaKa(), candidate.tofNSigmaKa()) // Kaon - }; + float pt = track.pt(); + auto sign = track.sign(); + + if (sign > 0) { + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PiPlus"), cent, pt, track.tpcNSigmaPi()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PiPlus"), cent, pt, track.tofNSigmaPi()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PiPlus"), cent, track.tofNSigmaPi(), track.tpcNSigmaPi()); + + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_KaPlus"), cent, pt, track.tpcNSigmaKa()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_KaPlus"), cent, pt, track.tofNSigmaKa()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_KaPlus"), cent, track.tofNSigmaKa(), track.tpcNSigmaKa()); + + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_Pr"), cent, pt, track.tpcNSigmaPr()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_Pr"), cent, pt, track.tofNSigmaPr()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_Pr"), cent, track.tofNSigmaPr(), track.tpcNSigmaPr()); + } else if (sign < 0) { + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PiMinus"), cent, pt, track.tpcNSigmaPi()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PiMinus"), cent, pt, track.tofNSigmaPi()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PiMinus"), cent, track.tofNSigmaPi(), track.tpcNSigmaPi()); + + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_KaMinus"), cent, pt, track.tpcNSigmaKa()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_KaMinus"), cent, pt, track.tofNSigmaKa()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_KaMinus"), cent, track.tofNSigmaKa(), track.tpcNSigmaKa()); + + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_AntiPr"), cent, pt, track.tpcNSigmaPr()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_AntiPr"), cent, pt, track.tofNSigmaPr()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_AntiPr"), cent, track.tofNSigmaPr(), track.tpcNSigmaPr()); + } + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PiAll"), cent, pt, track.tpcNSigmaPi()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PiAll"), cent, pt, track.tofNSigmaPi()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PiAll"), cent, track.tofNSigmaPi(), track.tpcNSigmaPi()); + + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_KaAll"), cent, pt, track.tpcNSigmaKa()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_KaAll"), cent, pt, track.tofNSigmaKa()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_KaAll"), cent, track.tofNSigmaKa(), track.tpcNSigmaKa()); + + histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PrAll"), cent, pt, track.tpcNSigmaPr()); + histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PrAll"), cent, pt, track.tofNSigmaPr()); + histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PrAll"), cent, track.tofNSigmaPr(), track.tpcNSigmaPr()); + } + + template + void fillNSigmaAftCut(const T& track, float cent, bool isSpecies[]) + { + float pt = track.pt(); + float tpcPi = track.tpcNSigmaPi(); + float tofPi = track.tofNSigmaPi(); + + float tpcKa = track.tpcNSigmaKa(); + float tofKa = track.tofNSigmaKa(); + + float tpcPr = track.tpcNSigmaPr(); + float tofPr = track.tofNSigmaPr(); + + if (isSpecies[kPiPlusIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PiPlus"), cent, pt, tpcPi); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PiPlus"), cent, pt, tofPi); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PiPlus"), cent, tofPi, tpcPi); + } + if (isSpecies[kPiMinusIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PiMinus"), cent, pt, tpcPi); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PiMinus"), cent, pt, tofPi); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PiMinus"), cent, tofPi, tpcPi); + } + if (isSpecies[kPiAllIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PiAll"), cent, pt, tpcPi); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PiAll"), cent, pt, tofPi); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PiAll"), cent, tofPi, tpcPi); + } + if (isSpecies[kKaPlusIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_KaPlus"), cent, pt, tpcKa); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_KaPlus"), cent, pt, tofKa); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_KaPlus"), cent, tofKa, tpcKa); + } + if (isSpecies[kKaMinusIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_KaMinus"), cent, pt, tpcKa); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_KaMinus"), cent, pt, tofKa); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_KaMinus"), cent, tofKa, tpcKa); + } + if (isSpecies[kKaAllIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_KaAll"), cent, pt, tpcKa); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_KaAll"), cent, pt, tofKa); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_KaAll"), cent, tofKa, tpcKa); + } + if (isSpecies[kPrIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_Pr"), cent, pt, tpcPr); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_Pr"), cent, pt, tofPr); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_Pr"), cent, tofPr, tpcPr); + } + if (isSpecies[kAntiPrIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_AntiPr"), cent, pt, tpcPr); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_AntiPr"), cent, pt, tofPr); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_AntiPr"), cent, tofPr, tpcPr); + } + if (isSpecies[kPrAllIdx]) { + histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PrAll"), cent, pt, tpcPr); + histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PrAll"), cent, pt, tofPr); + histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PrAll"), cent, tofPr, tpcPr); + } else { + return; + } + } + + // Returns: 0 = Unknown/Reject, 1 = Pion, 2 = Kaon, 3 = Proton + template + int identifyTrack(const T& candidate, int cent) + { + if (!candidate.hasTPC()) + return 0; + + float pt = candidate.pt(); + if (pt <= cfgCutPtLower || pt >= cfgCutPtUpperPID) + return 0; // Out of bounds + + if (!pidMeanSigmaMap) + return 0; + + int centBin = cent + 0.5; + auto charge = candidate.sign(); + int piIdx = (charge > 0) ? kPiPlusIdx : kPiMinusIdx; + int kaIdx = (charge > 0) ? kKaPlusIdx : kKaMinusIdx; + int prIdx = (charge > 0) ? kPrIdx : kAntiPrIdx; + + // TPC + float mPiTpc = pidMeanSigmaMap->meanTPC[piIdx][centBin]; + float sPiTpc = pidMeanSigmaMap->sigmaTPC[piIdx][centBin]; + + float mKaTpc = pidMeanSigmaMap->meanTPC[kaIdx][centBin]; + float sKaTpc = pidMeanSigmaMap->sigmaTPC[kaIdx][centBin]; + + float mPrTpc = pidMeanSigmaMap->meanTPC[prIdx][centBin]; + float sPrTpc = pidMeanSigmaMap->sigmaTPC[prIdx][centBin]; + + // TOF + float mPiTof = pidMeanSigmaMap->meanTOF[piIdx][centBin]; + float sPiTof = pidMeanSigmaMap->sigmaTOF[piIdx][centBin]; + + float mKaTof = pidMeanSigmaMap->meanTOF[kaIdx][centBin]; + float sKaTof = pidMeanSigmaMap->sigmaTOF[kaIdx][centBin]; + + float mPrTof = pidMeanSigmaMap->meanTOF[prIdx][centBin]; + float sPrTof = pidMeanSigmaMap->sigmaTOF[prIdx][centBin]; + + static int debugLogCounter = 0; + if (debugLogCounter < KConstTen) { + LOGF(info, "[PID DEBUG] CentBin: %d, Charge: %d", centBin, charge); + LOGF(info, " -> TPC USED | Pi (\u03bc=%.3f, \u03c3=%.3f) | Ka (\u03bc=%.3f, \u03c3=%.3f) | Pr (\u03bc=%.3f, \u03c3=%.3f)", + mPiTpc, sPiTpc, mKaTpc, sKaTpc, mPrTpc, sPrTpc); + + if (candidate.hasTOF()) { + LOGF(info, " -> TOF USED | Pi (\u03bc=%.3f, \u03c3=%.3f) | Ka (\u03bc=%.3f, \u03c3=%.3f) | Pr (\u03bc=%.3f, \u03c3=%.3f)", + mPiTof, sPiTof, mKaTof, sKaTof, mPrTof, sPrTof); + } else { + LOGF(info, " -> TOF USED | Track has no TOF signal."); + } + debugLogCounter++; + } + // Fetch Raw nSigma Values + float rawTpcPi = candidate.tpcNSigmaPi(); + float rawTpcKa = candidate.tpcNSigmaKa(); + float rawTpcPr = candidate.tpcNSigmaPr(); + + float rawTofPi = 0.f, rawTofKa = 0.f, rawTofPr = 0.f; + if (candidate.hasTOF()) { + rawTofPi = candidate.tofNSigmaPi(); + rawTofKa = candidate.tofNSigmaKa(); + rawTofPr = candidate.tofNSigmaPr(); + } + + // --- Low PT Regime --- + if (pt <= cfgCutPtUpperTPC) { + // Basic TPC passing check: |Raw - Mean| < (Cut * Sigma) + bool inTpcPi = std::abs(rawTpcPi - mPiTpc) < (cfgnSigmaCutTPC * sPiTpc); + bool inTpcKa = std::abs(rawTpcKa - mKaTpc) < (cfgnSigmaCutTPC * sKaTpc); + bool inTpcPr = std::abs(rawTpcPr - mPrTpc) < (cfgnSigmaCutTPC * sPrTpc); + + // Combined passing check (adds TOF if available) + bool passPi = inTpcPi && (!candidate.hasTOF() || std::abs(rawTofPi - mPiTof) < (cfgnSigmaCutTOF * sPiTof)); + bool passKa = inTpcKa && (!candidate.hasTOF() || std::abs(rawTofKa - mKaTof) < (cfgnSigmaCutTOF * sKaTof)); + bool passPr = inTpcPr && (!candidate.hasTOF() || std::abs(rawTofPr - mPrTof) < (cfgnSigmaCutTOF * sPrTof)); + + // Uniqueness check: Must pass target cut, and NOT fall into the TPC range of the others + if (passPi && !passKa && !passPr) + return 1; + if (passKa && !passPi && !passPr) + return 2; + if (passPr && !passPi && !passKa) + return 3; + + return 0; // Ambiguous or failed all cuts + } + + // --- High PT Regime--- + if (candidate.hasTOF() && pt > cfgCutPtUpperTPC) { + // Calculate 2D Normalized Distance (Elliptical distance normalized by sigma) + float dPi = std::hypot((rawTpcPi - mPiTpc) / sPiTpc, (rawTofPi - mPiTof) / sPiTof); + float dKa = std::hypot((rawTpcKa - mKaTpc) / sKaTpc, (rawTofKa - mKaTof) / sKaTof); + float dPr = std::hypot((rawTpcPr - mPrTpc) / sPrTpc, (rawTofPr - mPrTof) / sPrTof); + + // Count how many particles are within the ambiguity radius + int competitors = (dPi < cfgnSigmaOtherParticles) + + (dKa < cfgnSigmaOtherParticles) + + (dPr < cfgnSigmaOtherParticles); + + // If 1 or fewer are in the ambiguity region, pick the absolute best match + if (competitors <= 1) { + if (dPi <= dKa && dPi <= dPr && dPi < cfgnSigmaCutCombTPCTOF) + return 1; + if (dKa <= dPi && dKa <= dPr && dKa < cfgnSigmaCutCombTPCTOF) + return 2; + if (dPr <= dPi && dPr <= dKa && dPr < cfgnSigmaCutCombTPCTOF) + return 3; + } + } + return 0; // Unknown/Reject } template bool isEventSelected(const T& col) { + histos.fill(HIST("hEvtCount"), 0.5); + if (!col.sel8()) return false; + histos.fill(HIST("hEvtCount"), 1.5); + if (std::abs(col.posZ()) > cfgCutVertex) return false; - if (cfgEvSelkNoSameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) - return false; - if (cfgEvSelkNoITSROFrameBorder && !col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + histos.fill(HIST("hEvtCount"), 2.5); + + if (cfgEvSelNoSameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) return false; - if (cfgEvSelkNoTimeFrameBorder && !col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + histos.fill(HIST("hEvtCount"), 3.5); + + if (cfgUseGoodITSLayerAllCut && !col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return false; + histos.fill(HIST("hEvtCount"), 4.5); + if (cfgIsGoodZvtxFT0VsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) return false; + histos.fill(HIST("hEvtCount"), 5.5); + return true; + } + + bool isPassAddPileup(int multPV, int trksize, float cent) + { + auto checkLimits = [](float x, float y, const std::vector>& limits, float xM, float xMx) { + if (limits.empty()) + return true; + int bin = 1 + static_cast((x - xM) / (xMx - xM) * (limits.size() - 2)); + if (bin < 1 || bin >= static_cast(limits.size() - 1)) + return false; + return (y >= limits[bin].first && y <= limits[bin].second); + }; + if (cfgApplySigPupCut) { + if (!checkLimits(cent, trksize, state.mLimitsNchCent, state.mMinXNchCent, state.mMaxXNchCent)) + return false; + histos.fill(HIST("hEvtCount"), 6.5); + } + if (cfgApplyLinPupCut) { + if (trksize > (cfgLinPupParam0 + cfgLinPupParam1 * multPV)) + return false; + histos.fill(HIST("hEvtCount"), 7.5); + if (trksize < (cfgLinPupParam2 + cfgLinPupParam3 * multPV)) + return false; + histos.fill(HIST("hEvtCount"), 8.5); + } return true; } template bool isTrackSelected(const T& trk) { + histos.fill(HIST("hTrkCount"), 0.5); + if (trk.sign() == 0) return false; + histos.fill(HIST("hTrkCount"), 1.5); + if (!trk.has_collision()) return false; + histos.fill(HIST("hTrkCount"), 2.5); + if (!trk.isPVContributor()) return false; + histos.fill(HIST("hTrkCount"), 3.5); + if (!(trk.itsNCls() > cfgITScluster)) return false; + histos.fill(HIST("hTrkCount"), 4.5); + if (!(trk.tpcNClsFound() >= cfgTPCcluster)) return false; + histos.fill(HIST("hTrkCount"), 5.5); + if (!(trk.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) return false; + histos.fill(HIST("hTrkCount"), 6.5); if (trk.pt() < cfgCutPtLower || trk.pt() > cfgCutPtUpper || std::abs(trk.eta()) > cfgCutEta) return false; - if (std::abs(trk.dcaXY()) > cfgCutTracKDcaMaxXY || std::abs(trk.dcaZ()) > cfgCutTracKDcaMaxZ) + histos.fill(HIST("hTrkCount"), 7.5); + + if (!trk.isGlobalTrack()) return false; + histos.fill(HIST("hTrkCount"), 8.5); + + if (cfgPtDepDCAxy) { + // Evaluates: P0 + P1 / (pt^P2) + float maxDcaXY = cfgDcaXyP0 + cfgDcaXyP1 / std::pow(trk.pt(), cfgDcaXyP2); + if (std::abs(trk.dcaXY()) > maxDcaXY) { + return false; + } + histos.fill(HIST("hTrkCount"), 9.5); + } else { + if (std::abs(trk.dcaXY()) > cfgCutTracKDcaMaxXY) { + return false; + } + histos.fill(HIST("hTrkCount"), 9.5); + } + if (cfgPtDepDCAz) { + // Evaluates: P0 + P1 / (pt^P2) + float maxDcaZ = cfgDcaZP0 + cfgDcaZP1 / std::pow(trk.pt(), cfgDcaZP2); + if (std::abs(trk.dcaZ()) > maxDcaZ) { + return false; // Reject track if DCA is too large + } + histos.fill(HIST("hTrkCount"), 10.5); + } else { + if (std::abs(trk.dcaZ()) > cfgCutTracKDcaMaxZ) { + return false; + } + histos.fill(HIST("hTrkCount"), 10.5); + } return true; } @@ -315,155 +639,40 @@ struct RadialFlowDecorr { return true; } - template - bool selectionProton(const T& candidate) - { - if (!candidate.hasTPC()) - return false; - int flag = 0; - - if (candidate.pt() > cfgCutPtLower && candidate.pt() <= cfgCutPtUpperTPC) { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC) { - flag = 1; - } - if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < cfgnSigmaCutTOF) { - flag = 1; - } - } - if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < cfgCutPtUpperPID) { - auto [combNSigmaPr, combNSigmaPi, combNSigmaKa] = getAllCombinedNSigmas(candidate); - int flag2 = 0; - if (combNSigmaPr < cfgnSigmaOtherParticles) - flag2 += 1; - if (combNSigmaPi < cfgnSigmaOtherParticles) - flag2 += 1; - if (combNSigmaKa < cfgnSigmaOtherParticles) - flag2 += 1; - if (!(flag2 > 1) && !(combNSigmaPr > combNSigmaPi) && !(combNSigmaPr > combNSigmaKa)) { - if (combNSigmaPr < cfgnSigmaCutCombTPCTOF) { - flag = 1; - } - } - } - if (flag == 1) - return true; - else - return false; - } - - template - bool selectionPion(const T& candidate) - { - if (!candidate.hasTPC()) - return false; - int flag = 0; - - if (candidate.pt() > cfgCutPtLower && candidate.pt() <= cfgCutPtUpperTPC) { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < cfgnSigmaCutTPC) { - flag = 1; - } - if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPi()) < cfgnSigmaCutTOF) { - flag = 1; - } - } - if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < cfgCutPtUpperPID) { - auto [combNSigmaPr, combNSigmaPi, combNSigmaKa] = getAllCombinedNSigmas(candidate); - int flag2 = 0; - if (combNSigmaPr < cfgnSigmaOtherParticles) - flag2 += 1; - if (combNSigmaPi < cfgnSigmaOtherParticles) - flag2 += 1; - if (combNSigmaKa < cfgnSigmaOtherParticles) - flag2 += 1; - if (!(flag2 > 1) && !(combNSigmaPi > combNSigmaPr) && !(combNSigmaPi > combNSigmaKa)) { - if (combNSigmaPi < cfgnSigmaCutCombTPCTOF) { - flag = 1; - } - } - } - if (flag == 1) - return true; - else - return false; - } - - template - bool selectionKaon(const T& candidate) - { - if (!candidate.hasTPC()) - return false; - int flag = 0; - - if (candidate.pt() > cfgCutPtLower && candidate.pt() <= cfgCutPtUpperTPC) { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < cfgnSigmaCutTPC) { - flag = 1; - } - if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaKa()) < cfgnSigmaCutTOF) { - flag = 1; - } - } - if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < cfgCutPtUpperPID) { - auto [combNSigmaPr, combNSigmaPi, combNSigmaKa] = getAllCombinedNSigmas(candidate); - int flag2 = 0; - if (combNSigmaPr < cfgnSigmaOtherParticles) - flag2 += 1; - if (combNSigmaPi < cfgnSigmaOtherParticles) - flag2 += 1; - if (combNSigmaKa < cfgnSigmaOtherParticles) - flag2 += 1; - if (!(flag2 > 1) && !(combNSigmaKa > combNSigmaPi) && !(combNSigmaKa > combNSigmaPr)) { - if (combNSigmaKa < cfgnSigmaCutCombTPCTOF) { - flag = 1; - } - } - } - if (flag == 1) - return true; - else - return false; - } - float getCentrality(const auto& col) const { if (cfgCentralityChoice.value == kCentFT0C) return col.centFT0C(); - if (cfgCentralityChoice.value == kCentFT0A) - return col.centFT0A(); if (cfgCentralityChoice.value == kCentFT0M) return col.centFT0M(); + if (cfgCentralityChoice.value == kCentFDDM) + return col.centFDDM(); if (cfgCentralityChoice.value == kCentFV0A) return col.centFV0A(); return KinvalidCentrality; } - float getEfficiency(float mult, float pt, float eta, PID pidType, int effidx, bool cfgEff) const + float getEfficiency(float mult, float pt, float eta, PIDIdx pidType, int effidx, bool cfgEff) const { if (!cfgEff) { - if (effidx == 0) - return 1.0; - if (effidx == 1) - return 0.0; + return (effidx == 0) ? 1.0f : 0.0f; } - TH3F* h = nullptr; - if (effidx == 0) - h = hEff[pidType]; - if (effidx == 1) - h = hFake[pidType]; - - if (!h) - return -1; - const int ibx = h->GetXaxis()->FindBin(mult); - const int iby = h->GetYaxis()->FindBin(pt); - const int ibz = h->GetZaxis()->FindBin(eta); + TH3F* h = (effidx == 0) ? state.hEff[pidType] : state.hFake[pidType]; + if (!h) { + return (effidx == 0) ? 1.0f : 0.0f; // Safe defaults if map is missing + } + int ibx = h->GetXaxis()->FindBin(mult); + int iby = h->GetYaxis()->FindBin(pt); + int ibz = h->GetZaxis()->FindBin(eta); float val = h->GetBinContent(ibx, iby, ibz); return val; } - float getFlatteningWeight(float vz, float chg, float pt, float eta, float phi, PID pidType, bool cfgflat) const + float getFlatteningWeight(float vz, float chg, float pt, float eta, float phi, PIDIdx pidType, bool cfgflat) const { if (!cfgflat) return 1.0; - THnSparseF* h = hFlatWeight[pidType]; + THnSparseF* h = state.hFlatWeight[pidType]; if (!h) return 0.0; @@ -478,6 +687,45 @@ struct RadialFlowDecorr { return val; } + std::vector* offsetFT0 = nullptr; + uint64_t mLastTimestamp = 0; + double getEtaFT0(uint64_t globalChno, int i) + { + if (i > 1 || i < 0) { + LOGF(fatal, "kFIT Index %d out of range", i); + } + auto chPos = ft0Det.getChannelCenter(globalChno); + auto x = chPos.X() + (*offsetFT0)[i].getX(); + auto y = chPos.Y() + (*offsetFT0)[i].getY(); + auto z = chPos.Z() + (*offsetFT0)[i].getZ(); + // i == 0 is FT0A (A-side, positive Z) + // i == 1 is FT0C (C-side, negative Z) + if (i == 1) { + z = -std::abs(z); + } else if (i == 0) { + z = std::abs(z); + } + auto r = std::sqrt(x * x + y * y); + auto theta = std::atan2(r, z); + return -std::log(std::tan(0.5 * theta)); + } + + void loadAlignParam(uint64_t timestamp) + { + if (timestamp == mLastTimestamp && offsetFT0 != nullptr) { + return; + } + offsetFT0 = ccdb->getForTimeStamp>("FT0/Calib/Align", timestamp); + if (!offsetFT0) { + LOGF(fatal, "Failed to load valid FT0 alignment from CCDB!"); + return; + } + mLastTimestamp = timestamp; + LOGF(info, "Successfully loaded new alignment parameters for timestamp %llu", timestamp); + LOGF(info, "Offset for FT0A: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[0].getX(), (*offsetFT0)[0].getY(), (*offsetFT0)[0].getZ()); + LOGF(info, "Offset for FT0C: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[1].getX(), (*offsetFT0)[1].getY(), (*offsetFT0)[1].getZ()); + } + template std::pair calculateMeanAndC2FromSums(const double sumpmwk[KIntM][KIntK], const double sumwk[KIntK], float referenceMeanPt) const { @@ -517,12 +765,11 @@ struct RadialFlowDecorr { return {calculatedMeanPt, twopcorr}; } - using GeneralCollisions = soa::Join< - aod::Collisions, - aod::EvSels, - aod::Mults, - aod::CentFT0As, aod::CentFT0Cs, aod::CentFT0Ms, aod::CentFV0As, - aod::CentNGlobals>; + using GeneralCollisions = soa::Join; + Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZCut; using AodCollisionsSel = soa::Filtered; @@ -531,12 +778,11 @@ struct RadialFlowDecorr { aod::TracksExtra, aod::TrackSelection, aod::TracksDCA, - aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, - aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>; - Filter trackFilter = nabs(aod::track::eta) < cfgEtaCut && - aod::track::pt > cfgPtMin&& - aod::track::pt < cfgPtMax&& - nabs(aod::track::dcaXY) < cfgDCAXY&& nabs(aod::track::dcaZ) < cfgDCAZ; + aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, aod::pidTPCFullEl, + aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr, aod::pidTOFFullEl>; + Filter trackFilter = aod::track::pt > KPtMin&& + aod::track::pt < KPtMax&& + requireGlobalTrackInFilter(); using AodTracksSel = soa::Filtered; using TCs = soa::Join; using FilteredTCs = soa::Filtered; @@ -544,244 +790,240 @@ struct RadialFlowDecorr { using MyRun3MCCollisions = soa::Join< aod::Collisions, aod::EvSels, aod::Mults, aod::MultsExtra, - aod::CentFT0As, aod::CentFT0Cs, aod::CentFT0Ms, aod::CentFV0As, + aod::CentFT0Cs, aod::CentFT0Ms, aod::CentFDDMs, aod::CentFV0As, aod::CentNGlobals, aod::McCollisionLabels>; - using MyMCTracks = soa::Join< - aod::Tracks, aod::TrackSelection, aod::TracksExtra, aod::TracksDCA, - aod::McTrackLabels, - aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, - aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>; - - PresliceUnsorted partPerMcCollision = aod::mcparticle::mcCollisionId; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; - PresliceUnsorted trackPerMcParticle = aod::mctracklabel::mcParticleId; - Preslice perCollision = aod::track::collisionId; - Preslice trackPerCollision = aod::track::collisionId; void declareCommonQA() { - histos.add("hZvtx_after_sel", ";z_{vtx} (cm)", kTH1F, {{KNbinsZvtx, KZvtxMin, KZvtxMax}}); + histos.add("hVtxZ_after_sel", ";z_{vtx} (cm)", kTH1F, {{KNbinsZvtx, KZvtxMin, KZvtxMax}}); histos.add("hVtxZ", ";z_{vtx} (cm)", kTH1F, {{KNbinsZvtx, KZvtxMin, KZvtxMax}}); histos.add("hCentrality", ";centrality (%)", kTH1F, {{centAxis1Per}}); - histos.add("Hist2D_globalTracks_PVTracks", ";N_{global};N_{PV}", kTH2F, {{nChAxis2}, {nChAxis2}}); - histos.add("Hist2D_cent_nch", ";N_{PV};cent (%)", kTH2F, {{nChAxis2}, {centAxis1Per}}); - histos.add("hP", ";p (GeV/c)", kTH1F, {{KNbinsP, KPMin, KPMax}}); + histos.add("Hist2D_globalTracks_PVTracks", ";N_{global};N_{PV}", kTH2F, {{nChAxis}, {nChAxis}}); + histos.add("Hist2D_cent_nch", ";N_{PV};cent (%)", kTH2F, {{nChAxis}, {centAxis1Per}}); + + histos.add("Hist2D_globalTracks_cent", "cent (%);N_{global}", kTH2F, {{centAxis1Per}, {nChAxis}}); + histos.add("Hist2D_PVTracks_cent", "cent (%);N_{PV}", kTH2F, {{centAxis1Per}, {nChAxis}}); + + histos.add("hP", ";p (GeV/c)", kTH1F, {{KNbinsPt, KPMin, KPMax}}); histos.add("hPt", ";p_{T} (GeV/c)", kTH1F, {{KNbinsPt, KPtMin, KPtMax}}); - histos.add("hEta", ";#eta", kTH1F, {{KNbinsEta, KEtaMin, KEtaMax}}); + histos.add("hEta", ";#eta", kTH1F, {{KNbinsEtaFine, KEtaMin, KEtaMax}}); histos.add("hPhi", ";#phi", kTH1F, {{KNbinsPhi, KPhiMin, TwoPI}}); - histos.add("hEtaPhiReco", "hEtaPhiReco", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiReco_PID", "hEtaPhiReco_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hEvtCount", "Number of Event;; Count", kTH1F, {{9, 0, 9}}); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(1, "all Events"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(2, "after sel8"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(3, "after VertexZ Cut"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(4, "after kNoSameBunchPileup"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(5, "after kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(6, "after kIsGoodITSLayersAll"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(7, "after PVTracksCent Pileup Cut"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(8, "after Linear Pileup Cut (Up)"); + histos.get(HIST("hEvtCount"))->GetXaxis()->SetBinLabel(9, "after Linear Pileup Cut (Lw)"); + + histos.add("hTrkCount", "Number of Tracks;; Count", kTH1F, {{11, 0, 11}}); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(1, "all Tracks"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(2, "after sign!=0"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(3, "after has_collision"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(4, "after isPVContributor"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(5, "after itsNCls"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(6, "after tpcNClsFound"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(7, "after tpcNClsCrossedRows"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(8, "after pT,#eta selections"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(9, "after isGlobalTrack"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(10, "after dcaXY"); + histos.get(HIST("hTrkCount"))->GetXaxis()->SetBinLabel(11, "after dcaZ"); } + void declareMCCommonHists() { + for (const auto& suf : pidSuffix) { + histos.add("h3_AllPrimary" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoMatchedToPrimary" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_AllReco" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Secondary" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Fake" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoMatchedToPrimary_MisID" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + } - histos.add("ptResolution", ";p_{T}^{MC};p_{T}^{MC}-p_{T}^{reco}", kTH2F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsPtRes, -KPtResMax, KPtResMax}}); - histos.add("ptTruthReco", ";p_{T}^{MC};p_{T}^{reco}", kTH2F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsPtRes, cfgPtMin, cfgPtMax}}); - histos.add("etaResolution", ";#eta^{MC};#eta^{MC}-#eta^{reco}", kTH2F, {{KNbinsEtaRes, -KEtaFineMax, KEtaFineMax}, {KNbinsPtRes, -KEtaResMax, KEtaResMax}}); - histos.add("etaTruthReco", ";#eta^{MC};#eta^{reco}", kTH2F, {{KNbinsPtRes, -KEtaFineMax, KEtaFineMax}, {KNbinsPtRes, -KEtaFineMax, KEtaFineMax}}); + histos.add("ptResolution", ";p_{T}^{MC};(p_{T}^{reco}-p_{T}^{MC})/p_{T}^{MC}", kTH2F, {{KNbinsPtRes, KPtMin, KPtMax}, {100, -0.2, 0.2}}); + histos.add("etaResolution", ";#eta^{MC};#eta^{reco}-#eta^{MC}", kTH2F, {{KNbinsEtaRes, -KEtaFineMax, KEtaFineMax}, {100, -0.02, 0.02}}); + histos.add("etaTruthReco", ";#eta^{MC};#eta^{reco}", kTH2F, {{KNbinsEtaRes, -KEtaFineMax, KEtaFineMax}, {KNbinsEtaRes, -KEtaFineMax, KEtaFineMax}}); histos.add("TruthTracKVz", ";Vz^{MC};Vz^{Reco}", kTH2F, {{KNbinsVz, KVzMin, KVzMax}, {KNbinsVz, KVzMin, KVzMax}}); - histos.add("vzResolution", ";Vz^{MC};Vz^{MC}-Vz^{Reco}", kTH2F, {{KNbinsVz, KVzMin, KVzMax}, {KNbinsVz, -KVzResMax, KVzResMax}}); - - histos.add("h3_AllPrimary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoMatchedToPrimary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoUnMatchedToPrimary_Secondary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoUnMatchedToPrimary_Fake", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_AllReco", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - - histos.add("h3_AllPrimary_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoMatchedToPrimary_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoUnMatchedToPrimary_Secondary_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoUnMatchedToPrimary_Fake_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_AllReco_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - - histos.add("h_AllPrimary", ";p_{T}", kTH1F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); - histos.add("h_RecoMatchedToPrimary", ";p_{T}", kTH1F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); - histos.add("h_RecoUnMatchedToPrimary", ";p_{T}", kTH1F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); - histos.add("h_AllReco", ";p_{T}", kTH1F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); - histos.add("h_AllRecoEffCorr", ";p_{T}", kTH1F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); - - histos.add("hReco_ParticleWeight", ";cent;p_{T};#eta", kTH3F, {{centAxis1Per}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("hTruth_ParticleWeight", ";cent;p_{T};#eta", kTH3F, {{centAxis1Per}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - - histos.add("hDCAxy_Unmatched", ";DCA_{xy} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); - histos.add("hDCAz_Unmatched", ";DCA_{z} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); - histos.add("hDCAxy_NotPrimary", ";DCA_{xy} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); - histos.add("hDCAz_NotPrimary", ";DCA_{z} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); - histos.add("hDCAxy_RecoMatched", ";DCA_{xy} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); - histos.add("hDCAz_RecoMatched", ";DCA_{z} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); - histos.add("hDCAxy_Reco", ";DCA_{xy} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); - histos.add("hDCAz_Reco", ";DCA_{z} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); + histos.add("vzResolution", ";Vz^{MC};(Vz^{reco}-Vz^{MC})/Vz^{MC}", kTH2F, {{KNbinsVz, KVzMin, KVzMax}, {100, -0.1, 0.1}}); + } + + void declarenSigHists() + { + for (const auto& suf : pidSuffix) { + histos.add("h3DnsigmaTpcVsPtBefCut_Cent" + suf, "TPC nSigma vs pT Before Cut;cent [%]; p_{T} (GeV/c);n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); + histos.add("h3DnsigmaTofVsPtBefCut_Cent" + suf, "TOF nSigma vs pT Before Cut;cent [%]; p_{T} (GeV/c);n#sigma_{TOF}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); + histos.add("h3DnsigmaTpcVsTofBefCut_Cent" + suf, "TPC vs TOF nSigma Before Cut;cent [%]; n#sigma_{TOF};n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {200, -10.f, 10.f}, {200, -10.f, 10.f}}); + histos.add("h3DnsigmaTpcVsPtAftCut_Cent" + suf, "TPC nSigma vs pT After Cut;cent [%],; p_{T} (GeV/c);n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); + histos.add("h3DnsigmaTofVsPtAftCut_Cent" + suf, "TOF nSigma vs pT After Cut;cent [%],; p_{T} (GeV/c);n#sigma_{TOF}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); + histos.add("h3DnsigmaTpcVsTofAftCut_Cent" + suf, "TPC vs TOF nSigma After Cut;cent [%],; n#sigma_{TOF};n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {200, -10.f, 10.f}, {200, -10.f, 10.f}}); + } } void declareMCGetFlatHists() { - histos.add("hEtaPhiRecoWtd", "hEtaPhiRecoWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd", "hEtaPhiRecoEffWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoWtd_PID", "hEtaPhiRecoWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd_PID", "hEtaPhiRecoEffWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + for (const auto& suf : pidSuffix) { + histos.add("MCGen/hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + } } void declareMCMeanHists() { - histos.add("Eff_cent", ";cent;#epsilon", kTProfile, {centAxis1Per}); - histos.add("Fake_cent", ";cent;f_{fake}", kTProfile, {centAxis1Per}); - histos.add("wgt_cent", ";cent;w", kTProfile, {centAxis1Per}); - histos.add("Eff_Ntrk", ";N_{PV};#epsilon", kTProfile, {nChAxis2}); - histos.add("Fake_Ntrk", ";N_{PV};f_{fake}", kTProfile, {nChAxis2}); - histos.add("wgt_Ntrk", ";N_{PV};w", kTProfile, {nChAxis2}); - histos.add("Eff_pT", ";p_{T};#epsilon", kTProfile, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); - histos.add("Fake_pT", ";p_{T};f_{fake}", kTProfile, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); - histos.add("wgt_pT", ";p_{T};w", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); - histos.add("Eff_eta", ";#eta;#epsilon", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("Fake_eta", ";#eta;f_{fake}", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("wgt_eta", ";#eta;w", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("hEtaPhiRecoWtd", "hEtaPhiRecoWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd", "hEtaPhiRecoEffWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoWtd_PID", "hEtaPhiRecoWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd_PID", "hEtaPhiRecoEffWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - - // MC mean profiles (pT & Et) for various selections - histos.add("MCGen/Prof_cent_Nchrec", ";cent;#LT N_{PV}#GT", kTProfile, {centAxis1Per}); - - histos.add("MCGen/Prof_Cent_MeanpT", ";cent;#LT p_{T}#GT", kTProfile, {centAxis1Per}); - histos.add("MCGen/Prof_Mult_MeanpT", ";N_{PV};#LT p_{T}#GT", kTProfile, {nChAxis}); - - histos.add("pmeanTruNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanRecoNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanRecoEffcorrNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - histos.add("MCGen/Prof_Cent_MeanEt", ";cent;#LT E_{T}#GT", kTProfile, {centAxis1Per}); - histos.add("MCGen/Prof_Mult_MeanEt", ";N_{PV};#LT E_{T}#GT", kTProfile, {nChAxis}); - - histos.add("pmeanEtTruNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanEtRecoNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanEtRecoEffcorrNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - histos.add("pmeanMultTruNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanMultRecoNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanMultRecoEffcorrNchEtabinPtbin", ";N_{PV};#eta; p_{T}", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("Eff_cent", ";cent", kTProfile, {centAxis1Per}); + histos.add("Eff_Ntrk", ";N_{PV}", kTProfile, {nChAxis2}); + histos.add("Eff_pT", ";p_{T}", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); + histos.add("Eff_eta", ";#eta", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + + histos.add("Fake_cent", ";cent", kTProfile, {centAxis1Per}); + histos.add("Fake_Ntrk", ";N_{PV}", kTProfile, {nChAxis2}); + histos.add("Fake_pT", ";p_{T}", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); + histos.add("Fake_eta", ";#eta", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + + histos.add("wgt_cent", ";cent", kTProfile, {centAxis1Per}); + histos.add("wgt_Ntrk", ";N_{PV}", kTProfile, {nChAxis2}); + histos.add("wgt_pT", ";p_{T}", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); + histos.add("wgt_eta", ";#eta", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + + histos.add("pmeanFT0Amultpv", ";N_{PV};Ampl", kTProfile, {nChAxis}); + histos.add("pmeanFT0Cmultpv", ";N_{PV};Ampl", kTProfile, {nChAxis}); + histos.add("pmeanFT0A_cent", ";cent;Ampl", kTProfile, {centAxis1Per}); + histos.add("pmeanFT0C_cent", ";cent;Ampl", kTProfile, {centAxis1Per}); + histos.add("pmean_cent_id_eta_FT0", ";cent;id;#eta", kTProfile3D, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); + histos.add("h3_cent_id_eta_FT0", ";cent;id;#eta", kTH3F, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); + + histos.add("MCGen/Prof_Cent_Nsp_Nchrec", ";cent;isp", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); + histos.add("MCGen/Prof_Mult_Nsp_Nchrec", ";mult;isp", kTProfile2D, {{nChAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_Cent_Nsp_MeanpT", ";cent;isp", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); + histos.add("MCGen/Prof_Mult_Nsp_MeanpT", ";mult;isp", kTProfile2D, {{nChAxis}, {spBinAxis}}); + + histos.add("pmeanTru_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("pmeanReco_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("pmeanRecoEffcorr_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + + histos.add("pmeanMultTru_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("pmeanMultReco_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("pmeanMultRecoEffcorr_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + + for (const auto& suf : pidSuffix) { + histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + + histos.add("Prof2D_MeanpTSub_Tru" + suf, ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); + histos.add("Prof2D_MeanpTSub_Reco" + suf, ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); + histos.add("Prof2D_MeanpTSub_RecoEffCorr" + suf, ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); + } } void declareMCFlucHists() { - // Full Event Calc - histos.add("MCGen/Prof_Cent_MeanpT_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_Cent_MeanEt_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_Mult_MeanpT_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_Mult_MeanEt_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - histos.add("MCGen/Prof_Cent_C2_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_Cent_C2Et_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_C2_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_C2Et_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - // Sub Event Calc - histos.add("MCGen/Prof_C2Sub_Cent_etabin_ptbin", ";Centrality;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_C2EtSub_Cent_etabin_ptbin", ";Centrality;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_C2Sub_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_C2EtSub_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - histos.add("MCGen/Prof_Cov_Cent_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("MCGen/Prof_Cov_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - // Sub Event 2D Calc - histos.add("MCGen/Prof_ipt0_C2Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("MCGen/Prof_ipt1_C2Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("MCGen/Prof_ipt2_C2Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("MCGen/Prof_ipt0_C2EtSub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("MCGen/Prof_ipt1_C2EtSub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("MCGen/Prof_ipt2_C2EtSub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - - histos.add("MCGen/Prof_ipt0_Cov2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("MCGen/Prof_ipt1_Cov2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("MCGen/Prof_ipt2_Cov2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - - histos.add("MCGen/Prof_cent_Nchrec", ";cent;#LT N_{PV}#GT", kTProfile, {centAxis1Per}); - histos.add("MCGen/Prof_Cent_MeanpT", ";cent;#LT p_{T}#GT", kTProfile, {centAxis1Per}); - histos.add("MCGen/Prof_Cent_MeanEt", ";cent;#LT E_{T}#GT", kTProfile, {centAxis1Per}); - - histos.add("MCGen/Prof_Mult_MeanpT", ";N_{PV};#LT p_{T}#GT", kTProfile, {nChAxis}); - histos.add("MCGen/Prof_Mult_MeanEt", ";N_{PV};#LT E_{T}#GT", kTProfile, {nChAxis}); - - histos.add("hEtaPhiRecoWtd", "hEtaPhiRecoWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd", "hEtaPhiRecoEffWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoWtd_PID", "hEtaPhiRecoWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd_PID", "hEtaPhiRecoEffWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("MCGen/Prof_Cent_NEta_Nsp_Nchrec", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_Mult_NEta_Nsp_Nchrec", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_Cent_NEta_Nsp_MeanpT", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_Mult_NEta_Nsp_MeanpT", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + + histos.add("MCGen/Prof_MeanpT_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_C2_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_C2Sub_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_Cov_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_CovFT0A_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_CovFT0C_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); + + histos.add("MCGen/Prof_MeanpT_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_C2_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_C2Sub_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_Cov_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_CovFT0A_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + histos.add("MCGen/Prof_CovFT0C_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); + + for (const auto& suf : pidSuffix) { + histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + + histos.add(Form("MCGen/Prof_C2Sub2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add(Form("MCGen/Prof_GapSum2D%s", suf.c_str()), ";cent;gap;sum", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + histos.add(Form("MCGen/Prof_Cov2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add(Form("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add(Form("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + } } void declareDataGetFlatHists() { - histos.add("hEtaPhiRecoWtd", "hEtaPhiRecoWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd", "hEtaPhiRecoEffWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoWtd_PID", "hEtaPhiRecoWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd_PID", "hEtaPhiRecoEffWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - - histos.add("hnTrkPVZDC", ";ZDC_{A+C};N_{PV}", kTH2F, {{nChAxis2}, {200, 0, 3000}}); - histos.add("hNchZDC", ";ZDC_{A+C};N_{trk}", kTH2F, {{nChAxis2}, {200, 0, 30000}}); - - histos.add("hCentnTrk", ";Centrality (%);N_{trk}", kTH2F, {{centAxis1Per}, {nChAxis2}}); - histos.add("hCentnTrkPV", ";Centrality (%),N_{trk, PV}", kTH2F, {{centAxis1Per}, {nChAxis2}}); + for (const auto& suf : pidSuffix) { + histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + } + histos.add("hnTrkPVZDC", ";N_{PV};ZDC_{A+C}", kTH2F, {{nChAxis2}, {200, 0, 3000}}); + histos.add("hNchZDC", ";N_{trk};ZDC_{A+C}", kTH2F, {{nChAxis2}, {200, 0, 30000}}); } void declareDataMeanHists() { - histos.add("hEtaPhiRecoWtd", "hEtaPhiRecoWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd", "hEtaPhiRecoEffWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoWtd_PID", "hEtaPhiRecoWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd_PID", "hEtaPhiRecoEffWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - - histos.add("Prof_cent_Nchrec", ";cent;#LT N_{PV}#GT", kTProfile, {centAxis1Per}); - histos.add("Prof_Cent_MeanpT", ";cent;#LT p_{T}#GT", kTProfile, {centAxis1Per}); - histos.add("Prof_Cent_MeanEt", ";cent;#LT E_{T}#GT", kTProfile, {centAxis1Per}); - - histos.add("pmean_nch_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanEt_nch_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanMult_nch_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - histos.add("pmean_cent_etabin_ptbin", ";Centrality (%) ;#eta-bin;p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanEt_cent_etabin_ptbin", ";Centrality (%) ;#eta-bin;p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("pmeanMult_cent_etabin_ptbin", ";Centrality (%) ;#eta-bin;p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanFT0Amultpv", "N_{PV}; AmplitudeA", kTProfile, {nChAxis}); + histos.add("pmeanFT0A_cent", "cent; AmplitudeA", kTProfile, {centAxis1Per}); + histos.add("pmeanFT0Cmultpv", "N_{PV}; AmplitudeA", kTProfile, {nChAxis}); + histos.add("pmeanFT0C_cent", "cent; AmplitudeA", kTProfile, {centAxis1Per}); + + histos.add("pmean_cent_id_eta_FT0", ";cent;channel id; #eta;amplitude", kTProfile3D, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); + histos.add("h3_cent_id_eta_FT0", ";cent;channel id; #eta", kTH3F, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); + + histos.add("Prof_Cent_Nsp_Nchrec", ";cent;Species;#LT N_{PV}#GT", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); + histos.add("Prof_Mult_Nsp_Nchrec", ";N_{PV};Species;#LT N_{PV}#GT", kTProfile2D, {{nChAxis}, {spBinAxis}}); + histos.add("Prof_Cent_Nsp_MeanpT", ";cent;Species;#LT p_{T}#GT", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); + histos.add("Prof_Mult_Nsp_MeanpT", ";N_{PV};Species;#LT p_{T}#GT", kTProfile2D, {{nChAxis}, {spBinAxis}}); + + histos.add("pmean_nch_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("pmeanMult_nch_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("pmean_cent_etabin_spbin", ";Centrality (%) ;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("pmeanMult_cent_etabin_spbin", ";Centrality (%) ;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + + for (const auto& suf : pidSuffix) { + histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + + histos.add("Prof2D_MeanpTSub" + suf, ";cent;#eta_{A} bin;#eta_{C} bin", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {{etaBinAxis}}}); + } } void declareDataFlucHists() { - histos.add("hEtaPhiRecoWtd", "hEtaPhiRecoWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd", "hEtaPhiRecoEffWtd", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoWtd_PID", "hEtaPhiRecoWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - histos.add("hEtaPhiRecoEffWtd_PID", "hEtaPhiRecoEffWtd_PID", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); - - // Full Event Calc - histos.add("Prof_Cent_MeanpT_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_Cent_MeanEt_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_Mult_MeanpT_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_Mult_MeanEt_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - histos.add("Prof_Cent_C2_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_Cent_C2Et_etabin_ptbin", ";cent;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_C2_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_C2Et_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - // Sub Event Calc - histos.add("Prof_C2Sub_Cent_etabin_ptbin", ";Centrality;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_C2EtSub_Cent_etabin_ptbin", ";Centrality;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_C2Sub_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_C2EtSub_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_Cov_Cent_etabin_ptbin", ";Centrality;#eta-bin; p_{T}-bin", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - histos.add("Prof_Cov_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis2}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); - - // Sub Event 2D Calc - histos.add("Prof_ipt0_C2Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("Prof_ipt1_C2Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("Prof_ipt2_C2Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("Prof_ipt0_C2EtSub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("Prof_ipt1_C2EtSub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("Prof_ipt2_C2EtSub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - - histos.add("Prof_ipt0_Cov2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("Prof_ipt1_Cov2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); - histos.add("Prof_ipt2_Cov2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}}); + histos.add("Prof_MeanpT_Cent_etabin_spbin", ";cent;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_MeanpT_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_C2_Cent_etabin_spbin", ";cent;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_C2_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + + histos.add("Prof_C2Sub_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_C2Sub_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_Cov_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_Cov_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + + histos.add("Prof_CovFT0A_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_CovFT0A_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_CovFT0C_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("Prof_CovFT0C_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); + + for (const auto& suf : pidSuffix) { + histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("Prof_C2Sub2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_GapSum2D" + suf, ";cent;#Delta#eta (Gap);#Sigma#eta/2 (Sum)", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + histos.add("Prof_Cov2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A} bin;#eta_{C} bin", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_CovFT0A2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A};#eta_{B}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_CovFT0C2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A};#eta_{B}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + } } THnSparseF* buildWeightMapFromRaw(THnSparseF* hRaw, const char* mapName) @@ -795,7 +1037,7 @@ struct RadialFlowDecorr { hWMap->Reset(); auto axV = hRaw->GetAxis(0); // Vz auto axChg = hRaw->GetAxis(1); // Charge - auto axPt = hRaw->GetAxis(2); // Charge + auto axPt = hRaw->GetAxis(2); // Pt auto axE = hRaw->GetAxis(3); // Eta auto axP = hRaw->GetAxis(4); // Phi @@ -853,12 +1095,15 @@ struct RadialFlowDecorr { void init(InitContext&) { - if (cfgSys == 1) { - nChAxis = {cfgNchPbMax / 5, KBinOffset, cfgNchPbMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; - nChAxis2 = {cfgNchPbMax / 100, KBinOffset, cfgNchPbMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; + if (cfgSys == kPbPb) { + nChAxis = {cfgNchPbMax / 4, KBinOffset, cfgNchPbMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; + nChAxis2 = {cfgNchPbMax / 20, KBinOffset, cfgNchPbMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; + } else if (cfgSys == kNeNe || cfgSys == kOO) { + nChAxis = {cfgNchOMax / 2, KBinOffset, cfgNchOMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; + nChAxis2 = {cfgNchOMax / 5, KBinOffset, cfgNchOMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; } else { - nChAxis = {cfgNchOMax / 10, KBinOffset, cfgNchOMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; - nChAxis2 = {cfgNchOMax / 30, KBinOffset, cfgNchOMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; + nChAxis = {cfgNchOMax / 2, KBinOffset, cfgNchOMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; + nChAxis2 = {cfgNchOMax / 5, KBinOffset, cfgNchOMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; } ccdb->setURL(cfgCCDBurl.value); @@ -867,48 +1112,48 @@ struct RadialFlowDecorr { int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); ccdb->setCreatedNotAfter(now); + loadAlignParam(now); + ft0Det.calculateChannelCenter(); + std::string sysDir = ""; switch (cfgSys) { case kPbPb: sysDir = "PbPbTest"; break; + case kNeNe: + sysDir = "NeNeTest"; + break; case kOO: sysDir = "OOTest"; break; - case kpPb: - sysDir = "pPbTest"; - break; case kpp: sysDir = "ppTest"; break; default: LOGF(fatal, "Invalid cfgSys value: %d", cfgSys.value); } - + std::string pathNsig = cfgCCDBUserPath.value + "/" + sysDir + "/Job0_nSigMaps"; std::string pathEff = cfgCCDBUserPath.value + "/" + sysDir + "/Job1_EffMaps"; std::string pathMCFlat = cfgCCDBUserPath.value + "/" + sysDir + "/Job1_MCFlatMaps"; std::string pathMCMean = cfgCCDBUserPath.value + "/" + sysDir + "/Job2_MCMean"; + + std::string pathDataNsig = cfgCCDBUserPath.value + "/" + sysDir + "/Job0_DatanSigMaps"; std::string pathDataFlat = cfgCCDBUserPath.value + "/" + sysDir + "/Job1_DataFlatMaps"; std::string pathDataMean = cfgCCDBUserPath.value + "/" + sysDir + "/Job2_DataMean"; declareCommonQA(); - std::string userCcdbPath; - if (cfgSys == kPbPb) { - userCcdbPath = "/Users/s/somadutt/PbPbTest/"; - } - if (cfgSys == kOO) { - userCcdbPath = "/Users/s/somadutt/OOTest/"; - } - if (cfgSys == kpPb) { - userCcdbPath = "/Users/s/somadutt/pPbTest/"; - } - if (cfgSys == kpp) { - userCcdbPath = "/Users/s/somadutt/ppTest/"; + if (cfgRunMCGetNSig || cfgRunGetEff || cfgRunDataGetNSig || cfgRunGetDataFlat) { + declarenSigHists(); } if (cfgRunMCMean || cfgRunMCFluc || cfgRunGetEff) { declareMCCommonHists(); } + if (cfgRunGetMCFlat) { + declareMCGetFlatHists(); + histos.addClone("MCGen/", "MCReco/"); + histos.addClone("MCGen/", "MCRecoEffCorr/"); + } if (cfgRunMCMean) { declareMCMeanHists(); histos.addClone("MCGen/", "MCReco/"); @@ -919,11 +1164,11 @@ struct RadialFlowDecorr { histos.addClone("MCGen/", "MCReco/"); histos.addClone("MCGen/", "MCRecoEffCorr/"); } - if (cfgRunGetDataFlat) { + if (cfgRunDataGetNSig) { declareDataGetFlatHists(); } - if (cfgRunGetMCFlat) { - declareMCGetFlatHists(); + if (cfgRunGetDataFlat) { + declareDataGetFlatHists(); } if (cfgRunDataMean) { declareDataMeanHists(); @@ -932,101 +1177,192 @@ struct RadialFlowDecorr { declareDataFlucHists(); } - if (!cfgRunGetEff && (cfgEff)) { + if (!cfgRunGetEff && !cfgRunMCGetNSig && (cfgEff)) { TList* lst = ccdb->getForTimeStamp(pathEff, now); if (!lst) { LOGF(fatal, "Efficiency maps required but CCDB list is null at %s!", pathEff.c_str()); } - LOGF(info, "Loading Eff/Fake maps from TList..."); + LOGF(info, "Loading Eff/Fake maps from TList for all species..."); - auto loadEffFakeForPID = [&](PID pidType) { + auto loadEffFakeForPID = [&](PIDIdx pidType) { std::string suffix = pidSuffix[pidType]; std::string hEffNumName = "h3_RecoMatchedToPrimary" + suffix; std::string hEffDenName = "h3_AllPrimary" + suffix; std::string hFakeNumSecName = "h3_RecoUnMatchedToPrimary_Secondary" + suffix; std::string hFakeNumFakName = "h3_RecoUnMatchedToPrimary_Fake" + suffix; + std::string hFakeNumFakName2 = "h3_RecoMatchedToPrimary_MisID" + suffix; std::string hFakeDenName = "h3_AllReco" + suffix; auto* hNum = reinterpret_cast(lst->FindObject(hEffNumName.c_str())); auto* hDen = reinterpret_cast(lst->FindObject(hEffDenName.c_str())); if (hNum && hDen) { - hEff[pidType] = reinterpret_cast(hNum->Clone(Form("hEff%s", suffix.c_str()))); - hEff[pidType]->SetDirectory(nullptr); - hEff[pidType]->Divide(hDen); + state.hEff[pidType] = reinterpret_cast(hNum->Clone(Form("hEff%s", suffix.c_str()))); + state.hEff[pidType]->SetDirectory(nullptr); + state.hEff[pidType]->Divide(hDen); } else { - LOGF(error, "Missing CCDB objects for efficiency. Checked in list: %s, %s", hEffNumName.c_str(), hEffDenName.c_str()); + LOGF(error, "Missing CCDB objects for efficiency. Checked: %s, %s", hEffNumName.c_str(), hEffDenName.c_str()); } auto* hNumS = reinterpret_cast(lst->FindObject(hFakeNumSecName.c_str())); auto* hNumF = reinterpret_cast(lst->FindObject(hFakeNumFakName.c_str())); + auto* hNumF2 = reinterpret_cast(lst->FindObject(hFakeNumFakName2.c_str())); auto* hDenF = reinterpret_cast(lst->FindObject(hFakeDenName.c_str())); if (hNumS && hNumF && hDenF) { - hFake[pidType] = reinterpret_cast(hNumS->Clone(Form("hFake%s", suffix.c_str()))); - hFake[pidType]->Add(hNumF); - hFake[pidType]->SetDirectory(nullptr); - hFake[pidType]->Divide(hDenF); + state.hFake[pidType] = reinterpret_cast(hNumS->Clone(Form("hFake%s", suffix.c_str()))); + state.hFake[pidType]->Add(hNumF); + if (pidType != kInclusiveIdx && hNumF2) { + state.hFake[pidType]->Add(hNumF2); + } + state.hFake[pidType]->SetDirectory(nullptr); + state.hFake[pidType]->Divide(hDenF); } else { LOGF(error, "Missing CCDB object(s) for fakes for %s in list.", suffix.c_str()); } }; - loadEffFakeForPID(kInclusive); - loadEffFakeForPID(kCombinedPID); + for (int i = 0; i < KNsp; ++i) { + loadEffFakeForPID(static_cast(i)); + } + } + + bool requiresMCMap = (cfgRunGetEff || cfgRunGetMCFlat || cfgRunMCMean || cfgRunMCFluc); + bool requiresDataMap = (cfgRunGetDataFlat || cfgRunDataMean || cfgRunDataFluc); + + if (requiresMCMap || requiresDataMap) { + std::string currentPath = requiresMCMap ? pathNsig : pathDataNsig; + TList* pidList = ccdb->getForTimeStamp(currentPath, now); + + if (!pidList) { + LOGF(warn, "nSigma maps required but CCDB list is null at %s! Using raw values.", currentPath.c_str()); + } else { + if (!pidMeanSigmaMap) { + pidMeanSigmaMap = new PIDMeanSigmaMap(); + } + LOGF(info, "Performing 2D Gaussian fits on PID maps from CCDB..."); + auto loadPIDMeans = [&](PIDIdx pidType) { + std::string suffix = pidSuffix[pidType]; + std::string hName = "h3DnsigmaTpcVsTofBefCut_Cent" + suffix; + auto* h3 = reinterpret_cast(pidList->FindObject(hName.c_str())); + if (!h3) { + LOGF(warn, " [!] PID Hist %s not found in CCDB list.", hName.c_str()); + return; + } + int nCentBins = std::min(h3->GetXaxis()->GetNbins(), PIDMeanSigmaMap::MaxCentBins - 1); + LOGF(info, " -> Species: %s (Bins: %d)", hName.c_str(), nCentBins); + for (int iCent = 1; iCent <= nCentBins; ++iCent) { + h3->GetXaxis()->SetRange(iCent, iCent); + // Projecting: Z(TPC) vs Y(TOF). Result: X_axis=TOF, Y_axis=TPC + std::unique_ptr h2(reinterpret_cast(h3->Project3D("zy"))); + if (h2) { + int binX, binY, binZ; + h2->GetMaximumBin(binX, binY, binZ); + double guessMeanTOF = h2->GetXaxis()->GetBinCenter(binX); + double guessMeanTPC = h2->GetYaxis()->GetBinCenter(binY); + TF2 f2("f2", "[0]*TMath::Gaus(x,[1],[2])*TMath::Gaus(y,[3],[4])", -3, 3, -3, 3); + f2.SetParameters(h2->GetMaximum(), guessMeanTOF, 1.0, guessMeanTPC, 1.0); + h2->Fit(&f2, "QRN"); // Q=Quiet, R=Range, N=NoDraw + pidMeanSigmaMap->meanTOF[pidType][iCent - 1] = f2.GetParameter(1); + pidMeanSigmaMap->meanTPC[pidType][iCent - 1] = f2.GetParameter(3); + pidMeanSigmaMap->sigmaTOF[pidType][iCent - 1] = std::abs(f2.GetParameter(2)); + pidMeanSigmaMap->sigmaTPC[pidType][iCent - 1] = std::abs(f2.GetParameter(4)); + if (iCent % KConstTen == 0) { + LOGF(info, " Derived: For Species: %s (Bins: %d), Mean TOF = %.3f, Mean TPC = %.3f, Sigma TOF = %.3f, Sigma TPC = %.3f", hName.c_str(), iCent - 1, f2.GetParameter(1), f2.GetParameter(3), f2.GetParameter(2), f2.GetParameter(4)); + } + } + } + }; + for (int i = 1; i < KNsp; ++i) { + loadPIDMeans(static_cast(i)); + } + + auto loadLimits = [&](const char* name, std::vector>& limits, float& xMin, float& xMax) { + auto* h2 = reinterpret_cast(pidList->FindObject(name)); + if (!h2) + return; + + std::unique_ptr prof(h2->ProfileX("ptmp", 1, -1, "S")); + + int nBins = prof->GetNbinsX(); + xMin = prof->GetXaxis()->GetXmin(); + xMax = prof->GetXaxis()->GetXmax(); + + limits.assign(nBins + 2, {-99999.f, 999999.f}); + + for (int i = 1; i <= nBins; ++i) { + float mean = prof->GetBinContent(i); + float rms = prof->GetBinError(i); + + limits[i] = {mean - cfgPupnSig * rms, mean + cfgPupnSig * rms}; + } + }; + loadLimits("Hist2D_globalTracks_cent", state.mLimitsNchCent, state.mMinXNchCent, state.mMaxXNchCent); + } } if (!cfgRunGetEff && (cfgFlat)) { - // --- 1. Load Data Flattening Maps (if DataMean or DataFluc) --- if (cfgRunDataMean || cfgRunDataFluc) { - LOGF(info, "Data Run: Loading flattening maps from CCDB path: %s", pathDataFlat.c_str()); - + LOGF(info, "Data Run: Loading flattening maps from %s", pathDataFlat.c_str()); TList* lstDataFlat = ccdb->getForTimeStamp(pathDataFlat, now); if (lstDataFlat) { - auto* hRawIncl = reinterpret_cast(lstDataFlat->FindObject("hEtaPhiRecoEffWtd")); - if (hRawIncl) { - hFlatWeight[kInclusive] = buildWeightMapFromRaw(hRawIncl, "hFlatWeight"); - } else { - LOGF(error, "Data flattening 'hEtaPhiRecoEffWtd' not found in list from %s", pathDataFlat.c_str()); - } + for (int i = 0; i < KNsp; ++i) { + std::string suffix = pidSuffix[i]; + std::string hName; + + if (cfgEff && cfgFlat) { + hName = "hEtaPhiRecoWtd" + suffix; + } else if (cfgEff) { + hName = "hEtaPhiRecoEffWtd" + suffix; + } else { + hName = "hEtaPhiReco" + suffix; + } + auto* hRaw = reinterpret_cast(lstDataFlat->FindObject(hName.c_str())); - auto* hRawPID = reinterpret_cast(lstDataFlat->FindObject("hEtaPhiRecoEffWtd_PID")); - if (hRawPID) { - hFlatWeight[kCombinedPID] = buildWeightMapFromRaw(hRawPID, "hFlatWeight_PID"); - } else { - LOGF(error, "Data flattening 'hEtaPhiRecoEffWtd_PID' not found in list from %s", pathDataFlat.c_str()); + if (hRaw) { + state.hFlatWeight[i] = buildWeightMapFromRaw(hRaw, Form("hFlatWeight%s", suffix.c_str())); + } else { + LOGF(error, "Data flattening map '%s' not found.", hName.c_str()); + } } } else { - LOGF(error, "Could not retrieve TList for Data Flattening from: %s", pathDataFlat.c_str()); + LOGF(error, "Could not retrieve Data Flattening TList from: %s", pathDataFlat.c_str()); } } - // --- 2. Load MC Flattening Maps (if MCMean or MCFluc) --- if (cfgRunMCMean || cfgRunMCFluc) { - LOGF(info, "MC Run: Loading flattening maps from MC Flat list (%s)...", pathMCFlat.c_str()); - + LOGF(info, "MC Run: Loading flattening maps from %s", pathMCFlat.c_str()); TList* lstMCFlat = ccdb->getForTimeStamp(pathMCFlat, now); + if (lstMCFlat) { - auto loadFlatForPID = [&](PID pidType) { + auto loadFlatForPID = [&](PIDIdx pidType) { std::string suffix = pidSuffix[pidType]; - std::string hFlatSrcName = "hEtaPhiRecoEffWtd" + suffix; + std::string hFlatSrcName; + if (cfgEff && cfgFlat) { + hFlatSrcName = "MCReco/hEtaPhiRecoWtd" + suffix; + } else if (cfgEff) { + hFlatSrcName = "MCReco/hEtaPhiRecoEffWtd" + suffix; + } else { + hFlatSrcName = "MCReco/hEtaPhiReco" + suffix; + } auto* hRaw = reinterpret_cast(lstMCFlat->FindObject(hFlatSrcName.c_str())); if (hRaw) { - hFlatWeight[pidType] = buildWeightMapFromRaw(hRaw, Form("hFlatWeight%s", suffix.c_str())); + state.hFlatWeight[pidType] = buildWeightMapFromRaw(hRaw, Form("hFlatWeight%s", suffix.c_str())); } else { - LOGF(warning, "MC flattening source '%s' not found in list; skipping this PID.", hFlatSrcName.c_str()); + LOGF(warning, "MC flattening source '%s' not found in list.", hFlatSrcName.c_str()); } }; - loadFlatForPID(kInclusive); - loadFlatForPID(kCombinedPID); + for (int i = 0; i < KNsp; ++i) { + loadFlatForPID(static_cast(i)); + } } else { - LOGF(error, "Could not retrieve TList for MC Flattening from: %s", pathMCFlat.c_str()); + LOGF(error, "Could not retrieve MC Flattening TList from: %s", pathMCFlat.c_str()); } } } @@ -1034,7 +1370,6 @@ struct RadialFlowDecorr { auto loadTProfile3DFromList = [&](TList* sourceList, const char* objName, TProfile3D*& target) { if (!sourceList) return; - auto* tp = reinterpret_cast(sourceList->FindObject(objName)); if (tp) { target = reinterpret_cast(tp->Clone()); @@ -1045,23 +1380,34 @@ struct RadialFlowDecorr { } }; + auto loadTProfileFromList = [&](TList* sourceList, const char* objName, TProfile*& target) { + if (!sourceList) + return; + auto* tp = reinterpret_cast(sourceList->FindObject(objName)); + if (tp) { + target = reinterpret_cast(tp->Clone()); + target->SetDirectory(nullptr); + LOGF(info, "Loaded %s from list", objName); + } else { + LOGF(error, "Histogram %s missing in CCDB TList", objName); + } + }; + if (cfgRunMCFluc) { LOGF(info, "Loading MC Mean profiles from CCDB path: %s", pathMCMean.c_str()); TList* lstMCMean = ccdb->getForTimeStamp(pathMCMean, now); if (lstMCMean) { - loadTProfile3DFromList(lstMCMean, "pmeanTruNchEtabinPtbin", pmeanTruNchEtabinPtbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanRecoNchEtabinPtbin", pmeanRecoNchEtabinPtbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanRecoEffcorrNchEtabinPtbin", pmeanRecoEffcorrNchEtabinPtbinStep2); + loadTProfileFromList(lstMCMean, "pmeanFT0Amultpv", state.pmeanFT0AmultpvStep2); + loadTProfileFromList(lstMCMean, "pmeanFT0Cmultpv", state.pmeanFT0CmultpvStep2); - loadTProfile3DFromList(lstMCMean, "pmeanEtTruNchEtabinPtbin", pmeanEtTruNchEtabinPtbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanEtRecoNchEtabinPtbin", pmeanEtRecoNchEtabinPtbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanEtRecoEffcorrNchEtabinPtbin", pmeanEtRecoEffcorrNchEtabinPtbinStep2); - - loadTProfile3DFromList(lstMCMean, "pmeanMultTruNchEtabinPtbin", pmeanMultTruNchEtabinPtbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanMultRecoNchEtabinPtbin", pmeanMultRecoNchEtabinPtbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanMultRecoEffcorrNchEtabinPtbin", pmeanMultRecoEffcorrNchEtabinPtbinStep2); + loadTProfile3DFromList(lstMCMean, "pmeanTru_nch_etabin_spbin", state.pmeanTruNchEtabinSpbinStep2); + loadTProfile3DFromList(lstMCMean, "pmeanReco_nch_etabin_spbin", state.pmeanRecoNchEtabinSpbinStep2); + loadTProfile3DFromList(lstMCMean, "pmeanRecoEffcorr_nch_etabin_spbin", state.pmeanRecoEffcorrNchEtabinSpbinStep2); + loadTProfile3DFromList(lstMCMean, "pmeanMultTru_nch_etabin_spbin", state.pmeanMultTruNchEtabinSpbinStep2); + loadTProfile3DFromList(lstMCMean, "pmeanMultReco_nch_etabin_spbin", state.pmeanMultRecoNchEtabinSpbinStep2); + loadTProfile3DFromList(lstMCMean, "pmeanMultRecoEffcorr_nch_etabin_spbin", state.pmeanMultRecoEffcorrNchEtabinSpbinStep2); } else { LOGF(error, "Could not retrieve TList for MC Mean from: %s", pathMCMean.c_str()); } @@ -1072,9 +1418,11 @@ struct RadialFlowDecorr { TList* lstDataMean = ccdb->getForTimeStamp(pathDataMean, now); if (lstDataMean) { - loadTProfile3DFromList(lstDataMean, "pmean_nch_etabin_ptbin", pmeanNchEtabinPtbinStep2); - loadTProfile3DFromList(lstDataMean, "pmeanEt_nch_etabin_ptbin", pmeanEtNchEtabinPtbinStep2); - loadTProfile3DFromList(lstDataMean, "pmeanMult_nch_etabin_ptbin", pmeanMultNchEtabinPtbinStep2); + loadTProfileFromList(lstDataMean, "pmeanFT0Amultpv", state.pmeanFT0AmultpvStep2); + loadTProfileFromList(lstDataMean, "pmeanFT0Cmultpv", state.pmeanFT0CmultpvStep2); + + loadTProfile3DFromList(lstDataMean, "pmean_nch_etabin_spbin", state.pmeanNchEtabinSpbinStep2); + loadTProfile3DFromList(lstDataMean, "pmeanMult_nch_etabin_spbin", state.pmeanMultNchEtabinSpbinStep2); } else { LOGF(error, "Could not retrieve TList for Data Mean from: %s", pathDataMean.c_str()); } @@ -1082,991 +1430,1512 @@ struct RadialFlowDecorr { LOGF(info, "CCDB initialization complete for RadialFlowDecorr."); } - void processGetEffHists(aod::McCollisions const& mcColl, soa::SmallGroups const& collisions, TCs const& tracks, FilteredTCs const& /*filteredTracks*/, aod::McParticles const& mcParticles) + void processMCGetMeanNsig(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks) { - for (const auto& mcCollision : mcColl) { - auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); - if (colSlice.size() != 1) - continue; - - for (const auto& col : colSlice) { - if (!col.has_mcCollision()) - continue; - histos.fill(HIST("hVtxZ"), col.posZ()); - if (!isEventSelected(col)) - continue; + histos.fill(HIST("hVtxZ"), mcCollision.posZ()); + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + return; + float cent = getCentrality(mcCollision); + if (cent > KCentMax) + return; + float multPV = mcCollision.multNTracksPV(); - auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); - if (trackSlice.size() < 1) - continue; + histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); + histos.fill(HIST("hCentrality"), cent); + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), multPV, mcTracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); - auto partSlice = mcParticles.sliceBy(partPerMcCollision, mcCollision.globalIndex()); - if (partSlice.size() < 1) - continue; + for (const auto& track : mcTracks) { + if (!isTrackSelected(track)) + continue; + fillNSigmaBefCut(track, cent); + } + } + PROCESS_SWITCH(RadialFlowDecorr, processMCGetMeanNsig, "process MC to calculate Mean values of nSig Plots", cfgRunMCGetNSig); - float cent = getCentrality(col); - if (cent > KCentMax) - continue; + void processGetEffHists(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks, aod::McParticles const& mcParticles) + { + histos.fill(HIST("hVtxZ"), mcCollision.posZ()); + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + return; + float cent = getCentrality(mcCollision); + if (cent > KCentMax) + return; + float multPV = mcCollision.multNTracksPV(); + float vz = mcCollision.posZ(); + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) + return; + histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); + histos.fill(HIST("hCentrality"), cent); - histos.fill(HIST("hZvtx_after_sel"), col.posZ()); + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), multPV, mcTracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); - histos.fill(HIST("hCentrality"), cent); - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), col.multNTracksPV(), tracks.size()); - histos.fill(HIST("Hist2D_cent_nch"), col.multNTracksPV(), cent); + for (const auto& particle : mcParticles) { + if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) + continue; - for (const auto& particle : partSlice) { - if (!isParticleSelected(particle)) - continue; - if (!particle.isPhysicalPrimary()) - continue; + const int pdg = particle.pdgCode(); + const int absPdg = std::abs(pdg); + float pt = particle.pt(), eta = particle.eta(); + + bool isSpecies[KNsp] = { + true, // kInclusiveIdx + pdg == -KPiPlus, // kPiMinusIdx + pdg == KPiPlus, // kPiPlusIdx + absPdg == KPiPlus, // kPiAllIdx + pdg == -KKPlus, // kKaMinusIdx + pdg == KKPlus, // kKaPlusIdx + absPdg == KKPlus, // kKaAllIdx + pdg == -KProton, // kAntiPrIdx + pdg == KProton, // kPrIdx + absPdg == KProton // kPrAllIdx + }; - const int absPdgId = std::abs(particle.pdgCode()); - const bool isPion = (absPdgId == KPiPlus); - const bool isKaon = (absPdgId == KKPlus); - const bool isProton = (absPdgId == KProton); - const bool isPid = (isPion || isKaon || isProton); + histos.fill(HIST("h3_AllPrimary"), multPV, pt, eta); + if (isSpecies[kPiMinusIdx]) + histos.fill(HIST("h3_AllPrimary_PiMinus"), multPV, pt, eta); + else if (isSpecies[kPiPlusIdx]) + histos.fill(HIST("h3_AllPrimary_PiPlus"), multPV, pt, eta); + if (isSpecies[kPiAllIdx]) + histos.fill(HIST("h3_AllPrimary_PiAll"), multPV, pt, eta); + + if (isSpecies[kKaMinusIdx]) + histos.fill(HIST("h3_AllPrimary_KaMinus"), multPV, pt, eta); + else if (isSpecies[kKaPlusIdx]) + histos.fill(HIST("h3_AllPrimary_KaPlus"), multPV, pt, eta); + if (isSpecies[kKaAllIdx]) + histos.fill(HIST("h3_AllPrimary_KaAll"), multPV, pt, eta); + + if (isSpecies[kAntiPrIdx]) + histos.fill(HIST("h3_AllPrimary_AntiPr"), multPV, pt, eta); + else if (isSpecies[kPrIdx]) + histos.fill(HIST("h3_AllPrimary_Pr"), multPV, pt, eta); + if (isSpecies[kPrAllIdx]) + histos.fill(HIST("h3_AllPrimary_PrAll"), multPV, pt, eta); + } - histos.fill(HIST("hTruth_ParticleWeight"), cent, particle.pt(), particle.eta(), particle.weight()); - histos.fill(HIST("h3_AllPrimary"), col.multNTracksPV(), particle.pt(), particle.eta()); - histos.fill(HIST("h_AllPrimary"), particle.pt()); + for (const auto& track : mcTracks) { + if (!isTrackSelected(track)) + continue; - if (isPid) { - histos.fill(HIST("h3_AllPrimary_PID"), col.multNTracksPV(), particle.pt(), particle.eta()); - } - } - histos.fill(HIST("TruthTracKVz"), mcCollision.posZ(), col.posZ()); - histos.fill(HIST("vzResolution"), mcCollision.posZ(), mcCollision.posZ() - col.posZ()); + float pt = track.pt(), eta = track.eta(); + auto sign = track.sign(); + fillNSigmaBefCut(track, cent); - // Reconstructed - for (const auto& track : trackSlice) { - if (!isTrackSelected(track)) - continue; + int id = identifyTrack(track, cent); + bool isPi = (id == KPidPionOne); + bool isKa = (id == KPidKaonTwo); + bool isPr = (id == KPidProtonThree); + bool isSpecies[KNsp] = { + true, + isPi && sign < 0, isPi && sign > 0, isPi, + isKa && sign < 0, isKa && sign > 0, isKa, + isPr && sign < 0, isPr && sign > 0, isPr}; - const bool isPion = selectionPion(track); - const bool isKaon = selectionKaon(track); - const bool isProton = selectionProton(track); - const bool isPid = (isPion || isKaon || isProton); - histos.fill(HIST("hP"), track.p()); - histos.fill(HIST("hPt"), track.pt()); - histos.fill(HIST("hEta"), track.eta()); - histos.fill(HIST("hPhi"), track.phi()); - histos.fill(HIST("h_AllReco"), track.pt()); - - histos.fill(HIST("h3_AllReco"), col.multNTracksPV(), track.pt(), track.eta()); - histos.fill(HIST("hEtaPhiReco"), col.posZ(), track.sign(), track.pt(), track.eta(), track.phi()); - - histos.fill(HIST("hDCAxy_Reco"), track.dcaXY()); - histos.fill(HIST("hDCAz_Reco"), track.dcaZ()); - if (isPid) { - histos.fill(HIST("h3_AllReco_PID"), col.multNTracksPV(), track.pt(), track.eta()); - histos.fill(HIST("hEtaPhiReco_PID"), col.posZ(), track.sign(), track.pt(), track.eta(), track.phi()); - } + fillNSigmaAftCut(track, cent, isSpecies); + for (int isp = 0; isp < KNsp; ++isp) { + if (!isSpecies[isp]) + continue; + + if (isp == kInclusiveIdx) { + histos.fill(HIST("h3_AllReco"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + histos.fill(HIST("ptResolution"), mcP.pt(), (pt - mcP.pt()) / mcP.pt()); + histos.fill(HIST("etaResolution"), mcP.eta(), eta - mcP.eta()); + histos.fill(HIST("etaTruthReco"), mcP.eta(), eta); + histos.fill(HIST("vzResolution"), mcP.vz(), (vz - mcP.vz()) / mcP.vz()); + histos.fill(HIST("TruthTracKVz"), mcP.vz(), vz); + histos.fill(HIST("h3_RecoMatchedToPrimary"), multPV, mcP.pt(), mcP.eta()); + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake"), multPV, pt, eta); + } + } else if (isp == kPiMinusIdx) { + histos.fill(HIST("h3_AllReco_PiMinus"), multPV, pt, eta); if (track.has_mcParticle()) { - auto mcPart2 = track.mcParticle(); - if (mcPart2.isPhysicalPrimary()) { - const int absPdgId = std::abs(mcPart2.pdgCode()); - const bool isPionTrue = (absPdgId == kPiPlus); - const bool isKaonTrue = (absPdgId == kKPlus); - const bool isProtonTrue = (absPdgId == kProton); - const bool isPidTrue = (isPionTrue || isKaonTrue || isProtonTrue); - - histos.fill(HIST("hReco_ParticleWeight"), cent, mcPart2.pt(), mcPart2.eta(), mcPart2.weight()); - histos.fill(HIST("ptResolution"), mcPart2.pt(), mcPart2.pt() - track.pt()); - histos.fill(HIST("ptTruthReco"), mcPart2.pt(), track.pt()); - histos.fill(HIST("etaResolution"), mcPart2.eta(), mcPart2.eta() - track.eta()); - histos.fill(HIST("etaTruthReco"), mcPart2.eta(), track.eta()); - histos.fill(HIST("h3_RecoMatchedToPrimary"), col.multNTracksPV(), mcPart2.pt(), mcPart2.eta()); - histos.fill(HIST("h_RecoMatchedToPrimary"), mcPart2.pt()); - - histos.fill(HIST("hDCAxy_RecoMatched"), track.dcaXY()); - histos.fill(HIST("hDCAz_RecoMatched"), track.dcaZ()); - - if (isPid && isPidTrue) { - histos.fill(HIST("h3_RecoMatchedToPrimary_PID"), col.multNTracksPV(), mcPart2.pt(), mcPart2.eta()); + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (mcP.pdgCode() == -KPiPlus) { + histos.fill(HIST("h3_RecoMatchedToPrimary_PiMinus"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PiMinus"), multPV, pt, eta); } - } else { - // Matched to secondary - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary"), col.multNTracksPV(), track.pt(), track.eta()); - histos.fill(HIST("h_RecoUnMatchedToPrimary"), track.pt()); - histos.fill(HIST("hDCAxy_Unmatched"), track.dcaXY()); - histos.fill(HIST("hDCAz_Unmatched"), track.dcaZ()); - if (isPid) { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PID"), col.multNTracksPV(), track.pt(), track.eta()); + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PiMinus"), multPV, pt, eta); + } + } else { // No MC + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PiMinus"), multPV, pt, eta); + } + } else if (isp == kPiPlusIdx) { + histos.fill(HIST("h3_AllReco_PiPlus"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (mcP.pdgCode() == KPiPlus) { + histos.fill(HIST("h3_RecoMatchedToPrimary_PiPlus"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PiPlus"), multPV, pt, eta); } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PiPlus"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PiPlus"), multPV, pt, eta); + } + } else if (isp == kPiAllIdx) { + histos.fill(HIST("h3_AllReco_PiAll"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (std::abs(mcP.pdgCode()) == KPiPlus) { + histos.fill(HIST("h3_RecoMatchedToPrimary_PiAll"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PiAll"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PiAll"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PiAll"), multPV, pt, eta); + } + } else if (isp == kKaMinusIdx) { + histos.fill(HIST("h3_AllReco_KaMinus"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (mcP.pdgCode() == -KKPlus) { + histos.fill(HIST("h3_RecoMatchedToPrimary_KaMinus"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_KaMinus"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_KaMinus"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_KaMinus"), multPV, pt, eta); + } + } else if (isp == kKaPlusIdx) { + histos.fill(HIST("h3_AllReco_KaPlus"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (mcP.pdgCode() == KKPlus) { + histos.fill(HIST("h3_RecoMatchedToPrimary_KaPlus"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_KaPlus"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_KaPlus"), multPV, pt, eta); } } else { - // Fake track - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake"), col.multNTracksPV(), track.pt(), track.eta()); - histos.fill(HIST("h_RecoUnMatchedToPrimary"), track.pt()); - histos.fill(HIST("hDCAxy_NotPrimary"), track.dcaXY()); - histos.fill(HIST("hDCAz_NotPrimary"), track.dcaZ()); - if (isPid) { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PID"), col.multNTracksPV(), track.pt(), track.eta()); + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_KaPlus"), multPV, pt, eta); + } + } else if (isp == kKaAllIdx) { + histos.fill(HIST("h3_AllReco_KaAll"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (std::abs(mcP.pdgCode()) == KKPlus) { + histos.fill(HIST("h3_RecoMatchedToPrimary_KaAll"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_KaAll"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_KaAll"), multPV, pt, eta); } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_KaAll"), multPV, pt, eta); } - } // tracks - } // cols - } // mcColl - LOGF(info, "FINISHED RUNNING processGetEffHists"); + } else if (isp == kAntiPrIdx) { + histos.fill(HIST("h3_AllReco_AntiPr"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (mcP.pdgCode() == -KProton) { + histos.fill(HIST("h3_RecoMatchedToPrimary_AntiPr"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_AntiPr"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_AntiPr"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_AntiPr"), multPV, pt, eta); + } + } else if (isp == kPrIdx) { + histos.fill(HIST("h3_AllReco_Pr"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (mcP.pdgCode() == KProton) { + histos.fill(HIST("h3_RecoMatchedToPrimary_Pr"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_Pr"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_Pr"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_Pr"), multPV, pt, eta); + } + } else if (isp == kPrAllIdx) { + histos.fill(HIST("h3_AllReco_PrAll"), multPV, pt, eta); + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + if (std::abs(mcP.pdgCode()) == KProton) { + histos.fill(HIST("h3_RecoMatchedToPrimary_PrAll"), multPV, mcP.pt(), mcP.eta()); + } else { // Misidentified + histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PrAll"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PrAll"), multPV, pt, eta); + } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PrAll"), multPV, pt, eta); + } + } + } + } } - PROCESS_SWITCH(RadialFlowDecorr, processGetEffHists, "process MC to calculate Eff and Fakes", cfgRunGetEff); + PROCESS_SWITCH(RadialFlowDecorr, processGetEffHists, "process MC to calculate EffWeights", cfgRunGetEff); - void processMCFlat(aod::McCollisions const& mcColl, soa::SmallGroups const& collisions, TCs const& tracks, FilteredTCs const& /*filteredTracks*/, aod::McParticles const& mcParticles) + void processMCFlat(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks) { - for (const auto& mcCollision : mcColl) { - auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); - if (colSlice.size() != 1) - continue; - - for (const auto& col : colSlice) { - if (!col.has_mcCollision()) - continue; - if (!isEventSelected(col)) - continue; + histos.fill(HIST("hVtxZ"), mcCollision.posZ()); + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + return; - auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); - if (trackSlice.size() < 1) - continue; + float cent = getCentrality(mcCollision); + if (cent > KCentMax) + return; - auto partSlice = mcParticles.sliceBy(partPerMcCollision, mcCollision.globalIndex()); - if (partSlice.size() < 1) - continue; + float multPV = mcCollision.multNTracksPV(); + float vz = mcCollision.posZ(); - float cent = getCentrality(col); - if (cent > KCentMax) - continue; + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) + return; + histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); + histos.fill(HIST("hCentrality"), cent); - // Reconstructed - for (const auto& track : trackSlice) { - if (!isTrackSelected(track)) - continue; + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), mcCollision.multNTracksPV(), mcTracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); + for (const auto& track : mcTracks) { + if (!isTrackSelected(track)) + continue; - float effIncl = getEfficiency(col.multNTracksPV(), track.pt(), track.eta(), kInclusive, 0, cfgEff); - float fakeIncl = getEfficiency(col.multNTracksPV(), track.pt(), track.eta(), kInclusive, 1, cfgEff); - float wIncl = (1.0 - fakeIncl) / effIncl; - if (!std::isfinite(wIncl) || wIncl <= 0.f) - continue; - if (effIncl <= 0 || !std::isfinite(effIncl) || !std::isfinite(fakeIncl)) - continue; - histos.fill(HIST("hEtaPhiRecoEffWtd"), col.posZ(), track.sign(), track.pt(), track.eta(), track.phi(), wIncl); - const bool isPion = selectionPion(track); - const bool isKaon = selectionKaon(track); - const bool isProton = selectionProton(track); - const bool isPid = (isPion || isKaon || isProton); - float effPid = getEfficiency(col.multNTracksPV(), track.pt(), track.eta(), kCombinedPID, 0, cfgEff); - float fakePid = getEfficiency(col.multNTracksPV(), track.pt(), track.eta(), kCombinedPID, 1, cfgEff); - float wPid = (1.0 - fakePid) / effPid; - if (effPid >= 1 || fakePid >= 1 || !std::isfinite(effPid) || effPid <= KFloatEpsilon || !std::isfinite(fakePid)) - continue; + float pt = track.pt(), eta = track.eta(), phi = track.phi(); + auto sign = track.sign(); + int id = identifyTrack(track, cent); + bool isPi = (id == KPidPionOne); + bool isKa = (id == KPidKaonTwo); + bool isPr = (id == KPidProtonThree); + bool isSpecies[KNsp] = { + true, + isPi && sign < 0, isPi && sign > 0, isPi, + isKa && sign < 0, isKa && sign > 0, isKa, + isPr && sign < 0, isPr && sign > 0, isPr}; + + for (int isp = 0; isp < KNsp; ++isp) { + if (!isSpecies[isp]) + continue; - if (isPid) { - histos.fill(HIST("hEtaPhiRecoEffWtd_PID"), col.posZ(), track.sign(), track.pt(), track.eta(), track.phi(), wPid); + float eff = getEfficiency(multPV, pt, eta, static_cast(isp), 0, cfgEff); + float fake = getEfficiency(multPV, pt, eta, static_cast(isp), 1, cfgEff); + float w = (eff > KFloatEpsilon) ? (1.0f - fake) / eff : 0.0f; + + if (std::isfinite(w) && w > 0.f) { + if (isp == kInclusiveIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiMinusIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiPlusIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiAllIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaMinusIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaPlusIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaAllIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); + } else if (isp == kAntiPrIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); + } else if (isp == kPrIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_Pr"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); + } else if (isp == kPrAllIdx) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); } - } // tracks - } // cols - } // mcColl - LOGF(info, "FINISHED RUNNING processMCFlat"); + } + } + } } PROCESS_SWITCH(RadialFlowDecorr, processMCFlat, "process MC to calculate FlatWeights", cfgRunGetMCFlat); - void processMCMean(aod::McCollisions const& mcColl, MyRun3MCCollisions const& collisions, TCs const& tracks, FilteredTCs const& /*filteredTracks*/, aod::McParticles const& mcParticles) + void processMCMean(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks, aod::FT0s const&, aod::McParticles const& mcParticles) { - float sumWiTruth[KNEta][KNpT], sumWiptiTruth[KNEta][KNpT]; - float sumWiReco[KNEta][KNpT], sumWiptiReco[KNEta][KNpT]; - float sumWiRecoEffCorr[KNEta][KNpT], sumWiptiRecoEffCorr[KNEta][KNpT]; - float sumWiTruthEt[KNEta][KNpT], sumWiptiTruthEt[KNEta][KNpT]; - float sumWiRecoEt[KNEta][KNpT], sumWiptiRecoEt[KNEta][KNpT]; - float sumWiRecoEffCorrEt[KNEta][KNpT], sumWiptiRecoEffCorrEt[KNEta][KNpT]; + double sumWiTruth[KNsp][KNEta]{}, sumWiptiTruth[KNsp][KNEta]{}; + double sumWiReco[KNsp][KNEta]{}, sumWiptiReco[KNsp][KNEta]{}; + double sumWiRecoEffCorr[KNsp][KNEta]{}, sumWiptiRecoEffCorr[KNsp][KNEta]{}; + histos.fill(HIST("hVtxZ"), mcCollision.posZ()); + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + return; + float cent = getCentrality(mcCollision); + if (cent > KCentMax) + return; + float multPV = mcCollision.multNTracksPV(); + float vz = mcCollision.posZ(); + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) + return; + + histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); + histos.fill(HIST("hCentrality"), cent); + + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), mcCollision.multNTracksPV(), mcTracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); - for (const auto& mcCollision : mcColl) { - auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + memset(sumWiTruth, 0, sizeof(sumWiTruth)); + memset(sumWiptiTruth, 0, sizeof(sumWiptiTruth)); + memset(sumWiReco, 0, sizeof(sumWiReco)); + memset(sumWiptiReco, 0, sizeof(sumWiptiReco)); + memset(sumWiRecoEffCorr, 0, sizeof(sumWiRecoEffCorr)); + memset(sumWiptiRecoEffCorr, 0, sizeof(sumWiptiRecoEffCorr)); - if (colSlice.size() != 1) + for (const auto& particle : mcParticles) { + if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) continue; - for (const auto& col : colSlice) { - if (!col.has_mcCollision()) - continue; - if (!isEventSelected(col)) - continue; - histos.fill(HIST("hVtxZ"), col.posZ()); - auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); - if (trackSlice.size() < 1) - continue; + float pt = particle.pt(), eta = particle.eta(); + if (pt <= cfgPtMin || pt > cfgPtMax) + continue; + int pdgCode = particle.pdgCode(); + int absPdg = std::abs(pdgCode); + + bool isSpecies[KNsp] = { + true, // kInclusiveIdx + pdgCode == -KPiPlus, // kPiMinusIdx + pdgCode == KPiPlus, // kPiPlusIdx + absPdg == KPiPlus, // kPiAllIdx + pdgCode == -KKPlus, // kKaMinusIdx + pdgCode == KKPlus, // kKaPlusIdx + absPdg == KKPlus, // kKaAllIdx + pdgCode == -KProton, // kAntiPrIdx + pdgCode == KProton, // kPrIdx + absPdg == KProton // kPrAllIdx + }; - auto partSlice = mcParticles.sliceBy(partPerMcCollision, mcCollision.globalIndex()); - if (partSlice.size() < 1) + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) continue; - float cent = getCentrality(col); - if (cent > KCentMax) + for (int isp = 0; isp < KNsp; ++isp) { + if (isSpecies[isp]) { + sumWiTruth[isp][ieta]++; + sumWiptiTruth[isp][ieta] += pt; + } + } + } + } + + for (int isp = 0; isp < KNsp; ++isp) { + histos.fill(HIST("MCGen/Prof_Cent_Nsp_Nchrec"), cent, isp, sumWiTruth[isp][0]); + histos.fill(HIST("MCGen/Prof_Mult_Nsp_Nchrec"), multPV, isp, sumWiTruth[isp][0]); + if (sumWiTruth[isp][0] > 1.0f) { + histos.fill(HIST("MCGen/Prof_Cent_Nsp_MeanpT"), cent, isp, sumWiptiTruth[isp][0] / sumWiTruth[isp][0]); + histos.fill(HIST("MCGen/Prof_Mult_Nsp_MeanpT"), multPV, isp, sumWiptiTruth[isp][0] / sumWiTruth[isp][0]); + } + } + + for (const auto& track : mcTracks) { + if (!isTrackSelected(track)) + continue; + float pt = track.pt(), eta = track.eta(), phi = track.phi(); + if (pt <= cfgPtMin || pt > cfgPtMax) + continue; + auto sign = track.sign(); + histos.fill(HIST("hPt"), pt); + histos.fill(HIST("hEta"), eta); + histos.fill(HIST("hPhi"), phi); + int id = identifyTrack(track, cent); + bool isPi = (id == KPidPionOne); + bool isKa = (id == KPidKaonTwo); + bool isPr = (id == KPidProtonThree); + bool isSpecies[KNsp] = { + true, + isPi && sign < 0, isPi && sign > 0, isPi, + isKa && sign < 0, isKa && sign > 0, isKa, + isPr && sign < 0, isPr && sign > 0, isPr}; + + for (int isp = 0; isp < KNsp; ++isp) { + if (!isSpecies[isp]) + continue; + float eff = getEfficiency(multPV, pt, eta, static_cast(isp), 0, cfgEff); + float fake = getEfficiency(multPV, pt, eta, static_cast(isp), 1, cfgEff); + float flatW = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); + float w = flatW * (1.0 - fake) / eff; + if (!std::isfinite(w) || w <= 0.f || eff <= KFloatEpsilon) continue; - histos.fill(HIST("hZvtx_after_sel"), col.posZ()); - histos.fill(HIST("hCentrality"), cent); - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), col.multNTracksPV(), tracks.size()); - histos.fill(HIST("Hist2D_cent_nch"), col.multNTracksPV(), cent); - histos.fill(HIST("TruthTracKVz"), mcCollision.posZ(), col.posZ()); - histos.fill(HIST("vzResolution"), mcCollision.posZ(), mcCollision.posZ() - col.posZ()); - - memset(sumWiTruth, 0, sizeof(sumWiTruth)); - memset(sumWiptiTruth, 0, sizeof(sumWiptiTruth)); - memset(sumWiReco, 0, sizeof(sumWiReco)); - memset(sumWiptiReco, 0, sizeof(sumWiptiReco)); - memset(sumWiRecoEffCorr, 0, sizeof(sumWiRecoEffCorr)); - memset(sumWiptiRecoEffCorr, 0, sizeof(sumWiptiRecoEffCorr)); - memset(sumWiTruthEt, 0, sizeof(sumWiTruthEt)); - memset(sumWiptiTruthEt, 0, sizeof(sumWiptiTruthEt)); - memset(sumWiRecoEt, 0, sizeof(sumWiRecoEt)); - memset(sumWiptiRecoEt, 0, sizeof(sumWiptiRecoEt)); - memset(sumWiRecoEffCorrEt, 0, sizeof(sumWiRecoEffCorrEt)); - memset(sumWiptiRecoEffCorrEt, 0, sizeof(sumWiptiRecoEffCorrEt)); - - // Truth - for (const auto& particle : partSlice) { - if (!isParticleSelected(particle)) - continue; - if (!particle.isPhysicalPrimary()) + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) continue; - - const int absPdgId = std::abs(particle.pdgCode()); - const bool isPion = (absPdgId == kPiPlus); - const bool isKaon = (absPdgId == kKPlus); - const bool isProton = (absPdgId == kProton); - - float pt = particle.pt(); - float eta = particle.eta(); - float p = particle.p(); - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - sumWiTruth[ieta][ipt]++; - sumWiptiTruth[ieta][ipt] += pt; - if (isPion || isKaon || isProton) { - float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus - : o2::constants::physics::MassProton; - float energy = std::sqrt(p * p + m * m); - float et = energy * (pt / p); // E_T = E * sin(theta) = E * (pT / p) - sumWiTruthEt[ieta][ipt]++; - sumWiptiTruthEt[ieta][ipt] += et; - } - } - } + sumWiReco[isp][ieta]++; + sumWiptiReco[isp][ieta] += pt; + sumWiRecoEffCorr[isp][ieta] += w; + sumWiptiRecoEffCorr[isp][ieta] += w * pt; } - for (const auto& track : trackSlice) { - if (!isTrackSelected(track)) - continue; + if (isp == kInclusiveIdx) { + histos.fill(HIST("Eff_cent"), cent, eff); + histos.fill(HIST("Fake_cent"), cent, fake); + histos.fill(HIST("wgt_cent"), cent, w); - float pt = track.pt(); - float eta = track.eta(); - float p = track.p(); - float phi = track.phi(); + histos.fill(HIST("Eff_Ntrk"), multPV, eff); + histos.fill(HIST("Fake_Ntrk"), multPV, fake); + histos.fill(HIST("wgt_Ntrk"), multPV, w); - histos.fill(HIST("hEtaPhiReco"), col.posZ(), track.sign(), track.pt(), eta, phi); + histos.fill(HIST("Eff_pT"), pt, eff); + histos.fill(HIST("Fake_pT"), pt, fake); + histos.fill(HIST("wgt_pT"), pt, w); - float effIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 0, cfgEff); - float fakeIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 1, cfgEff); - float flatWeightIncl = getFlatteningWeight(col.posZ(), track.sign(), pt, eta, phi, kInclusive, cfgFlat); - float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; - if (!std::isfinite(wIncl) || wIncl <= 0.f) - continue; - if (effIncl <= 0 || !std::isfinite(effIncl) || !std::isfinite(fakeIncl) || !std::isfinite(flatWeightIncl)) - continue; - histos.fill(HIST("hEtaPhiRecoWtd"), col.posZ(), track.sign(), pt, eta, phi, flatWeightIncl); - histos.fill(HIST("hEtaPhiRecoEffWtd"), col.posZ(), track.sign(), pt, eta, phi, wIncl); - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - sumWiReco[ieta][ipt] += 1.0; - sumWiptiReco[ieta][ipt] += pt; - } - } + histos.fill(HIST("Eff_eta"), eta, eff); + histos.fill(HIST("Fake_eta"), eta, fake); + histos.fill(HIST("wgt_eta"), eta, w); + } + if (isp == kInclusiveIdx) { + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPiMinusIdx) { + histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPiPlusIdx) { + histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPiAllIdx) { + histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kKaMinusIdx) { + histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kKaPlusIdx) { + histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kKaAllIdx) { + histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPrIdx) { + histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kAntiPrIdx) { + histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPrAllIdx) { + histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } + } + } - if (!std::isfinite(wIncl) || !std::isfinite(fakeIncl) || !std::isfinite(flatWeightIncl)) - continue; + for (int isp = 0; isp < KNsp; ++isp) { + histos.fill(HIST("MCReco/Prof_Cent_Nsp_Nchrec"), cent, isp, sumWiReco[isp][0]); + histos.fill(HIST("MCReco/Prof_Mult_Nsp_Nchrec"), multPV, isp, sumWiReco[isp][0]); - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - sumWiRecoEffCorr[ieta][ipt] += wIncl; - sumWiptiRecoEffCorr[ieta][ipt] += wIncl * pt; - } - } + histos.fill(HIST("MCRecoEffCorr/Prof_Cent_Nsp_Nchrec"), cent, isp, sumWiRecoEffCorr[isp][0]); + histos.fill(HIST("MCRecoEffCorr/Prof_Mult_Nsp_Nchrec"), multPV, isp, sumWiRecoEffCorr[isp][0]); - const bool isPion = selectionPion(track); - const bool isKaon = selectionKaon(track); - const bool isProton = selectionProton(track); - if (isPion || isKaon || isProton) { - histos.fill(HIST("hEtaPhiReco_PID"), col.posZ(), track.sign(), track.pt(), eta, phi); - float effPid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 0, cfgEff); - float fakePid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 1, cfgEff); - float flatWeightPid = getFlatteningWeight(col.posZ(), track.sign(), pt, eta, phi, kCombinedPID, cfgFlat); - float wPid = flatWeightPid * (1.0 - fakePid) / effPid; - if (!std::isfinite(effPid) || effPid <= KFloatEpsilon || !std::isfinite(fakePid) || !std::isfinite(flatWeightPid)) - continue; - histos.fill(HIST("hEtaPhiRecoWtd_PID"), col.posZ(), track.sign(), track.pt(), eta, track.phi(), flatWeightPid); - histos.fill(HIST("hEtaPhiRecoEffWtd_PID"), col.posZ(), track.sign(), track.pt(), eta, track.phi(), wPid); - - float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus - : o2::constants::physics::MassProton; - float energy = std::sqrt(p * p + m * m); - float et = energy * (pt / p); // E_T = E * sin(theta) - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - sumWiRecoEt[ieta][ipt] += 1.0; - sumWiptiRecoEt[ieta][ipt] += et; - } - } + if (sumWiReco[isp][0] > 1.0f) { + histos.fill(HIST("MCReco/Prof_Cent_Nsp_MeanpT"), cent, isp, sumWiptiReco[isp][0] / sumWiReco[isp][0]); + histos.fill(HIST("MCReco/Prof_Mult_Nsp_MeanpT"), multPV, isp, sumWiptiReco[isp][0] / sumWiReco[isp][0]); + } + if (sumWiRecoEffCorr[isp][0] > 1.0f) { + histos.fill(HIST("MCRecoEffCorr/Prof_Cent_Nsp_MeanpT"), cent, isp, sumWiptiRecoEffCorr[isp][0] / sumWiRecoEffCorr[isp][0]); + histos.fill(HIST("MCRecoEffCorr/Prof_Mult_Nsp_MeanpT"), multPV, isp, sumWiptiRecoEffCorr[isp][0] / sumWiRecoEffCorr[isp][0]); + } + } - if (!std::isfinite(wPid) || !std::isfinite(fakePid) || !std::isfinite(flatWeightPid)) - continue; - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - sumWiRecoEffCorrEt[ieta][ipt] += wPid; - sumWiptiRecoEffCorrEt[ieta][ipt] += wPid * et; - } - } + for (int ietaA = 0; ietaA < KNEta; ++ietaA) { + for (int ietaC = 0; ietaC < KNEta; ++ietaC) { + for (int isp = 0; isp < KNsp; ++isp) { + float nTruAB = sumWiTruth[isp][ietaA] + sumWiTruth[isp][ietaC]; + float nRecoAB = sumWiReco[isp][ietaA] + sumWiReco[isp][ietaC]; + float nCorrAB = sumWiRecoEffCorr[isp][ietaA] + sumWiRecoEffCorr[isp][ietaC]; + + float mptsubTru = (sumWiptiTruth[isp][ietaA] + sumWiptiTruth[isp][ietaC]) / nTruAB; + float mptsubReco = (sumWiptiReco[isp][ietaA] + sumWiptiReco[isp][ietaC]) / nRecoAB; + float mptsubRecoEffCorr = (sumWiptiRecoEffCorr[isp][ietaA] + sumWiptiRecoEffCorr[isp][ietaC]) / nCorrAB; + + if (nTruAB > 0) { + if (isp == kInclusiveIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kPiMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_PiMinus"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kPiPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_PiPlus"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kPiAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_PiAll"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kKaMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_KaMinus"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kKaPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_KaPlus"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kKaAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_KaAll"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_Pr"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kAntiPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_AntiPr"), cent, ietaA, ietaC, mptsubTru); + else if (isp == kPrAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Tru_PrAll"), cent, ietaA, ietaC, mptsubTru); } - if (std::isfinite(wIncl)) { - if (cent < KCentTestMin) { - histos.fill(HIST("wgt_pT"), pt, wIncl); - histos.fill(HIST("Eff_pT"), pt, effIncl); - histos.fill(HIST("Fake_pT"), pt, fakeIncl); - histos.fill(HIST("Eff_eta"), eta, effIncl); - histos.fill(HIST("Fake_eta"), eta, fakeIncl); - histos.fill(HIST("wgt_eta"), eta, wIncl); - } - histos.fill(HIST("Eff_cent"), cent, effIncl); - histos.fill(HIST("Eff_Ntrk"), col.multNTracksPV(), effIncl); - histos.fill(HIST("Fake_cent"), cent, fakeIncl); - histos.fill(HIST("Fake_Ntrk"), col.multNTracksPV(), fakeIncl); - histos.fill(HIST("wgt_cent"), cent, wIncl); - histos.fill(HIST("wgt_Ntrk"), col.multNTracksPV(), wIncl); + if (nRecoAB > 0) { + if (isp == kInclusiveIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kPiMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_PiMinus"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kPiPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_PiPlus"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kPiAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_PiAll"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kKaMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_KaMinus"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kKaPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_KaPlus"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kKaAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_KaAll"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_Pr"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kAntiPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_AntiPr"), cent, ietaA, ietaC, mptsubReco); + else if (isp == kPrAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Reco_PrAll"), cent, ietaA, ietaC, mptsubReco); } - } // end track loop - - if (std::isfinite(sumWiTruth[0][0])) { - float meanPtTruth = sumWiptiTruth[0][0] / sumWiTruth[0][0]; - if (!std::isfinite(meanPtTruth)) - LOGF(info, "meanPtTruth = %.3f, num = %.3f, den =%.3f", meanPtTruth, sumWiptiTruth[0][0], sumWiTruth[0][0]); - if (std::isfinite(meanPtTruth)) { - histos.fill(HIST("MCGen/Prof_cent_Nchrec"), cent, sumWiTruth[0][0]); - histos.fill(HIST("MCGen/Prof_Cent_MeanpT"), cent, meanPtTruth); - histos.fill(HIST("MCGen/Prof_Mult_MeanpT"), col.multNTracksPV(), meanPtTruth); - } - } - if (std::isfinite(sumWiReco[0][0])) { - float meanPtReco = sumWiptiReco[0][0] / sumWiReco[0][0]; - if (!std::isfinite(meanPtReco)) - LOGF(info, "meanPtReco = %.3f, num = %.3f, den =%.3f", meanPtReco, sumWiptiReco[0][0], sumWiReco[0][0]); - if (std::isfinite(meanPtReco)) { - histos.fill(HIST("MCReco/Prof_cent_Nchrec"), cent, sumWiReco[0][0]); - histos.fill(HIST("MCReco/Prof_Cent_MeanpT"), cent, meanPtReco); - histos.fill(HIST("MCReco/Prof_Mult_MeanpT"), col.multNTracksPV(), meanPtReco); - } - } - if (std::isfinite(sumWiRecoEffCorr[0][0])) { - float meanpTeffcorr = sumWiptiRecoEffCorr[0][0] / sumWiRecoEffCorr[0][0]; - if (!std::isfinite(meanpTeffcorr)) - LOGF(info, "meanPtRecoEffcorr = %.3f, num = %.3f, den =%.3f", meanpTeffcorr, sumWiptiRecoEffCorr[0][0], sumWiRecoEffCorr[0][0]); - if (std::isfinite(meanpTeffcorr)) { - histos.fill(HIST("MCRecoEffCorr/Prof_cent_Nchrec"), cent, sumWiRecoEffCorr[0][0]); - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_MeanpT"), cent, meanpTeffcorr); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_MeanpT"), col.multNTracksPV(), meanpTeffcorr); + if (nCorrAB > 0) { + if (isp == kInclusiveIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kPiMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PiMinus"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kPiPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PiPlus"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kPiAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PiAll"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kKaMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_KaMinus"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kKaPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_KaPlus"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kKaAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_KaAll"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_Pr"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kAntiPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_AntiPr"), cent, ietaA, ietaC, mptsubRecoEffCorr); + else if (isp == kPrAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PrAll"), cent, ietaA, ietaC, mptsubRecoEffCorr); } } + } - if (std::isfinite(sumWiTruthEt[0][0])) { - float meanEt = sumWiptiTruthEt[0][0] / sumWiTruthEt[0][0]; - if (!std::isfinite(meanEt)) - LOGF(info, "meanEtTruthEt = %.3f, num = %.3f, den =%.3f", meanEt, sumWiptiTruthEt[0][0], sumWiTruthEt[0][0]); - if (std::isfinite(meanEt)) { - histos.fill(HIST("MCGen/Prof_Cent_MeanEt"), cent, meanEt); - histos.fill(HIST("MCGen/Prof_Mult_MeanEt"), col.multNTracksPV(), meanEt); - } + for (int isp = 0; isp < KNsp; ++isp) { + if (sumWiTruth[isp][ietaA] > 0) { + float val = sumWiptiTruth[isp][ietaA] / sumWiTruth[isp][ietaA]; + histos.fill(HIST("pmeanTru_nch_etabin_spbin"), multPV, ietaA, isp, val); + histos.fill(HIST("pmeanMultTru_nch_etabin_spbin"), multPV, ietaA, isp, sumWiTruth[isp][ietaA]); } - // "MCReco" - if (std::isfinite(sumWiRecoEt[0][0])) { - float meanEt = sumWiptiRecoEt[0][0] / sumWiRecoEt[0][0]; - if (!std::isfinite(meanEt)) - LOGF(info, "meanEtRecoEt = %.3f, num = %.3f, den =%.3f", meanEt, sumWiptiRecoEt[0][0], sumWiRecoEt[0][0]); - if (std::isfinite(meanEt)) { - histos.fill(HIST("MCReco/Prof_Cent_MeanEt"), cent, meanEt); - histos.fill(HIST("MCReco/Prof_Mult_MeanEt"), col.multNTracksPV(), meanEt); - } + if (sumWiReco[isp][ietaA] > 0) { + float val = sumWiptiReco[isp][ietaA] / sumWiReco[isp][ietaA]; + histos.fill(HIST("pmeanReco_nch_etabin_spbin"), multPV, ietaA, isp, val); + histos.fill(HIST("pmeanMultReco_nch_etabin_spbin"), multPV, ietaA, isp, sumWiReco[isp][ietaA]); } - // "MCRecoEffCorr" - if (std::isfinite(sumWiRecoEffCorrEt[0][0])) { - float meanEt = sumWiptiRecoEffCorrEt[0][0] / sumWiRecoEffCorrEt[0][0]; - if (!std::isfinite(meanEt)) - LOGF(info, "meanEtRecoEffcorrEt = %.3f, num = %.3f, den =%.3f", meanEt, sumWiptiRecoEffCorrEt[0][0], sumWiRecoEffCorrEt[0][0]); - if (std::isfinite(meanEt)) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_MeanEt"), cent, meanEt); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_MeanEt"), col.multNTracksPV(), meanEt); - } - } - - for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (std::isfinite(sumWiTruth[ieta][ipt])) - histos.fill(HIST("pmeanTruNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiTruth[ieta][ipt] / sumWiTruth[ieta][ipt]); - if (std::isfinite(sumWiReco[ieta][ipt])) - histos.fill(HIST("pmeanRecoNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiReco[ieta][ipt] / sumWiReco[ieta][ipt]); - if (std::isfinite(sumWiRecoEffCorr[ieta][ipt])) - histos.fill(HIST("pmeanRecoEffcorrNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiRecoEffCorr[ieta][ipt] / sumWiRecoEffCorr[ieta][ipt]); - - if (std::isfinite(sumWiTruthEt[ieta][ipt])) { - histos.fill(HIST("pmeanEtTruNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiTruthEt[ieta][ipt] / sumWiTruthEt[ieta][ipt]); - histos.fill(HIST("pmeanMultTruNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiTruthEt[ieta][ipt]); - } - if (std::isfinite(sumWiRecoEt[ieta][ipt])) { - histos.fill(HIST("pmeanEtRecoNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiRecoEt[ieta][ipt] / sumWiRecoEt[ieta][ipt]); - histos.fill(HIST("pmeanMultRecoNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiRecoEt[ieta][ipt]); - } - if (std::isfinite(sumWiRecoEffCorrEt[ieta][ipt])) { - histos.fill(HIST("pmeanEtRecoEffcorrNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiRecoEffCorrEt[ieta][ipt] / sumWiRecoEffCorrEt[ieta][ipt]); - histos.fill(HIST("pmeanMultRecoEffcorrNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiRecoEffCorrEt[ieta][ipt]); - } - } + if (sumWiRecoEffCorr[isp][ietaA] > 0) { + float val = sumWiptiRecoEffCorr[isp][ietaA] / sumWiRecoEffCorr[isp][ietaA]; + histos.fill(HIST("pmeanRecoEffcorr_nch_etabin_spbin"), multPV, ietaA, isp, val); + histos.fill(HIST("pmeanMultRecoEffcorr_nch_etabin_spbin"), multPV, ietaA, isp, sumWiRecoEffCorr[isp][ietaA]); } - } // end col loop + } + } // end ietaA + + double amplFT0A = 0, amplFT0C = 0; + if (mcCollision.has_foundFT0()) { + const auto& ft0 = mcCollision.foundFT0(); + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + auto chanelid = ft0.channelA()[iCh]; + float ampl = ft0.amplitudeA()[iCh]; + amplFT0A += ampl; + auto eta = getEtaFT0(chanelid, 0); + histos.fill(HIST("pmean_cent_id_eta_FT0"), cent, chanelid, eta, ampl); + histos.fill(HIST("h3_cent_id_eta_FT0"), cent, chanelid, eta, ampl); + } + for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { + auto chanelid = ft0.channelC()[iCh]; + auto globalId = chanelid + KnFt0cCell; + float ampl = ft0.amplitudeC()[iCh]; + auto eta = getEtaFT0(globalId, 1); + amplFT0C += ampl; + histos.fill(HIST("pmean_cent_id_eta_FT0"), cent, globalId, eta, ampl); + histos.fill(HIST("h3_cent_id_eta_FT0"), cent, globalId, eta, ampl); + } } - LOGF(info, "FINISHED RUNNING processMCMean (pT + Et)"); + + histos.fill(HIST("pmeanFT0Amultpv"), multPV, amplFT0A); + histos.fill(HIST("pmeanFT0A_cent"), cent, amplFT0A); + histos.fill(HIST("pmeanFT0Cmultpv"), multPV, amplFT0C); + histos.fill(HIST("pmeanFT0C_cent"), cent, amplFT0C); } - PROCESS_SWITCH(RadialFlowDecorr, processMCMean, "process MC to calculate mean pt/Et and Eff Hists", cfgRunMCMean); + PROCESS_SWITCH(RadialFlowDecorr, processMCMean, "process MC to calculate mean pt and Eff Hists", cfgRunMCMean); - void processMCFluc(aod::McCollisions const& mcColl, MyRun3MCCollisions const& collisions, TCs const& tracks, FilteredTCs const& /*filteredTracks*/, aod::McParticles const& mcParticles) + void processMCFluc(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks, aod::FT0s const&, aod::McParticles const& mcParticles) { - double sumPmwkTru[KNEta][KNpT][KIntM][KIntK]{}; - double sumWkTru[KNEta][KNpT][KIntK]{}; - double sumPmwkReco[KNEta][KNpT][KIntM][KIntK]{}; - double sumWkReco[KNEta][KNpT][KIntK]{}; - double sumPmwkRecoEffCor[KNEta][KNpT][KIntM][KIntK]{}; - double sumWkRecoEffCor[KNEta][KNpT][KIntK]{}; - double sumPmwkTruEt[KNEta][KNpT][KIntM][KIntK]{}; - double sumWkTruEt[KNEta][KNpT][KIntK]{}; - double sumPmwkRecoEt[KNEta][KNpT][KIntM][KIntK]{}; - double sumWkRecoEt[KNEta][KNpT][KIntK]{}; - double sumPmwkRecoEffCorEt[KNEta][KNpT][KIntM][KIntK]{}; - double sumWkRecoEffCorEt[KNEta][KNpT][KIntK]{}; - double meanTru[KNEta][KNpT]{}, c2Tru[KNEta][KNpT]{}; - double meanReco[KNEta][KNpT]{}, c2Reco[KNEta][KNpT]{}; - double meanRecoEffCor[KNEta][KNpT]{}, c2RecoEffCor[KNEta][KNpT]{}; - double meanTruEt[KNEta][KNpT]{}, c2TruEt[KNEta][KNpT]{}; - double meanRecoEt[KNEta][KNpT]{}, c2RecoEt[KNEta][KNpT]{}; - double meanRecoEffCorEt[KNEta][KNpT]{}, c2RecoEffCorEt[KNEta][KNpT]{}; - - double meanTruMult[KNEta][KNpT]{}, covTruEt[KNEta][KNpT]{}; - double meanRecoMult[KNEta][KNpT]{}, covRecoEt[KNEta][KNpT]{}; - double meanRecoEffCorMult[KNEta][KNpT]{}, covRecoEffCorEt[KNEta][KNpT]{}; - - double p1kBarTru[KNEta][KNpT]{}, p1kBarReco[KNEta][KNpT]{}, p1kBarRecoEffCor[KNEta][KNpT]{}; - double p1kBarTruEt[KNEta][KNpT]{}, p1kBarRecoEt[KNEta][KNpT]{}, p1kBarRecoEffCorEt[KNEta][KNpT]{}; - double p1kBarTruMult[KNEta][KNpT]{}, p1kBarRecoMult[KNEta][KNpT]{}, p1kBarRecoEffCorMult[KNEta][KNpT]{}; - - for (const auto& mcCollision : mcColl) { - auto partSlice = mcParticles.sliceBy(partPerMcCollision, mcCollision.globalIndex()); - auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); - if (colSlice.size() != 1) + if (!state.pmeanTruNchEtabinSpbinStep2 || !state.pmeanRecoNchEtabinSpbinStep2 || !state.pmeanRecoEffcorrNchEtabinSpbinStep2 || + !state.pmeanMultTruNchEtabinSpbinStep2 || !state.pmeanMultRecoNchEtabinSpbinStep2 || !state.pmeanMultRecoEffcorrNchEtabinSpbinStep2) { + LOGF(warning, "MC fluc: Unified Mean pT or Mult map missing"); + return; + } + double sumPmwkTru[KNsp][KNEta][KIntM][KIntK]{}; + double sumWkTru[KNsp][KNEta][KIntK]{}; + double sumPmwkReco[KNsp][KNEta][KIntM][KIntK]{}; + double sumWkReco[KNsp][KNEta][KIntK]{}; + double sumPmwkRecoEffCor[KNsp][KNEta][KIntM][KIntK]{}; + double sumWkRecoEffCor[KNsp][KNEta][KIntK]{}; + + double meanTru[KNsp][KNEta]{}, c2Tru[KNsp][KNEta]{}; + double meanReco[KNsp][KNEta]{}, c2Reco[KNsp][KNEta]{}; + double meanRecoEffCor[KNsp][KNEta]{}, c2RecoEffCor[KNsp][KNEta]{}; + + double meanTruMult[KNsp][KNEta]{}; + double meanRecoMult[KNsp][KNEta]{}; + double meanRecoEffCorMult[KNsp][KNEta]{}; + + double p1kBarTru[KNsp][KNEta]{}, p1kBarReco[KNsp][KNEta]{}, p1kBarRecoEffCor[KNsp][KNEta]{}; + double p1kBarTruMult[KNsp][KNEta]{}, p1kBarRecoMult[KNsp][KNEta]{}, p1kBarRecoEffCorMult[KNsp][KNEta]{}; + + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + return; + float cent = getCentrality(mcCollision); + if (cent > KCentMax) + return; + float multPV = mcCollision.multNTracksPV(); + float vz = mcCollision.posZ(); + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) + return; + + histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); + histos.fill(HIST("hCentrality"), cent); + + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), multPV, mcTracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); + + memset(sumPmwkTru, 0, sizeof(sumPmwkTru)); + memset(sumWkTru, 0, sizeof(sumWkTru)); + memset(sumPmwkReco, 0, sizeof(sumPmwkReco)); + memset(sumWkReco, 0, sizeof(sumWkReco)); + memset(sumPmwkRecoEffCor, 0, sizeof(sumPmwkRecoEffCor)); + memset(sumWkRecoEffCor, 0, sizeof(sumWkRecoEffCor)); + + memset(meanTru, 0, sizeof(meanTru)); + memset(c2Tru, 0, sizeof(c2Tru)); + memset(meanReco, 0, sizeof(meanReco)); + memset(c2Reco, 0, sizeof(c2Reco)); + memset(meanRecoEffCor, 0, sizeof(meanRecoEffCor)); + memset(c2RecoEffCor, 0, sizeof(c2RecoEffCor)); + + memset(meanTruMult, 0, sizeof(meanTruMult)); + memset(meanRecoMult, 0, sizeof(meanRecoMult)); + memset(meanRecoEffCorMult, 0, sizeof(meanRecoEffCorMult)); + + memset(p1kBarTru, 0, sizeof(p1kBarTru)); + memset(p1kBarReco, 0, sizeof(p1kBarReco)); + memset(p1kBarRecoEffCor, 0, sizeof(p1kBarRecoEffCor)); + + memset(p1kBarTruMult, 0, sizeof(p1kBarTruMult)); + memset(p1kBarRecoMult, 0, sizeof(p1kBarRecoMult)); + memset(p1kBarRecoEffCorMult, 0, sizeof(p1kBarRecoEffCorMult)); + + double p1kBarFt0A = 0.0, p1kBarFt0C = 0.0; + + for (const auto& particle : mcParticles) { + if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) + continue; + + float pt = particle.pt(); + if (pt <= cfgPtMin || pt > cfgPtMax) continue; - for (const auto& col : colSlice) { + float eta = particle.eta(); + int pdgCode = particle.pdgCode(); + int absPdg = std::abs(pdgCode); + + bool isSpecies[KNsp] = { + true, // kInclusiveIdx + pdgCode == -KPiPlus, // kPiMinusIdx + pdgCode == KPiPlus, // kPiPlusIdx + absPdg == KPiPlus, // kPiAllIdx + pdgCode == -KKPlus, // kKaMinusIdx + pdgCode == KKPlus, // kKaPlusIdx + absPdg == KKPlus, // kKaAllIdx + pdgCode == -KProton, // kAntiPrIdx + pdgCode == KProton, // kPrIdx + absPdg == KProton // kPrAllIdx + }; - auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); - if (trackSlice.size() < 1) + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) continue; + for (int isp = 0; isp < KNsp; ++isp) { + if (isSpecies[isp]) { + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkTru[isp][ieta][m][k] += std::pow(pt, m); + } + sumWkTru[isp][ieta][k]++; + } + } + } + } + } // end truth loop + + for (const auto& track : mcTracks) { + if (!isTrackSelected(track)) + continue; - memset(sumPmwkTru, 0, sizeof(sumPmwkTru)); - memset(sumWkTru, 0, sizeof(sumWkTru)); - memset(sumPmwkReco, 0, sizeof(sumPmwkReco)); - memset(sumWkReco, 0, sizeof(sumWkReco)); - memset(sumPmwkRecoEffCor, 0, sizeof(sumPmwkRecoEffCor)); - memset(sumWkRecoEffCor, 0, sizeof(sumWkRecoEffCor)); - - memset(sumPmwkTruEt, 0, sizeof(sumPmwkTruEt)); - memset(sumWkTruEt, 0, sizeof(sumWkTruEt)); - memset(sumPmwkRecoEt, 0, sizeof(sumPmwkRecoEt)); - memset(sumWkRecoEt, 0, sizeof(sumWkRecoEt)); - memset(sumPmwkRecoEffCorEt, 0, sizeof(sumPmwkRecoEffCorEt)); - memset(sumWkRecoEffCorEt, 0, sizeof(sumWkRecoEffCorEt)); - - memset(meanTru, 0, sizeof(meanTru)); - memset(c2Tru, 0, sizeof(c2Tru)); - memset(meanReco, 0, sizeof(meanReco)); - memset(c2Reco, 0, sizeof(c2Reco)); - memset(meanRecoEffCor, 0, sizeof(meanRecoEffCor)); - memset(c2RecoEffCor, 0, sizeof(c2RecoEffCor)); - - memset(meanTruEt, 0, sizeof(meanTruEt)); - memset(c2TruEt, 0, sizeof(c2TruEt)); - memset(meanRecoEt, 0, sizeof(meanRecoEt)); - memset(c2RecoEt, 0, sizeof(c2RecoEt)); - memset(meanRecoEffCorEt, 0, sizeof(meanRecoEffCorEt)); - memset(c2RecoEffCorEt, 0, sizeof(c2RecoEffCorEt)); - - memset(meanTruMult, 0, sizeof(meanTruMult)); - memset(meanRecoMult, 0, sizeof(meanRecoMult)); - memset(meanRecoEffCorMult, 0, sizeof(meanRecoEffCorMult)); - - memset(covTruEt, 0, sizeof(covTruEt)); - memset(covRecoEt, 0, sizeof(covRecoEt)); - memset(covRecoEffCorEt, 0, sizeof(covRecoEffCorEt)); - - memset(p1kBarTru, 0, sizeof(p1kBarTru)); - memset(p1kBarReco, 0, sizeof(p1kBarReco)); - memset(p1kBarRecoEffCor, 0, sizeof(p1kBarRecoEffCor)); - - memset(p1kBarTruEt, 0, sizeof(p1kBarTruEt)); - memset(p1kBarRecoEt, 0, sizeof(p1kBarRecoEt)); - memset(p1kBarRecoEffCorEt, 0, sizeof(p1kBarRecoEffCorEt)); - - memset(p1kBarTruMult, 0, sizeof(p1kBarTruMult)); - memset(p1kBarRecoMult, 0, sizeof(p1kBarRecoMult)); - memset(p1kBarRecoEffCorMult, 0, sizeof(p1kBarRecoEffCorMult)); - - if (!col.has_mcCollision() || !isEventSelected(col)) + float pt = track.pt(); + if (pt <= cfgPtMin || pt > cfgPtMax) + continue; + float eta = track.eta(); + float phi = track.phi(); + auto sign = track.sign(); + histos.fill(HIST("hPt"), pt); + histos.fill(HIST("hEta"), eta); + histos.fill(HIST("hPhi"), phi); + + int id = identifyTrack(track, cent); + bool isPi = (id == KPidPionOne); + bool isKa = (id == KPidKaonTwo); + bool isPr = (id == KPidProtonThree); + bool isSpecies[KNsp] = { + true, + isPi && sign < 0, isPi && sign > 0, isPi, + isKa && sign < 0, isKa && sign > 0, isKa, + isPr && sign < 0, isPr && sign > 0, isPr}; + + for (int isp = 0; isp < KNsp; ++isp) { + if (!isSpecies[isp]) continue; - float cent = getCentrality(col); - if (cent > KCentMax) + float eff = getEfficiency(multPV, pt, eta, static_cast(isp), 0, cfgEff); + float fake = getEfficiency(multPV, pt, eta, static_cast(isp), 1, cfgEff); + float flatW = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); + float w = flatW * (1.0 - fake) / eff; + + if (!std::isfinite(w) || w <= 0.f || eff <= KFloatEpsilon) continue; - // truth - for (const auto& particle : partSlice) { - if (!isParticleSelected(particle)) - continue; - if (!particle.isPhysicalPrimary()) + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) continue; - float pt = particle.pt(); - float eta = particle.eta(); - float p = particle.p(); - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) { - sumPmwkTru[ieta][ipt][m][k] += std::pow(pt, m); - } - sumWkTru[ieta][ipt][k]++; - } - } - } - const int absPdgId = std::abs(particle.pdgCode()); - const bool isPion = (absPdgId == kPiPlus); - const bool isKaon = (absPdgId == kKPlus); - const bool isProton = (absPdgId == kProton); - if (isPion || isKaon || isProton) { - - float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus - : o2::constants::physics::MassProton; - float energy = std::sqrt(p * p + m * m); - float et = energy * (pt / p); - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) { - sumPmwkTruEt[ieta][ipt][m][k] += std::pow(et, m); - } - sumWkTruEt[ieta][ipt][k]++; - } - } + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkReco[isp][ieta][m][k] += std::pow(1.0, k) * std::pow(pt, m); + sumPmwkRecoEffCor[isp][ieta][m][k] += std::pow(w, k) * std::pow(pt, m); } + sumWkReco[isp][ieta][k] += std::pow(1.0, k); + sumWkRecoEffCor[isp][ieta][k] += std::pow(w, k); } - } // end truth loop + } - for (const auto& track : trackSlice) { - if (!isTrackSelected(track)) - continue; - float pt = track.pt(); - float eta = track.eta(); - float p = track.p(); - float phi = track.phi(); - - float effIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 0, cfgEff); - float fakeIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 1, cfgEff); - float flatWeightIncl = getFlatteningWeight(col.posZ(), track.sign(), pt, eta, phi, kInclusive, cfgFlat); - float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; - if (!std::isfinite(wIncl) || wIncl <= 0.f) - continue; - if (effIncl <= 0 || !std::isfinite(effIncl) || !std::isfinite(fakeIncl) || !std::isfinite(flatWeightIncl)) - continue; + if (isp == kInclusiveIdx) { + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPiMinusIdx) { + histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPiPlusIdx) { + histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPiAllIdx) { + histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kKaMinusIdx) { + histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kKaPlusIdx) { + histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kKaAllIdx) { + histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPrIdx) { + histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kAntiPrIdx) { + histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } else if (isp == kPrAllIdx) { + histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } + } + } // trkslice - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) { - sumPmwkReco[ieta][ipt][m][k] += std::pow(1.0, k) * std::pow(pt, m); - sumPmwkRecoEffCor[ieta][ipt][m][k] += std::pow(wIncl, k) * std::pow(pt, m); - } - sumWkReco[ieta][ipt][k] += std::pow(1.0, k); - sumWkRecoEffCor[ieta][ipt][k] += std::pow(wIncl, k); - } - } - } + for (int ieta = 0; ieta < KNEta; ++ieta) { + const int ibx = state.pmeanTruNchEtabinSpbinStep2->GetXaxis()->FindBin(mcCollision.multNTracksPV()); + const int iby = ieta + 1; + + for (int isp = 0; isp < KNsp; ++isp) { + const int ibz = isp + 1; + + meanTruMult[isp][ieta] = sumWkTru[isp][ieta][1]; + meanRecoMult[isp][ieta] = sumWkReco[isp][ieta][1]; + meanRecoEffCorMult[isp][ieta] = sumWkRecoEffCor[isp][ieta][1]; + + float mmptTru = state.pmeanTruNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + float mmptReco = state.pmeanRecoNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + float mmptRecoEffCor = state.pmeanRecoEffcorrNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + + float mmMultTru = state.pmeanMultTruNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + float mmMultReco = state.pmeanMultRecoNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + float mmMultRecoEffCor = state.pmeanMultRecoEffcorrNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + + if (std::isfinite(mmptTru)) + std::tie(meanTru[isp][ieta], c2Tru[isp][ieta]) = calculateMeanAndC2FromSums(sumPmwkTru[isp][ieta], sumWkTru[isp][ieta], mmptTru); + if (std::isfinite(mmptReco)) + std::tie(meanReco[isp][ieta], c2Reco[isp][ieta]) = calculateMeanAndC2FromSums(sumPmwkReco[isp][ieta], sumWkReco[isp][ieta], mmptReco); + if (std::isfinite(mmptRecoEffCor)) + std::tie(meanRecoEffCor[isp][ieta], c2RecoEffCor[isp][ieta]) = calculateMeanAndC2FromSums(sumPmwkRecoEffCor[isp][ieta], sumWkRecoEffCor[isp][ieta], mmptRecoEffCor); + + if (mmptTru != 0.0f) + p1kBarTru[isp][ieta] = meanTru[isp][ieta] - mmptTru; + if (mmptReco != 0.0f) + p1kBarReco[isp][ieta] = meanReco[isp][ieta] - mmptReco; + if (mmptRecoEffCor != 0.0f) + p1kBarRecoEffCor[isp][ieta] = meanRecoEffCor[isp][ieta] - mmptRecoEffCor; + + if (mmMultTru != 0.0f) + p1kBarTruMult[isp][ieta] = meanTruMult[isp][ieta] - mmMultTru; + if (mmMultReco != 0.0f) + p1kBarRecoMult[isp][ieta] = meanRecoMult[isp][ieta] - mmMultReco; + if (mmMultRecoEffCor != 0.0f) + p1kBarRecoEffCorMult[isp][ieta] = meanRecoEffCorMult[isp][ieta] - mmMultRecoEffCor; + } + } - const bool isPion = selectionPion(track); - const bool isKaon = selectionKaon(track); - const bool isProton = selectionProton(track); - - if (isPion || isKaon || isProton) { - float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus - : o2::constants::physics::MassProton; - float energy = std::sqrt(p * p + m * m); - float et = energy * (pt / p); // E_T = E * sin(theta) - float effPid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 0, cfgEff); - float fakePid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 1, cfgEff); - float flatWeightPid = getFlatteningWeight(col.posZ(), track.sign(), pt, eta, phi, kCombinedPID, cfgFlat); - float wPid = flatWeightPid * (1 - fakePid) / effPid; - if (effPid >= 1 || fakePid >= 1 || !std::isfinite(effPid) || effPid <= KFloatEpsilon || !std::isfinite(fakePid) || !std::isfinite(flatWeightPid)) - continue; - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) { - sumPmwkRecoEt[ieta][ipt][m][k] += std::pow(1.0, k) * std::pow(et, m); - sumPmwkRecoEffCorEt[ieta][ipt][m][k] += std::pow(wPid, k) * std::pow(et, m); - } - sumWkRecoEt[ieta][ipt][k] += std::pow(1.0, k); - sumWkRecoEffCorEt[ieta][ipt][k] += std::pow(wPid, k); - } - } - } - } + double amplFT0A = 0, amplFT0C = 0; + if (mcCollision.has_foundFT0()) { + const auto& ft0 = mcCollision.foundFT0(); + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + float ampl = ft0.amplitudeA()[iCh]; + amplFT0A += ampl; + } + for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { + float ampl = ft0.amplitudeC()[iCh]; + amplFT0C += ampl; + } + } + + for (int isp = 0; isp < KNsp; ++isp) { + for (int ieta = 0; ieta < KNEta; ++ieta) { + histos.fill(HIST("MCGen/Prof_Cent_NEta_Nsp_Nchrec"), cent, ieta, isp, sumWkTru[isp][ieta][1]); + histos.fill(HIST("MCGen/Prof_Mult_NEta_Nsp_Nchrec"), multPV, ieta, isp, sumWkTru[isp][ieta][1]); + + histos.fill(HIST("MCReco/Prof_Cent_NEta_Nsp_Nchrec"), cent, ieta, isp, sumWkReco[isp][ieta][1]); + histos.fill(HIST("MCReco/Prof_Mult_NEta_Nsp_Nchrec"), multPV, ieta, isp, sumWkReco[isp][ieta][1]); + + histos.fill(HIST("MCRecoEffCorr/Prof_Cent_NEta_Nsp_Nchrec"), cent, ieta, isp, sumWkRecoEffCor[isp][ieta][1]); + histos.fill(HIST("MCRecoEffCorr/Prof_Mult_NEta_Nsp_Nchrec"), multPV, ieta, isp, sumWkRecoEffCor[isp][ieta][1]); + + if (sumWkTru[isp][ieta][1] > 1.0f) { + histos.fill(HIST("MCGen/Prof_Cent_NEta_Nsp_MeanpT"), cent, ieta, isp, meanTru[isp][ieta]); + histos.fill(HIST("MCGen/Prof_Mult_NEta_Nsp_MeanpT"), multPV, ieta, isp, meanTru[isp][ieta]); + } + if (sumWkReco[isp][ieta][1] > 1.0f) { + histos.fill(HIST("MCReco/Prof_Cent_NEta_Nsp_MeanpT"), cent, ieta, isp, meanReco[isp][ieta]); + histos.fill(HIST("MCReco/Prof_Mult_NEta_Nsp_MeanpT"), multPV, ieta, isp, meanReco[isp][ieta]); + } + if (sumWkRecoEffCor[isp][ieta][1] > 1.0f) { + histos.fill(HIST("MCRecoEffCorr/Prof_Cent_NEta_Nsp_MeanpT"), cent, ieta, isp, meanRecoEffCor[isp][ieta]); + histos.fill(HIST("MCRecoEffCorr/Prof_Mult_NEta_Nsp_MeanpT"), multPV, ieta, isp, meanRecoEffCor[isp][ieta]); + } + } + } + + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int isp = 0; isp < KNsp; ++isp) { + if (std::isfinite(meanTru[isp][ieta])) { + histos.fill(HIST("MCGen/Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, meanTru[isp][ieta]); + histos.fill(HIST("MCGen/Prof_MeanpT_Mult_etabin_spbin"), multPV, ieta, isp, meanTru[isp][ieta]); + } + if (std::isfinite(c2Tru[isp][ieta])) { + histos.fill(HIST("MCGen/Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2Tru[isp][ieta]); + histos.fill(HIST("MCGen/Prof_C2_Mult_etabin_spbin"), multPV, ieta, isp, c2Tru[isp][ieta]); + } + if (std::isfinite(meanReco[isp][ieta])) { + histos.fill(HIST("MCReco/Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, meanReco[isp][ieta]); + histos.fill(HIST("MCReco/Prof_MeanpT_Mult_etabin_spbin"), multPV, ieta, isp, meanReco[isp][ieta]); + } + if (std::isfinite(c2Reco[isp][ieta])) { + histos.fill(HIST("MCReco/Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2Reco[isp][ieta]); + histos.fill(HIST("MCReco/Prof_C2_Mult_etabin_spbin"), multPV, ieta, isp, c2Reco[isp][ieta]); } + if (std::isfinite(meanRecoEffCor[isp][ieta])) { + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, meanRecoEffCor[isp][ieta]); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Mult_etabin_spbin"), multPV, ieta, isp, meanRecoEffCor[isp][ieta]); + } + if (std::isfinite(c2RecoEffCor[isp][ieta])) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2RecoEffCor[isp][ieta]); + histos.fill(HIST("MCRecoEffCorr/Prof_C2_Mult_etabin_spbin"), multPV, ieta, isp, c2RecoEffCor[isp][ieta]); + } + } + } - // FullEvent calculation for all individual eta ranges - for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - meanTruMult[ieta][ipt] = sumWkTru[ieta][ipt][1]; - meanRecoMult[ieta][ipt] = sumWkReco[ieta][ipt][1]; - meanRecoEffCorMult[ieta][ipt] = sumWkRecoEffCor[ieta][ipt][1]; - - const int ibx = pmeanTruNchEtabinPtbinStep2->GetXaxis()->FindBin(col.multNTracksPV()); - const int iby = ieta + 1; - const int ibz = ipt + 1; - - float mmptTru = pmeanTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmptReco = pmeanRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmptRecoEffCor = pmeanRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmetTru = pmeanEtTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmetReco = pmeanEtRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmetRecoEffCor = pmeanEtRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - - if (std::isfinite(mmptTru)) - std::tie(meanTru[ieta][ipt], c2Tru[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkTru[ieta][ipt], sumWkTru[ieta][ipt], mmptTru); - if (std::isfinite(mmptReco)) - std::tie(meanReco[ieta][ipt], c2Reco[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkReco[ieta][ipt], sumWkReco[ieta][ipt], mmptReco); - if (std::isfinite(mmptRecoEffCor)) - std::tie(meanRecoEffCor[ieta][ipt], c2RecoEffCor[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkRecoEffCor[ieta][ipt], sumWkRecoEffCor[ieta][ipt], mmptRecoEffCor); - - if (std::isfinite(mmetTru)) - std::tie(meanTruEt[ieta][ipt], c2TruEt[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkTruEt[ieta][ipt], sumWkTruEt[ieta][ipt], mmetTru); - if (std::isfinite(mmetReco)) - std::tie(meanRecoEt[ieta][ipt], c2RecoEt[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkRecoEt[ieta][ipt], sumWkRecoEt[ieta][ipt], mmetReco); - if (std::isfinite(mmetRecoEffCor)) - std::tie(meanRecoEffCorEt[ieta][ipt], c2RecoEffCorEt[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkRecoEffCorEt[ieta][ipt], sumWkRecoEffCorEt[ieta][ipt], mmetRecoEffCor); - - //"Truth" - if (std::isfinite(meanTru[ieta][ipt])) { - histos.fill(HIST("MCGen/Prof_Cent_MeanpT_etabin_ptbin"), cent, ieta, ipt, meanTru[ieta][ipt]); - histos.fill(HIST("MCGen/Prof_Mult_MeanpT_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, meanTru[ieta][ipt]); + p1kBarFt0A = amplFT0A - state.pmeanFT0AmultpvStep2->GetBinContent(state.pmeanFT0AmultpvStep2->GetXaxis()->FindBin(multPV)); + p1kBarFt0C = amplFT0C - state.pmeanFT0CmultpvStep2->GetBinContent(state.pmeanFT0CmultpvStep2->GetXaxis()->FindBin(multPV)); + + for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { + int ietaC = KNEta - ietaA; + for (int isp = 0; isp < KNsp; ++isp) { + float c2SubTru = p1kBarTru[isp][ietaA] * p1kBarTru[isp][ietaC]; + float c2SubReco = p1kBarReco[isp][ietaA] * p1kBarReco[isp][ietaC]; + float c2SubRecoEffCor = p1kBarRecoEffCor[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; + + float covTru = p1kBarTruMult[isp][ietaA] * p1kBarTru[isp][ietaC]; + float covReco = p1kBarRecoMult[isp][ietaA] * p1kBarReco[isp][ietaC]; + float covRecoEffCor = p1kBarRecoEffCorMult[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; + + float covFT0ATru = p1kBarFt0A * p1kBarTru[isp][ietaC]; + float covFT0AReco = p1kBarFt0A * p1kBarReco[isp][ietaC]; + float covFT0ARecoEffCor = p1kBarFt0A * p1kBarRecoEffCor[isp][ietaC]; + + float covFT0CTru = p1kBarFt0C * p1kBarTru[isp][ietaA]; + float covFT0CReco = p1kBarFt0C * p1kBarReco[isp][ietaA]; + float covFT0CRecoEffCor = p1kBarFt0C * p1kBarRecoEffCor[isp][ietaA]; + + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2SubTru); + histos.fill(HIST("MCGen/Prof_C2Sub_Mult_etabin_spbin"), multPV, ietaA, isp, c2SubTru); + } + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2SubReco); + histos.fill(HIST("MCReco/Prof_C2Sub_Mult_etabin_spbin"), multPV, ietaA, isp, c2SubReco); + } + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Mult_etabin_spbin"), multPV, ietaA, isp, c2SubRecoEffCor); + } + if (std::isfinite(covTru)) { + histos.fill(HIST("MCGen/Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covTru); + histos.fill(HIST("MCGen/Prof_Cov_Mult_etabin_spbin"), multPV, ietaA, isp, covTru); + } + if (std::isfinite(covReco)) { + histos.fill(HIST("MCReco/Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covReco); + histos.fill(HIST("MCReco/Prof_Cov_Mult_etabin_spbin"), multPV, ietaA, isp, covReco); + } + if (std::isfinite(covRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Mult_etabin_spbin"), multPV, ietaA, isp, covRecoEffCor); + } + + if (std::isfinite(covFT0ATru)) { + histos.fill(HIST("MCGen/Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0ATru); + histos.fill(HIST("MCGen/Prof_CovFT0A_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0ATru); + } + if (std::isfinite(covFT0AReco)) { + histos.fill(HIST("MCReco/Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0AReco); + histos.fill(HIST("MCReco/Prof_CovFT0A_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0AReco); + } + if (std::isfinite(covFT0ARecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0ARecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0ARecoEffCor); + } + + if (std::isfinite(covFT0CTru)) { + histos.fill(HIST("MCGen/Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0CTru); + histos.fill(HIST("MCGen/Prof_CovFT0C_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0CTru); + } + if (std::isfinite(covFT0CReco)) { + histos.fill(HIST("MCReco/Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0CReco); + histos.fill(HIST("MCReco/Prof_CovFT0C_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0CReco); + } + if (std::isfinite(covFT0CRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0CRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0CRecoEffCor); + } + } + } + + for (int ietaA = 1; ietaA < KNEta; ++ietaA) { + for (int ietaC = 1; ietaC < KNEta; ++ietaC) { + + float etaValA = (etaLw[ietaA] + etaUp[ietaA]) / 2.0f; + float etaValB = (etaLw[ietaC] + etaUp[ietaC]) / 2.0f; + float gap = etaValA - etaValB; + float sum = (etaValA + etaValB); + for (int isp = 0; isp < KNsp; ++isp) { + + float c2SubTru = p1kBarTru[isp][ietaA] * p1kBarTru[isp][ietaC]; + float c2SubReco = p1kBarReco[isp][ietaA] * p1kBarReco[isp][ietaC]; + float c2SubRecoEffCor = p1kBarRecoEffCor[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; + + float covTru = p1kBarTruMult[isp][ietaA] * p1kBarTru[isp][ietaC]; + float covReco = p1kBarRecoMult[isp][ietaA] * p1kBarReco[isp][ietaC]; + float covRecoEffCor = p1kBarRecoEffCorMult[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; + + float covFT0ATru = p1kBarFt0A * p1kBarTru[isp][ietaC]; + float covFT0AReco = p1kBarFt0A * p1kBarReco[isp][ietaC]; + float covFT0ARecoEffCor = p1kBarFt0A * p1kBarRecoEffCor[isp][ietaC]; + + float covFT0CTru = p1kBarFt0C * p1kBarTru[isp][ietaA]; + float covFT0CReco = p1kBarFt0C * p1kBarReco[isp][ietaA]; + float covFT0CRecoEffCor = p1kBarFt0C * p1kBarRecoEffCor[isp][ietaA]; + + if (isp == kInclusiveIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D"), cent, gap, sum, c2SubTru); } - if (std::isfinite(meanTruEt[ieta][ipt])) { - histos.fill(HIST("MCGen/Prof_Cent_MeanEt_etabin_ptbin"), cent, ieta, ipt, meanTruEt[ieta][ipt]); - histos.fill(HIST("MCGen/Prof_Mult_MeanEt_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, meanTruEt[ieta][ipt]); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D"), cent, gap, sum, c2SubReco); } - // "MCReco" - if (std::isfinite(meanReco[ieta][ipt])) { - histos.fill(HIST("MCReco/Prof_Cent_MeanpT_etabin_ptbin"), cent, ieta, ipt, meanReco[ieta][ipt]); - histos.fill(HIST("MCReco/Prof_Mult_MeanpT_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, meanReco[ieta][ipt]); + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D"), cent, gap, sum, c2SubRecoEffCor); } - if (std::isfinite(meanRecoEt[ieta][ipt])) { - histos.fill(HIST("MCReco/Prof_Cent_MeanEt_etabin_ptbin"), cent, ieta, ipt, meanRecoEt[ieta][ipt]); - histos.fill(HIST("MCReco/Prof_Mult_MeanEt_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, meanRecoEt[ieta][ipt]); + + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kPiMinusIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_PiMinus"), cent, gap, sum, c2SubTru); } - // "MCRecoEffCor" - if (std::isfinite(meanRecoEffCor[ieta][ipt])) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_MeanpT_etabin_ptbin"), cent, ieta, ipt, meanRecoEffCor[ieta][ipt]); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_MeanpT_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, meanRecoEffCor[ieta][ipt]); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_PiMinus"), cent, gap, sum, c2SubReco); } - if (std::isfinite(meanRecoEffCorEt[ieta][ipt])) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_MeanEt_etabin_ptbin"), cent, ieta, ipt, meanRecoEffCorEt[ieta][ipt]); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_MeanEt_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, meanRecoEffCorEt[ieta][ipt]); + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PiMinus"), cent, gap, sum, c2SubRecoEffCor); } - //"Truth" - if (std::isfinite(c2Tru[ieta][ipt])) { - histos.fill(HIST("MCGen/Prof_Cent_C2_etabin_ptbin"), cent, ieta, ipt, c2Tru[ieta][ipt]); - histos.fill(HIST("MCGen/Prof_C2_Mult_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, c2Tru[ieta][ipt]); + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kPiPlusIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_PiPlus"), cent, gap, sum, c2SubTru); } - if (std::isfinite(c2TruEt[ieta][ipt])) { - histos.fill(HIST("MCGen/Prof_Cent_C2Et_etabin_ptbin"), cent, ieta, ipt, c2TruEt[ieta][ipt]); - histos.fill(HIST("MCGen/Prof_C2Et_Mult_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, c2TruEt[ieta][ipt]); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_PiPlus"), cent, gap, sum, c2SubReco); } - // "MCReco" - if (std::isfinite(c2Reco[ieta][ipt])) { - histos.fill(HIST("MCReco/Prof_Cent_C2_etabin_ptbin"), cent, ieta, ipt, c2Reco[ieta][ipt]); - histos.fill(HIST("MCReco/Prof_C2_Mult_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, c2Reco[ieta][ipt]); + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PiPlus"), cent, gap, sum, c2SubRecoEffCor); } - if (std::isfinite(c2RecoEt[ieta][ipt])) { - histos.fill(HIST("MCReco/Prof_Cent_C2Et_etabin_ptbin"), cent, ieta, ipt, c2RecoEt[ieta][ipt]); - histos.fill(HIST("MCReco/Prof_C2Et_Mult_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, c2RecoEt[ieta][ipt]); + + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kPiAllIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_PiAll"), cent, gap, sum, c2SubTru); } - // "MCRecoEffCor" - if (std::isfinite(c2RecoEffCor[ieta][ipt])) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_C2_etabin_ptbin"), cent, ieta, ipt, c2RecoEffCor[ieta][ipt]); - histos.fill(HIST("MCRecoEffCorr/Prof_C2_Mult_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, c2RecoEffCor[ieta][ipt]); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_PiAll"), cent, gap, sum, c2SubReco); } - if (std::isfinite(c2RecoEffCorEt[ieta][ipt])) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_C2Et_etabin_ptbin"), cent, ieta, ipt, c2RecoEffCorEt[ieta][ipt]); - histos.fill(HIST("MCRecoEffCorr/Prof_C2Et_Mult_etabin_ptbin"), col.multNTracksPV(), ieta, ipt, c2RecoEffCorEt[ieta][ipt]); + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PiAll"), cent, gap, sum, c2SubRecoEffCor); } - } - } - for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - const int ibx = pmeanTruNchEtabinPtbinStep2->GetXaxis()->FindBin(col.multNTracksPV()); - const int iby = ieta + 1; - const int ibz = ipt + 1; - - float mmptTru = pmeanTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmptReco = pmeanRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmptRecoEffCor = pmeanRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmetTru = pmeanEtTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmetReco = pmeanEtRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmetRecoEffCor = pmeanEtRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - - float mmMultTru = pmeanMultTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmMultReco = pmeanMultRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmMultRecoEffCor = pmeanMultRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - - if (mmptTru != 0.0f) - p1kBarTru[ieta][ipt] = meanTru[ieta][ipt] - mmptTru; - if (mmptReco != 0.0f) - p1kBarReco[ieta][ipt] = meanReco[ieta][ipt] - mmptReco; - if (mmptRecoEffCor != 0.0f) - p1kBarRecoEffCor[ieta][ipt] = meanRecoEffCor[ieta][ipt] - mmptRecoEffCor; - - if (mmetTru != 0.0f) - p1kBarTruEt[ieta][ipt] = meanTruEt[ieta][ipt] - mmetTru; - if (mmetReco != 0.0f) - p1kBarRecoEt[ieta][ipt] = meanRecoEt[ieta][ipt] - mmetReco; - if (mmetRecoEffCor != 0.0f) - p1kBarRecoEffCorEt[ieta][ipt] = meanRecoEffCorEt[ieta][ipt] - mmetRecoEffCor; - - if (mmMultTru != 0.0f) - p1kBarTruMult[ieta][ipt] = meanTruMult[ieta][ipt] - mmMultTru; - if (mmMultReco != 0.0f) - p1kBarRecoMult[ieta][ipt] = meanRecoMult[ieta][ipt] - mmMultReco; - if (mmMultRecoEffCor != 0.0f) - p1kBarRecoEffCorMult[ieta][ipt] = meanRecoEffCorMult[ieta][ipt] - mmMultRecoEffCor; - } - } - - for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { - int ietaC = KNEta - ietaA; - for (int ipt = 0; ipt < KNpT; ++ipt) { - float c2Sub_Tru = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; - float c2SubEt_Tru = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; - float c2Sub_Reco = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; - float c2SubEt_Reco = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; - float c2Sub_RecoEffCor = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; - float c2SubEt_RecoEffCor = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; - - float cov_Tru_AC = p1kBarTruMult[ietaA][ipt] * p1kBarTru[ietaC][ipt]; - float cov_Reco_AC = p1kBarRecoMult[ietaA][ipt] * p1kBarReco[ietaC][ipt]; - float cov_RecoEffCor_AC = p1kBarRecoEffCorMult[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; - - float cov_Tru_CA = p1kBarTru[ietaA][ipt] * p1kBarTruMult[ietaC][ipt]; - float cov_Reco_CA = p1kBarReco[ietaA][ipt] * p1kBarRecoMult[ietaC][ipt]; - float cov_RecoEffCor_CA = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCorMult[ietaC][ipt]; - - if (std::isfinite(c2Sub_Tru)) { - histos.fill(HIST("MCGen/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub_Tru); - histos.fill(HIST("MCGen/Prof_C2Sub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2Sub_Tru); + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kKaMinusIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_KaMinus"), cent, gap, sum, c2SubTru); } - - if (std::isfinite(c2SubEt_Tru)) { - histos.fill(HIST("MCGen/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt_Tru); - histos.fill(HIST("MCGen/Prof_C2EtSub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2SubEt_Tru); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_KaMinus"), cent, gap, sum, c2SubReco); + } + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_KaMinus"), cent, gap, sum, c2SubRecoEffCor); } - if (std::isfinite(cov_Tru_AC)) { - histos.fill(HIST("MCGen/Prof_Cov_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, cov_Tru_AC); - histos.fill(HIST("MCGen/Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_Tru_AC); + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kKaPlusIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_KaPlus"), cent, gap, sum, c2SubTru); } - if (std::isfinite(cov_Tru_CA)) { - histos.fill(HIST("MCGen/Prof_Cov_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, cov_Tru_CA); - histos.fill(HIST("MCGen/Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_Tru_CA); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_KaPlus"), cent, gap, sum, c2SubReco); } - - if (std::isfinite(c2Sub_Reco)) { - histos.fill(HIST("MCReco/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub_Reco); - histos.fill(HIST("MCReco/Prof_C2Sub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2Sub_Reco); + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_KaPlus"), cent, gap, sum, c2SubRecoEffCor); } - if (std::isfinite(c2SubEt_Reco)) { - histos.fill(HIST("MCReco/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt_Reco); - histos.fill(HIST("MCReco/Prof_C2EtSub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2SubEt_Reco); + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kKaAllIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_KaAll"), cent, gap, sum, c2SubTru); } - if (std::isfinite(cov_Reco_AC)) { - histos.fill(HIST("MCReco/Prof_Cov_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, cov_Reco_AC); - histos.fill(HIST("MCReco/Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_Reco_AC); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_KaAll"), cent, gap, sum, c2SubReco); } - if (std::isfinite(cov_Reco_CA)) { - histos.fill(HIST("MCReco/Prof_Cov_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, cov_Reco_CA); - histos.fill(HIST("MCReco/Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_Reco_CA); + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_KaAll"), cent, gap, sum, c2SubRecoEffCor); } - if (std::isfinite(c2Sub_RecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub_RecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2Sub_RecoEffCor); + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kPrIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_Pr"), cent, gap, sum, c2SubTru); } - - if (std::isfinite(c2SubEt_RecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt_RecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_C2EtSub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2SubEt_RecoEffCor); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_Pr"), cent, gap, sum, c2SubReco); + } + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_Pr"), cent, gap, sum, c2SubRecoEffCor); } - if (std::isfinite(cov_RecoEffCor_AC)) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, cov_RecoEffCor_AC); - histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_Reco_AC); + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kAntiPrIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_AntiPr"), cent, gap, sum, c2SubTru); } - if (std::isfinite(cov_RecoEffCor_CA)) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, cov_RecoEffCor_CA); - histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_Reco_CA); + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_AntiPr"), cent, gap, sum, c2SubReco); + } + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_AntiPr"), cent, gap, sum, c2SubRecoEffCor); } - } - } - for (int ietaA = 1; ietaA < KNEta; ++ietaA) { - for (int ietaC = 1; ietaC < KNEta; ++ietaC) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - float c2Sub_Tru = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; - float c2SubEt_Tru = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; - float c2Sub_Reco = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; - float c2SubEt_Reco = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; - float c2Sub_RecoEffCor = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; - float c2SubEt_RecoEffCor = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; - float cov_Tru = p1kBarTruMult[ietaA][ipt] * p1kBarTru[ietaC][ipt]; - float cov_Reco = p1kBarRecoMult[ietaA][ipt] * p1kBarReco[ietaC][ipt]; - float cov_RecoEffCor = p1kBarRecoEffCorMult[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; - switch (ipt) { - case 0: - if (std::isfinite(c2Sub_Tru)) - histos.fill(HIST("MCGen/Prof_ipt0_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_Tru); - if (std::isfinite(c2SubEt_Tru)) - histos.fill(HIST("MCGen/Prof_ipt0_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_Tru); - if (std::isfinite(c2Sub_Reco)) - histos.fill(HIST("MCReco/Prof_ipt0_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_Reco); - if (std::isfinite(c2SubEt_Reco)) - histos.fill(HIST("MCReco/Prof_ipt0_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_Reco); - if (std::isfinite(c2Sub_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_RecoEffCor); - if (std::isfinite(c2SubEt_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_RecoEffCor); - - if (std::isfinite(cov_Tru)) - histos.fill(HIST("MCGen/Prof_ipt0_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_Tru); - if (std::isfinite(cov_Reco)) - histos.fill(HIST("MCReco/Prof_ipt0_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_Reco); - if (std::isfinite(cov_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_RecoEffCor); - - break; - case 1: - if (std::isfinite(c2Sub_Tru)) - histos.fill(HIST("MCGen/Prof_ipt1_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_Tru); - if (std::isfinite(c2SubEt_Tru)) - histos.fill(HIST("MCGen/Prof_ipt1_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_Tru); - if (std::isfinite(c2Sub_Reco)) - histos.fill(HIST("MCReco/Prof_ipt1_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_Reco); - if (std::isfinite(c2SubEt_Reco)) - histos.fill(HIST("MCReco/Prof_ipt1_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_Reco); - if (std::isfinite(c2Sub_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_RecoEffCor); - if (std::isfinite(c2SubEt_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_RecoEffCor); - - if (std::isfinite(cov_Tru)) - histos.fill(HIST("MCGen/Prof_ipt1_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_Tru); - if (std::isfinite(cov_Reco)) - histos.fill(HIST("MCReco/Prof_ipt1_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_Reco); - if (std::isfinite(cov_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_RecoEffCor); - - break; - case 2: - if (std::isfinite(c2Sub_Tru)) - histos.fill(HIST("MCGen/Prof_ipt2_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_Tru); - if (std::isfinite(c2SubEt_Tru)) - histos.fill(HIST("MCGen/Prof_ipt2_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_Tru); - if (std::isfinite(c2Sub_Reco)) - histos.fill(HIST("MCReco/Prof_ipt2_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_Reco); - if (std::isfinite(c2SubEt_Reco)) - histos.fill(HIST("MCReco/Prof_ipt2_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_Reco); - if (std::isfinite(c2Sub_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2Sub_RecoEffCor); - if (std::isfinite(c2SubEt_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, c2SubEt_RecoEffCor); - - if (std::isfinite(cov_Tru)) - histos.fill(HIST("MCGen/Prof_ipt2_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_Tru); - if (std::isfinite(cov_Reco)) - histos.fill(HIST("MCReco/Prof_ipt2_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_Reco); - if (std::isfinite(cov_RecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov_RecoEffCor); - - break; - } + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0CRecoEffCor); + + } else if (isp == kPrAllIdx) { + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D_PrAll"), cent, gap, sum, c2SubTru); + } + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D_PrAll"), cent, gap, sum, c2SubReco); } + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PrAll"), cent, gap, sum, c2SubRecoEffCor); + } + + if (std::isfinite(covTru)) + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covTru); + if (std::isfinite(covReco)) + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covReco); + if (std::isfinite(covRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covRecoEffCor); + + if (std::isfinite(covFT0ATru)) + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0ATru); + if (std::isfinite(covFT0AReco)) + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0AReco); + if (std::isfinite(covFT0ARecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0ARecoEffCor); + + if (std::isfinite(covFT0CTru)) + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0CTru); + if (std::isfinite(covFT0CReco)) + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0CReco); + if (std::isfinite(covFT0CRecoEffCor)) + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0CRecoEffCor); } } } } - LOGF(info, "FINISHED RUNNING processMCFluc (pT + Et)"); } - PROCESS_SWITCH(RadialFlowDecorr, processMCFluc, "process MC to calculate pt/Et fluc", cfgRunMCFluc); + PROCESS_SWITCH(RadialFlowDecorr, processMCFluc, "process MC to calculate pt fluc", cfgRunMCFluc); + + void processDataGetNSig(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, AodTracksSel const& tracks) + { + histos.fill(HIST("hVtxZ"), coll.posZ()); + if (!isEventSelected(coll)) + return; + float cent = getCentrality(coll); + if (cent > KCentMax) + return; + histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); + histos.fill(HIST("hCentrality"), cent); + + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, coll.multNTracksPV()); + + int ntrk = 0; + for (const auto& track : tracks) { + if (!isTrackSelected(track)) + continue; + float pt = track.pt(); + if (pt <= cfgPtMin || pt > cfgPtMax) + continue; + float eta = track.eta(); + if (eta > etaLw[0] && eta < etaUp[0]) + ntrk++; + fillNSigmaBefCut(track, cent); + } + + if (cfgZDC) { + const auto& foundBC = coll.foundBC_as(); + if (!foundBC.has_zdc()) { + return; + } + auto zdc = foundBC.zdc(); + auto zdcAmp = zdc.energyCommonZNA() + zdc.energyCommonZNC(); + histos.fill(HIST("hnTrkPVZDC"), coll.multNTracksPV(), zdcAmp); + histos.fill(HIST("hNchZDC"), ntrk, zdcAmp); + } + } + PROCESS_SWITCH(RadialFlowDecorr, processDataGetNSig, "process data to Get Nsigma cuts", cfgRunDataGetNSig); void processGetDataFlat(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, AodTracksSel const& tracks) { @@ -2077,49 +2946,105 @@ struct RadialFlowDecorr { if (cent > KCentMax) return; - histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) + return; + + histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); histos.fill(HIST("hCentrality"), cent); histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, coll.multNTracksPV()); int ntrk = 0; + float vz = coll.posZ(); + for (const auto& track : tracks) { if (!isTrackSelected(track)) continue; - float p = track.p(); float pt = track.pt(); + if (pt <= cfgPtMin || pt > cfgPtMax) + continue; float eta = track.eta(); float phi = track.phi(); - if (p < KFloatEpsilon) - continue; - float effIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 0, cfgEff); - float fakeIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 1, cfgEff); - float wIncl = (1.0 - fakeIncl) / effIncl; - if (!std::isfinite(wIncl) || wIncl <= KFloatEpsilon || effIncl <= KFloatEpsilon) - continue; - histos.fill(HIST("hEtaPhiReco"), coll.posZ(), track.sign(), pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd"), coll.posZ(), track.sign(), pt, eta, phi, wIncl); + auto sign = track.sign(); + + histos.fill(HIST("hPt"), pt); + histos.fill(HIST("hEta"), eta); + histos.fill(HIST("hPhi"), phi); if (eta > etaLw[0] && eta < etaUp[0]) ntrk++; + fillNSigmaBefCut(track, cent); + int id = identifyTrack(track, cent); + bool isPi = (id == KPidPionOne); + bool isKa = (id == KPidKaonTwo); + bool isPr = (id == KPidProtonThree); + bool isSpecies[KNsp] = { + true, + isPi && sign < 0, isPi && sign > 0, isPi, + isKa && sign < 0, isKa && sign > 0, isKa, + isPr && sign < 0, isPr && sign > 0, isPr}; + + fillNSigmaAftCut(track, cent, isSpecies); + for (int isp = 0; isp < KNsp; ++isp) { + if (!isSpecies[isp]) + continue; + float eff = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 0, cfgEff); + if (eff <= KFloatEpsilon) + continue; + + float fake = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 1, cfgEff); + float w = (1.0f - fake) / eff; - const bool isPion = selectionPion(track); - const bool isKaon = selectionKaon(track); - const bool isProton = selectionProton(track); - if (isPion || isKaon || isProton) { - float effPid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 0, cfgEff); - float fakePid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 1, cfgEff); - float wPid = (1.0 - fakePid) / effPid; - if (!std::isfinite(wPid) || wPid <= KFloatEpsilon || effPid <= KFloatEpsilon) + if (!std::isfinite(w) || w <= 0.f) continue; - histos.fill(HIST("hEtaPhiReco_PID"), coll.posZ(), track.sign(), pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PID"), coll.posZ(), track.sign(), pt, eta, phi, wPid); + + if (isp == kInclusiveIdx) { + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiMinusIdx) { + histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiPlusIdx) { + histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiAllIdx) { + histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaMinusIdx) { + histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaPlusIdx) { + histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaAllIdx) { + histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); + } else if (isp == kPrIdx) { + histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); + } else if (isp == kAntiPrIdx) { + histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); + } else if (isp == kPrAllIdx) { + histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); + } } } - histos.fill(HIST("hCentnTrk"), cent, ntrk); - histos.fill(HIST("hCentnTrkPV"), cent, coll.multNTracksPV()); if (cfgZDC) { const auto& foundBC = coll.foundBC_as(); if (!foundBC.has_zdc()) { @@ -2133,10 +3058,10 @@ struct RadialFlowDecorr { } PROCESS_SWITCH(RadialFlowDecorr, processGetDataFlat, "process data to calculate Flattening maps", cfgRunGetDataFlat); - void processDataMean(AodCollisionsSel::iterator const& coll, aod::BCsWithTimestamps const&, AodTracksSel const& tracks) + void processDataMean(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, aod::FT0s const&, AodTracksSel const& tracks) { - float sumWi[KNEta][KNpT]{}, sumWipti[KNEta][KNpT]{}; - float sumWiEt[KNEta][KNpT]{}, sumWiEtVal[KNEta][KNpT]{}; + double sumWi[KNsp][KNEta]{}, sumWipti[KNsp][KNEta]{}; + if (!isEventSelected(coll)) return; @@ -2144,329 +3069,499 @@ struct RadialFlowDecorr { if (cent > KCentMax) return; - histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) + return; + + histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); histos.fill(HIST("hCentrality"), cent); histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, coll.multNTracksPV()); + + float vz = coll.posZ(); for (const auto& track : tracks) { if (!isTrackSelected(track)) continue; + + float p = track.p(); float pt = track.pt(); float eta = track.eta(); - float p = track.p(); float phi = track.phi(); + auto sign = track.sign(); + if (p < KFloatEpsilon) continue; - histos.fill(HIST("hP"), p); - histos.fill(HIST("hPt"), pt); - histos.fill(HIST("hEta"), eta); - histos.fill(HIST("hPhi"), track.phi()); - float effIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 0, cfgEff); - float fakeIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 1, cfgEff); - float flatWeightIncl = getFlatteningWeight(coll.posZ(), track.sign(), pt, eta, phi, kInclusive, cfgFlat); - float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; - if (!std::isfinite(wIncl) || wIncl <= KFloatEpsilon || effIncl <= KFloatEpsilon) + if (pt <= cfgPtMin || pt > cfgPtMax) continue; - histos.fill(HIST("hEtaPhiReco"), coll.posZ(), track.sign(), pt, eta, track.phi()); - histos.fill(HIST("hEtaPhiRecoEffWtd"), coll.posZ(), track.sign(), eta, pt, track.phi(), (1.0 - fakeIncl) / effIncl); - histos.fill(HIST("hEtaPhiRecoWtd"), coll.posZ(), track.sign(), eta, pt, track.phi(), wIncl); - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + histos.fill(HIST("hP"), p); + histos.fill(HIST("hPt"), pt); + histos.fill(HIST("hEta"), eta); + histos.fill(HIST("hPhi"), phi); + int id = identifyTrack(track, cent); + bool isPi = (id == KPidPionOne); + bool isKa = (id == KPidKaonTwo); + bool isPr = (id == KPidProtonThree); + bool isSpecies[KNsp] = { + true, + isPi && sign < 0, isPi && sign > 0, isPi, + isKa && sign < 0, isKa && sign > 0, isKa, + isPr && sign < 0, isPr && sign > 0, isPr}; + + for (int isp = 0; isp < KNsp; ++isp) { + if (!isSpecies[isp]) continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - sumWi[ieta][ipt] += wIncl; - sumWipti[ieta][ipt] += wIncl * pt; - } - } + float eff = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 0, cfgEff); + if (eff <= KFloatEpsilon) + continue; + + float fake = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 1, cfgEff); + float flatWeight = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); + float w = flatWeight * (1.0f - fake) / eff; - const bool isPion = selectionPion(track); - const bool isKaon = selectionKaon(track); - const bool isProton = selectionProton(track); - if (isPion || isKaon || isProton) { - float effPid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 0, cfgEff); - float fakePid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 1, cfgEff); - float flatWeightPid = getFlatteningWeight(coll.posZ(), track.sign(), pt, eta, phi, kCombinedPID, cfgFlat); - float wPid = flatWeightPid * (1.0 - fakePid) / effPid; - if (!std::isfinite(wPid) || wPid <= KFloatEpsilon || effPid <= KFloatEpsilon) + if (!std::isfinite(w) || w <= 0.f) continue; - histos.fill(HIST("hEtaPhiReco_PID"), coll.posZ(), track.sign(), pt, eta, track.phi()); - histos.fill(HIST("hEtaPhiRecoEffWtd_PID"), coll.posZ(), track.sign(), eta, pt, track.phi(), (1.0 - fakePid) / effPid); - histos.fill(HIST("hEtaPhiRecoWtd_PID"), coll.posZ(), track.sign(), eta, pt, track.phi(), wPid); + if (isp == kInclusiveIdx) { + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiMinusIdx) { + histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiPlusIdx) { + histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); + } else if (isp == kPiAllIdx) { + histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaMinusIdx) { + histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaPlusIdx) { + histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); + } else if (isp == kKaAllIdx) { + histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); + } else if (isp == kPrIdx) { + histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); + } else if (isp == kAntiPrIdx) { + histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); + } else if (isp == kPrAllIdx) { + histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); + } - float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus - : o2::constants::physics::MassProton; - float energy = std::sqrt(p * p + m * m); - float et = energy * (pt / p); // E_T = E * sin(theta) for (int ieta = 0; ieta < KNEta; ++ieta) { if (eta <= etaLw[ieta] || eta > etaUp[ieta]) continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - sumWiEt[ieta][ipt] += wPid; - sumWiEtVal[ieta][ipt] += wPid * et; - } + sumWi[isp][ieta] += w; + sumWipti[isp][ieta] += w * pt; } } } - histos.fill(HIST("Prof_cent_Nchrec"), cent, sumWi[0][0]); - if (sumWi[0][0] > 1.0f) - histos.fill(HIST("Prof_Cent_MeanpT"), cent, sumWipti[0][0] / sumWi[0][0]); - if (sumWiEt[0][0] > 1.0f) - histos.fill(HIST("Prof_Cent_MeanEt"), cent, sumWiEtVal[0][0] / sumWiEt[0][0]); - for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (sumWi[ieta][ipt] > 1.0f) { - histos.fill(HIST("pmean_nch_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, sumWipti[ieta][ipt] / sumWi[ieta][ipt]); - histos.fill(HIST("pmeanMult_nch_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, sumWi[ieta][ipt]); - histos.fill(HIST("pmean_cent_etabin_ptbin"), cent, ieta, ipt, sumWipti[ieta][ipt] / sumWi[ieta][ipt]); - histos.fill(HIST("pmeanMult_cent_etabin_ptbin"), cent, ieta, ipt, sumWi[ieta][ipt]); + for (int isp = 0; isp < KNsp; ++isp) { + if (sumWi[isp][0] < 1.0f) + continue; + histos.fill(HIST("Prof_Cent_Nsp_Nchrec"), cent, isp, sumWi[isp][0]); + histos.fill(HIST("Prof_Mult_Nsp_Nchrec"), coll.multNTracksPV(), isp, sumWi[isp][0]); + histos.fill(HIST("Prof_Cent_Nsp_MeanpT"), cent, isp, sumWipti[isp][0] / sumWi[isp][0]); + histos.fill(HIST("Prof_Mult_Nsp_MeanpT"), coll.multNTracksPV(), isp, sumWipti[isp][0] / sumWi[isp][0]); + } + + for (int ietaA = 0; ietaA < KNEta; ++ietaA) { + for (int ietaC = 0; ietaC < KNEta; ++ietaC) { + for (int isp = 0; isp < KNsp; ++isp) { + if ((sumWi[isp][ietaA] < 1.0f) || (sumWi[isp][ietaC] < 1.0f)) + continue; + + double wCorrAB = sumWi[isp][ietaA] + sumWi[isp][ietaC]; + if (wCorrAB > 0) { + float mptsub = (sumWipti[isp][ietaA] + sumWipti[isp][ietaC]) / wCorrAB; + if (isp == kInclusiveIdx) + histos.fill(HIST("Prof2D_MeanpTSub"), cent, ietaA, ietaC, mptsub); + else if (isp == kPiMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_PiMinus"), cent, ietaA, ietaC, mptsub); + else if (isp == kPiPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_PiPlus"), cent, ietaA, ietaC, mptsub); + else if (isp == kPiAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_PiAll"), cent, ietaA, ietaC, mptsub); + else if (isp == kKaMinusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_KaMinus"), cent, ietaA, ietaC, mptsub); + else if (isp == kKaPlusIdx) + histos.fill(HIST("Prof2D_MeanpTSub_KaPlus"), cent, ietaA, ietaC, mptsub); + else if (isp == kKaAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_KaAll"), cent, ietaA, ietaC, mptsub); + else if (isp == kPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_Pr"), cent, ietaA, ietaC, mptsub); + else if (isp == kAntiPrIdx) + histos.fill(HIST("Prof2D_MeanpTSub_AntiPr"), cent, ietaA, ietaC, mptsub); + else if (isp == kPrAllIdx) + histos.fill(HIST("Prof2D_MeanpTSub_PrAll"), cent, ietaA, ietaC, mptsub); + } + if (ietaA == ietaC) { + double mpt = sumWipti[isp][ietaA] / sumWi[isp][ietaA]; + if (sumWi[isp][ietaA] >= 1.0f && std::isfinite(mpt)) { + histos.fill(HIST("pmean_nch_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, mpt); + histos.fill(HIST("pmeanMult_nch_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, sumWi[isp][ietaA]); + histos.fill(HIST("pmean_cent_etabin_spbin"), cent, ietaA, isp, mpt); + histos.fill(HIST("pmeanMult_cent_etabin_spbin"), cent, ietaA, isp, sumWi[isp][ietaA]); + } + } } - if (sumWiEt[ieta][ipt] > 1.0f) - histos.fill(HIST("pmeanEt_nch_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, sumWiEtVal[ieta][ipt] / sumWiEt[ieta][ipt]); - histos.fill(HIST("pmeanEt_cent_etabin_ptbin"), cent, ieta, ipt, sumWiEtVal[ieta][ipt] / sumWiEt[ieta][ipt]); } } + double amplFT0A = 0, amplFT0C = 0; + if (coll.has_foundFT0()) { + const auto& ft0 = coll.foundFT0(); + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + auto chanelid = ft0.channelA()[iCh]; + float ampl = ft0.amplitudeA()[iCh]; + amplFT0A += ampl; + auto eta = getEtaFT0(chanelid, 0); + histos.fill(HIST("pmean_cent_id_eta_FT0"), cent, chanelid, eta, ampl); + histos.fill(HIST("h3_cent_id_eta_FT0"), cent, chanelid, eta, ampl); + } + for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { + auto chanelid = ft0.channelC()[iCh]; + auto globalId = chanelid + KnFt0cCell; + float ampl = ft0.amplitudeC()[iCh]; + auto eta = getEtaFT0(globalId, 1); + amplFT0C += ampl; + histos.fill(HIST("pmean_cent_id_eta_FT0"), cent, globalId, eta, ampl); + histos.fill(HIST("h3_cent_id_eta_FT0"), cent, globalId, eta, ampl); + } + } + + histos.fill(HIST("pmeanFT0Amultpv"), coll.multNTracksPV(), amplFT0A); + histos.fill(HIST("pmeanFT0A_cent"), cent, amplFT0A); + histos.fill(HIST("pmeanFT0Cmultpv"), coll.multNTracksPV(), amplFT0C); + histos.fill(HIST("pmeanFT0C_cent"), cent, amplFT0C); } - PROCESS_SWITCH(RadialFlowDecorr, processDataMean, "process data to calculate mean pT and Et", cfgRunDataMean); + PROCESS_SWITCH(RadialFlowDecorr, processDataMean, "process data to calculate mean pT", cfgRunDataMean); - void processDataFluc(AodCollisionsSel::iterator const& coll, aod::BCsWithTimestamps const&, AodTracksSel const& tracks) + void processDataFluc(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, aod::FT0s const&, AodTracksSel const& tracks) { if (!isEventSelected(coll)) return; float cent = getCentrality(coll); if (cent > KCentMax) return; - if (!pmeanNchEtabinPtbinStep2 || !pmeanEtNchEtabinPtbinStep2 || !pmeanMultNchEtabinPtbinStep2) { - LOGF(warning, "Data fluc: Mean pT or Et map missing"); + + if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) return; - } - if (!hEff[kInclusive] || !hFake[kInclusive] || !hFlatWeight[kInclusive] || !hEff[kCombinedPID] || !hFake[kCombinedPID] || !hFlatWeight[kCombinedPID]) { - LOGF(warning, "Data fluc: Inclusive or PID correction maps are null"); + histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); + histos.fill(HIST("hCentrality"), cent); + + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); + histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); + histos.fill(HIST("Hist2D_PVTracks_cent"), cent, coll.multNTracksPV()); + + if (!state.pmeanNchEtabinSpbinStep2 || !state.pmeanMultNchEtabinSpbinStep2) { + LOGF(warning, "Data fluc: Mean pT or Mult map missing"); return; } - double sumpmwk[KNEta][KNpT][KIntM][KIntK]{}; - double sumwk[KNEta][KNpT][KIntK]{}; - double sumpmwkEt[KNEta][KNpT][KIntM][KIntK]{}; - double sumwkEt[KNEta][KNpT][KIntK]{}; - double mean[KNEta][KNpT]{}, c2[KNEta][KNpT]{}; - double p1kBar[KNEta][KNpT]{}; - double meanEt[KNEta][KNpT]{}, c2Et[KNEta][KNpT]{}; - double p1kBarEt[KNEta][KNpT]{}; - double p1kBarMult[KNEta][KNpT]{}, meanMult[KNEta][KNpT]{}; + + for (int isp = 0; isp < KNsp; ++isp) { + auto pid = static_cast(isp); + if (!state.hEff[pid] || !state.hFake[pid] || !state.hFlatWeight[pid]) { + LOGF(warning, "Data fluc: Correction maps (Eff, Fake, or Flat) are null for species index %d", isp); + return; + } + } + + double sumpmwk[KNsp][KNEta][KIntM][KIntK]{}; + double sumwk[KNsp][KNEta][KIntK]{}; + + double mean[KNsp][KNEta]{}, c2[KNsp][KNEta]{}; + double p1kBar[KNsp][KNEta]{}; + double meanMult[KNsp][KNEta]{}, p1kBarMult[KNsp][KNEta]{}; + + float vz = coll.posZ(); for (const auto& track : tracks) { if (!isTrackSelected(track)) continue; + + float p = track.p(); float pt = track.pt(); float eta = track.eta(); - float p = track.p(); float phi = track.phi(); + auto sign = track.sign(); + if (p < KFloatEpsilon) continue; - float effIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 0, cfgEff); - float fakeIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 1, cfgEff); - float flatWeightIncl = getFlatteningWeight(coll.posZ(), track.sign(), pt, eta, phi, kInclusive, cfgFlat); - float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; - if (!std::isfinite(wIncl) || wIncl <= KFloatEpsilon || effIncl <= KFloatEpsilon) + if (pt <= cfgPtMin || pt > cfgPtMax) continue; - histos.fill(HIST("hEtaPhiReco"), coll.posZ(), track.sign(), pt, eta, track.phi()); - histos.fill(HIST("hEtaPhiRecoEffWtd"), coll.posZ(), track.sign(), eta, pt, track.phi(), (1.0 - fakeIncl) / effIncl); - histos.fill(HIST("hEtaPhiRecoWtd"), coll.posZ(), track.sign(), eta, pt, track.phi(), wIncl); - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + int id = identifyTrack(track, cent); + bool isPi = (id == KPidPionOne); + bool isKa = (id == KPidKaonTwo); + bool isPr = (id == KPidProtonThree); + bool isSpecies[KNsp] = { + true, + isPi && sign < 0, isPi && sign > 0, isPi, + isKa && sign < 0, isKa && sign > 0, isKa, + isPr && sign < 0, isPr && sign > 0, isPr}; + + for (int isp = 0; isp < KNsp; ++isp) { + if (!isSpecies[isp]) continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) - sumpmwk[ieta][ipt][m][k] += std::pow(wIncl, k) * std::pow(pt, m); - sumwk[ieta][ipt][k] += std::pow(wIncl, k); - } - } - } - - const bool isPion = selectionPion(track); - const bool isKaon = selectionKaon(track); - const bool isProton = selectionProton(track); - if (isPion || isKaon || isProton) { - float effPid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 0, cfgEff); - float fakePid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 1, cfgEff); - float flatWeightPid = getFlatteningWeight(coll.posZ(), track.sign(), pt, eta, phi, kCombinedPID, cfgFlat); - float wPid = flatWeightPid * (1.0 - fakePid) / effPid; - if (!std::isfinite(wPid) || wPid <= KFloatEpsilon || effPid <= KFloatEpsilon) + float eff = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 0, cfgEff); + if (eff <= KFloatEpsilon) continue; - histos.fill(HIST("hEtaPhiReco_PID"), coll.posZ(), track.sign(), pt, eta, track.phi()); - histos.fill(HIST("hEtaPhiRecoEffWtd_PID"), coll.posZ(), track.sign(), eta, pt, track.phi(), (1.0 - fakePid) / effPid); - histos.fill(HIST("hEtaPhiRecoWtd_PID"), coll.posZ(), track.sign(), eta, pt, track.phi(), wPid); - float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus - : o2::constants::physics::MassProton; + float fake = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 1, cfgEff); + float flatWeight = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); + float w = flatWeight * (1.0f - fake) / eff; + + if (!std::isfinite(w) || w <= 0.f) + continue; - float energy = std::sqrt(p * p + m * m); - float et = energy * (pt / p); // E_T = E * sin(theta) for (int ieta = 0; ieta < KNEta; ++ieta) { if (eta <= etaLw[ieta] || eta > etaUp[ieta]) continue; - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (pt <= pTLw[ipt] || pt > pTUp[ipt]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) - sumpmwkEt[ieta][ipt][m][k] += std::pow(wPid, k) * std::pow(et, m); - sumwkEt[ieta][ipt][k] += std::pow(wPid, k); + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumpmwk[isp][ieta][m][k] += std::pow(w, k) * std::pow(pt, m); } + sumwk[isp][ieta][k] += std::pow(w, k); } } } } - for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - const int ibx = pmeanNchEtabinPtbinStep2->GetXaxis()->FindBin(coll.multNTracksPV()); - const int iby = ieta + 1; - const int ibz = ipt + 1; - float mmpt = pmeanNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmet = pmeanEtNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - float mmMult = pmeanMultNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); - - mean[ieta][ipt] = sumpmwk[ieta][ipt][1][1] / sumwk[ieta][ipt][1]; - meanEt[ieta][ipt] = sumpmwkEt[ieta][ipt][1][1] / sumwkEt[ieta][ipt][1]; - meanMult[ieta][ipt] = sumwk[ieta][ipt][1]; - if (std::isfinite(mmpt)) { - std::tie(mean[ieta][ipt], c2[ieta][ipt]) = - calculateMeanAndC2FromSums(sumpmwk[ieta][ipt], sumwk[ieta][ipt], mmpt); - p1kBar[ieta][ipt] = mean[ieta][ipt] - mmpt; - } - if (std::isfinite(mmet)) { - std::tie(meanEt[ieta][ipt], c2Et[ieta][ipt]) = - calculateMeanAndC2FromSums(sumpmwkEt[ieta][ipt], sumwkEt[ieta][ipt], mmet); - p1kBarEt[ieta][ipt] = meanEt[ieta][ipt] - mmet; - } - p1kBarMult[ieta][ipt] = meanMult[ieta][ipt] - mmMult; + double amplFT0A = 0, amplFT0C = 0; + if (coll.has_foundFT0()) { + const auto& ft0 = coll.foundFT0(); + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + float ampl = ft0.amplitudeA()[iCh]; + amplFT0A += ampl; + } + for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { + float ampl = ft0.amplitudeC()[iCh]; + amplFT0C += ampl; } } + double p1kBarFt0A = amplFT0A - state.pmeanFT0AmultpvStep2->GetBinContent(state.pmeanFT0AmultpvStep2->GetXaxis()->FindBin(coll.multNTracksPV())); + double p1kBarFt0C = amplFT0C - state.pmeanFT0CmultpvStep2->GetBinContent(state.pmeanFT0CmultpvStep2->GetXaxis()->FindBin(coll.multNTracksPV())); for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (sumwk[ieta][ipt][1] > 1.f) { - histos.fill(HIST("Prof_Cent_MeanpT_etabin_ptbin"), cent, ieta, ipt, mean[ieta][ipt]); - histos.fill(HIST("Prof_Mult_MeanpT_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, mean[ieta][ipt]); - } - if (sumwkEt[ieta][ipt][1] > 1.f) { - histos.fill(HIST("Prof_Cent_MeanEt_etabin_ptbin"), cent, ieta, ipt, meanEt[ieta][ipt]); - histos.fill(HIST("Prof_Mult_MeanEt_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, meanEt[ieta][ipt]); - } - if (std::isfinite(c2[ieta][ipt])) { - histos.fill(HIST("Prof_Cent_C2_etabin_ptbin"), cent, ieta, ipt, c2[ieta][ipt]); - histos.fill(HIST("Prof_Mult_C2_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, c2[ieta][ipt]); - } - if (std::isfinite(c2Et[ieta][ipt])) { - histos.fill(HIST("Prof_Cent_C2Et_etabin_ptbin"), cent, ieta, ipt, c2Et[ieta][ipt]); - histos.fill(HIST("Prof_Mult_C2Et_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, c2Et[ieta][ipt]); + const int ibx = state.pmeanNchEtabinSpbinStep2->GetXaxis()->FindBin(coll.multNTracksPV()); + const int iby = ieta + 1; + + for (int isp = 0; isp < KNsp; ++isp) { + const int ibz = isp + 1; + + float mmpt = state.pmeanNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + float mmMult = state.pmeanMultNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + + mean[isp][ieta] = sumpmwk[isp][ieta][1][1] / sumwk[isp][ieta][1]; + meanMult[isp][ieta] = sumwk[isp][ieta][1]; + + if (std::isfinite(mmpt)) { + std::tie(mean[isp][ieta], c2[isp][ieta]) = calculateMeanAndC2FromSums(sumpmwk[isp][ieta], sumwk[isp][ieta], mmpt); + p1kBar[isp][ieta] = mean[isp][ieta] - mmpt; } + p1kBarMult[isp][ieta] = meanMult[isp][ieta] - mmMult; } } for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - if (std::isfinite(c2[ieta][ipt])) - histos.fill(HIST("Prof_C2_Mult_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, c2[ieta][ipt]); - if (std::isfinite(c2Et[ieta][ipt])) - histos.fill(HIST("Prof_C2Et_Mult_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, c2Et[ieta][ipt]); + for (int isp = 0; isp < KNsp; ++isp) { + if (std::isfinite(mean[isp][ieta])) { + histos.fill(HIST("Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, mean[isp][ieta]); + histos.fill(HIST("Prof_MeanpT_Mult_etabin_spbin"), coll.multNTracksPV(), ieta, isp, mean[isp][ieta]); + } + if (std::isfinite(c2[isp][ieta])) { + histos.fill(HIST("Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2[isp][ieta]); + histos.fill(HIST("Prof_C2_Mult_etabin_spbin"), coll.multNTracksPV(), ieta, isp, c2[isp][ieta]); + } } } for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { int ietaC = KNEta - ietaA; - for (int ipt = 0; ipt < KNpT; ++ipt) { - float c2Sub = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; - float c2SubEt = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; - float cov_AC = p1kBarMult[ietaA][ipt] * p1kBar[ietaC][ipt]; - float cov_CA = p1kBar[ietaA][ipt] * p1kBarMult[ietaC][ipt]; + for (int isp = 0; isp < KNsp; ++isp) { + float c2Sub = p1kBar[isp][ietaA] * p1kBar[isp][ietaC]; + float covAC = p1kBarMult[isp][ietaA] * p1kBar[isp][ietaC]; + float covCA = p1kBar[isp][ietaA] * p1kBarMult[isp][ietaC]; + + float covFT0A = p1kBarFt0A * p1kBar[isp][ietaC]; + float covFT0C = p1kBarFt0C * p1kBar[isp][ietaA]; if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2Sub); - histos.fill(HIST("Prof_C2Sub_Mult_etabin_ptbin"), coll.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2Sub); + histos.fill(HIST("Prof_C2Sub_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, c2Sub); + } + if (std::isfinite(covAC)) { + histos.fill(HIST("Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covAC); + histos.fill(HIST("Prof_Cov_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, covAC); } - if (std::isfinite(c2SubEt)) { - histos.fill(HIST("Prof_C2EtSub_Cent_etabin_ptbin"), cent, ietaA, ipt, c2SubEt); - histos.fill(HIST("Prof_C2EtSub_Mult_etabin_ptbin"), coll.multNTracksPV(), ietaA, ipt, c2SubEt); + if (std::isfinite(covCA)) { + histos.fill(HIST("Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covCA); + histos.fill(HIST("Prof_Cov_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, covCA); } - if (std::isfinite(cov_AC)) { - histos.fill(HIST("Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_AC); - histos.fill(HIST("Prof_Cov_Mult_etabin_ptbin"), coll.multNTracksPV(), ietaA, ipt, cov_AC); + if (std::isfinite(covFT0A)) { + histos.fill(HIST("Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0A); + histos.fill(HIST("Prof_CovFT0A_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, covFT0A); } - if (std::isfinite(cov_CA)) { - histos.fill(HIST("Prof_Cov_Cent_etabin_ptbin"), cent, ietaA, ipt, cov_CA); - histos.fill(HIST("Prof_Cov_Mult_etabin_ptbin"), coll.multNTracksPV(), ietaA, ipt, cov_CA); + if (std::isfinite(covFT0C)) { + histos.fill(HIST("Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0C); + histos.fill(HIST("Prof_CovFT0C_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, covFT0C); } } } for (int ietaA = 1; ietaA < KNEta; ++ietaA) { for (int ietaC = 1; ietaC < KNEta; ++ietaC) { - for (int ipt = 0; ipt < KNpT; ++ipt) { - float covpt = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; - if (std::isfinite(covpt)) { - switch (ipt) { - case 0: - histos.fill(HIST("Prof_ipt0_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, covpt); - break; - case 1: - histos.fill(HIST("Prof_ipt1_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, covpt); - break; - case 2: - histos.fill(HIST("Prof_ipt2_C2Sub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, covpt); - break; - } - } - float covet = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; - if (std::isfinite(covet)) { - switch (ipt) { - case 0: - histos.fill(HIST("Prof_ipt0_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, covet); - break; - case 1: - histos.fill(HIST("Prof_ipt1_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, covet); - break; - case 2: - histos.fill(HIST("Prof_ipt2_C2EtSub2D_Cent_etaA_etaC"), cent, ietaA, ietaC, covet); - break; + float etaValA = (etaLw[ietaA] + etaUp[ietaA]) / 2.0f; + float etaValB = (etaLw[ietaC] + etaUp[ietaC]) / 2.0f; + float gap = etaValA - etaValB; + float sum = (etaValA + etaValB); + + for (int isp = 0; isp < KNsp; ++isp) { + + float c2Sub = p1kBar[isp][ietaA] * p1kBar[isp][ietaC]; + float cov = p1kBarMult[isp][ietaA] * p1kBar[isp][ietaC]; + float covFT0A = p1kBarFt0A * p1kBar[isp][ietaC]; + float covFT0C = p1kBarFt0C * p1kBar[isp][ietaA]; + + if (isp == kInclusiveIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D"), cent, gap, sum, c2Sub); } - } - float cov = p1kBarMult[ietaA][ipt] * p1kBar[ietaC][ipt]; - if (std::isfinite(cov)) { - switch (ipt) { - case 0: - histos.fill(HIST("Prof_ipt0_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov); - break; - case 1: - histos.fill(HIST("Prof_ipt1_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov); - break; - case 2: - histos.fill(HIST("Prof_ipt2_Cov2D_Cent_etaA_etaC"), cent, ietaA, ietaC, cov); - break; + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kPiMinusIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_PiMinus"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kPiPlusIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_PiPlus"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kPiAllIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_PiAll"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kKaMinusIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_KaMinus"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kKaPlusIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_KaPlus"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kKaAllIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_KaAll"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kPrIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_Pr"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kAntiPrIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_AntiPr"), cent, gap, sum, c2Sub); + } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0C); + } else if (isp == kPrAllIdx) { + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D_PrAll"), cent, gap, sum, c2Sub); } + if (std::isfinite(cov)) + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, cov); + if (std::isfinite(covFT0A)) + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0A); + if (std::isfinite(covFT0C)) + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0C); } } } } } - PROCESS_SWITCH(RadialFlowDecorr, processDataFluc, "process data to calculate fluc pT and Et", cfgRunDataFluc); + PROCESS_SWITCH(RadialFlowDecorr, processDataFluc, "process data to calculate fluc pT", cfgRunDataFluc); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/EbyEFluctuations/Tasks/v0ptHadPiKaProt.cxx b/PWGCF/EbyEFluctuations/Tasks/v0ptHadPiKaProt.cxx index 6bdeab9fe76..f79cb80298b 100644 --- a/PWGCF/EbyEFluctuations/Tasks/v0ptHadPiKaProt.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/v0ptHadPiKaProt.cxx @@ -39,6 +39,7 @@ #include "ReconstructionDataFormats/Track.h" #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +69,8 @@ using namespace o2::framework::expressions; static constexpr float LongArrayFloat[3][20] = {{1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {2.1, 2.2, 2.3, -2.1, -2.2, -2.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {3.1, 3.2, 3.3, -3.1, -3.2, -3.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}}; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + struct V0ptHadPiKaProt { // ITS response @@ -74,7 +78,8 @@ struct V0ptHadPiKaProt { // Connect to ccdb Service ccdb; Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable ccdbUrl{"ccdbUrl", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; + Configurable ccdbUrl{"ccdbUrl", "https://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPath{"ccdbPath", "Users/s/swati/PhiWeight", "CCDB path to ccdb object containing phi weight in a 3D histogram"}; enum Particles { PIONS = 0, @@ -115,6 +120,9 @@ struct V0ptHadPiKaProt { Configurable cfgnSigmaCutCombTPCTOF{"cfgnSigmaCutCombTPCTOF", 2.0f, "PID nSigma combined cut for TPC and TOF"}; ConfigurableAxis nchAxis{"nchAxis", {5000, 0.5, 5000.5}, ""}; ConfigurableAxis centAxis{"centAxis", {90, 0., 90.}, "Centrality/Multiplicity percentile bining"}; + ConfigurableAxis nchAxis1{"nchAxis1", {500, 0.5, 500.5}, "Axis for multiplicity of GlobalTracks/PVTracks"}; + ConfigurableAxis nchAxis2{"nchAxis2", {1000, 0.5, 30000.5}, "Axis for multiplicity of FT0A/FT0C/FV0A"}; + ConfigurableAxis nchAxis3{"nchAxis3", {1000, 0.5, 100000.5}, "Axis for multiplicity of FT0A/FT0C/FV0A"}; Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; Configurable cfgCutPtLowerProt{"cfgCutPtLowerProt", 0.2f, "Lower pT cut"}; Configurable cfgCutPtUpper{"cfgCutPtUpper", 10.0f, "Higher pT cut for inclusive hadron analysis"}; @@ -122,7 +130,7 @@ struct V0ptHadPiKaProt { Configurable cfgCutEta{"cfgCutEta", 0.8f, "absolute Eta cut"}; Configurable cfgCutEtaLeft{"cfgCutEtaLeft", 0.8f, "Left end of eta gap"}; Configurable cfgCutEtaRight{"cfgCutEtaRight", 0.8f, "Right end of eta gap"}; - Configurable cfgNSubsample{"cfgNSubsample", 10, "Number of subsamples"}; + Configurable cfgNSubsample{"cfgNSubsample", 20, "Number of subsamples"}; Configurable cfgCentralityChoice{"cfgCentralityChoice", 0, "Which centrality estimator? 0-->FT0C, 1-->FT0A, 2-->FT0M, 3-->FV0A"}; Configurable cfgEvSelkNoSameBunchPileup{"cfgEvSelkNoSameBunchPileup", true, "Pileup removal"}; Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; @@ -133,11 +141,67 @@ struct V0ptHadPiKaProt { Configurable cfgPtCutTOF{"cfgPtCutTOF", 0.3f, "Minimum pt to use TOF N-sigma"}; Configurable> nSigmas{"nSigmas", {LongArrayFloat[0], 3, 6, {"TPC", "TOF", "ITS"}, {"pos_pi", "pos_ka", "pos_pr", "neg_pi", "neg_ka", "neg_pr"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; Configurable cfgUseRun3V2PID{"cfgUseRun3V2PID", true, "True if PID cuts to be used are similar to Run3 v2 PID analysis"}; - + Configurable cfgNbinsV02pt{"cfgNbinsV02pt", 14, "No. of pT bins for v02(pT) analysis"}; + Configurable cfgCutPtMaxForV02{"cfgCutPtMaxForV02", 3.0f, "Max. pT for v02(pT)"}; + Configurable cfgCutEtaWindowB{"cfgCutEtaWindowB", 0.4f, "value of x in |eta| cfgLoadPhiWeights{"cfgLoadPhiWeights", false, "Load phi weights from CCDB to take care of non-uniform acceptance"}; + + // pT dep DCAxy and DCAz cuts + Configurable cfgUsePtDepDCAxy{"cfgUsePtDepDCAxy", true, "Use pt-dependent DCAxy cut"}; + Configurable cfgUsePtDepDCAz{"cfgUsePtDepDCAz", true, "Use pt-dependent DCAz cut"}; + O2_DEFINE_CONFIGURABLE(cfgDCAxyFunc, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"); + O2_DEFINE_CONFIGURABLE(cfgDCAzFunc, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAz cut"); + TF1* fPtDepDCAxy = nullptr; + TF1* fPtDepDCAz = nullptr; + + O2_DEFINE_CONFIGURABLE(cfgUseSmallIonAdditionalEventCut, bool, true, "Use additional event cut on mult correlations for small ions") + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") + O2_DEFINE_CONFIGURABLE(cfgEvSelV0AT0ACut, bool, true, "V0A T0A 5 sigma cut") + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultCentHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCentLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultT0CCutEnabled, bool, false, "Enable Global multiplicity vs T0C centrality cut") + Configurable> cfgMultT0CCutPars{"cfgMultT0CCutPars", std::vector{143.04, -4.58368, 0.0766055, -0.000727796, 2.86153e-06, 23.3108, -0.36304, 0.00437706, -4.717e-05, 1.98332e-07}, "Global multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultPVT0CCutEnabled, bool, false, "Enable PV multiplicity vs T0C centrality cut") + Configurable> cfgMultPVT0CCutPars{"cfgMultPVT0CCutPars", std::vector{195.357, -6.15194, 0.101313, -0.000955828, 3.74793e-06, 30.0326, -0.43322, 0.00476265, -5.11206e-05, 2.13613e-07}, "PV multiplicity vs T0C centrality cut parameter values"}; + + O2_DEFINE_CONFIGURABLE(cfgMultMultPVHighCutFunction, std::string, "[0]+[1]*x + 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultPVLowCutFunction, std::string, "[0]+[1]*x - 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, false, "Enable global multiplicity vs PV multiplicity cut") + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.140809, 0.734344, 2.77495, 0.0165935}, "PV multiplicity vs T0C centrality cut parameter values"}; + + O2_DEFINE_CONFIGURABLE(cfgMultMultV0AHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 4.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ALowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ACutEnabled, bool, false, "Enable global multiplicity vs V0A multiplicity cut") + Configurable> cfgMultMultV0ACutPars{"cfgMultMultV0ACutPars", std::vector{534.893, 184.344, 0.423539, -0.00331436, 5.34622e-06, 871.239, 53.3735, -0.203528, 0.000122758, 5.41027e-07}, "Global multiplicity vs V0A multiplicity cut parameter values"}; + + std::vector multT0CCutPars; + std::vector multPVT0CCutPars; + std::vector multGlobalPVCutPars; + std::vector multMultV0ACutPars; + TF1* fMultPVT0CCutLow = nullptr; + TF1* fMultPVT0CCutHigh = nullptr; + TF1* fMultT0CCutLow = nullptr; + TF1* fMultT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + TF1* fMultMultV0ACutLow = nullptr; + TF1* fMultMultV0ACutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + } cfgFuncParas; + + // Output HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histosAnalysis{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; std::vector>> subSample; + std::vector>> subSampleV02; TRandom3* funRndm = new TRandom3(0); + // Phi weight histograms initialization + TH2F* hWeightPhiFunctionVzEtaPhi = nullptr; + // Filter command*********** Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < cfgCutPtUpper) && (requireGlobalTrackInFilter()) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (aod::track::itsChi2NCl < cfgCutItsChi2NCl) && (nabs(aod::track::dcaZ) < cfgCutTrackDcaZ); @@ -175,6 +239,24 @@ struct V0ptHadPiKaProt { itsNsigmaCut[kKaonLowCut] = nSigmas->getData()[kITS][kKaonLowCut]; itsNsigmaCut[kProtonLowCut] = nSigmas->getData()[kITS][kProtonLowCut]; + // Loading phi weight histograms from CCDB + if (cfgLoadPhiWeights) { + + // Accessing eff histograms + ccdb->setURL(ccdbUrl.value); + // Enabling object caching, otherwise each call goes to the CCDB server + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now, will be replaced by the value of the train creation + // This avoids that users can replace objects **while** a train is running + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + LOGF(info, "Getting object %s", ccdbPath.value.data()); + TList* lst = ccdb->getForTimeStamp(ccdbPath.value, ccdbNoLaterThan.value); + hWeightPhiFunctionVzEtaPhi = reinterpret_cast(lst->FindObject("hWeightPhiFunctionVzEtaPhi")); + if (!hWeightPhiFunctionVzEtaPhi) + LOGF(info, "FATAL!! could not get phi weights---------> check"); + } + // Define axes std::vector ptBin = {0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.5, 4.0, 5.0, 6.0, 8.0, 10.0}; AxisSpec ptAxis = {ptBin, "#it{p}_{T} (GeV/#it{c})"}; @@ -184,18 +266,39 @@ struct V0ptHadPiKaProt { // Add histograms to histogram manager (as in the output object of in AliPhysics) // QA hists + histos.add("hEventStatData", "Data Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); histos.add("hZvtx_after_sel", ";Z (cm)", kTH1F, {{240, -12, 12}}); histos.add("hCentrality", ";centrality (%)", kTH1F, {{90, 0, 90}}); + // before selection + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_PVTracks_beforeSel", "", {HistType::kTH2D, {nchAxis1, nchAxis1}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_centFT0C_beforeSel", "", {HistType::kTH2D, {centAxis, nchAxis1}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_PVTracks_centFT0C_beforeSel", "", {HistType::kTH2D, {centAxis, nchAxis1}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_V0ATracks_beforeSel", "", {HistType::kTH2D, {nchAxis3, nchAxis1}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_T0ATracks_beforeSel", "", {HistType::kTH2D, {nchAxis2, nchAxis1}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_V0ATracks_T0CTracks_beforeSel", "", {HistType::kTH2D, {nchAxis2, nchAxis3}}); + // after selection + if (cfgUseSmallIonAdditionalEventCut) { + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_PVTracks_afterSel", "", {HistType::kTH2D, {nchAxis1, nchAxis1}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_centFT0C_afterSel", "", {HistType::kTH2D, {centAxis, nchAxis1}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_PVTracks_centFT0C_afterSel", "", {HistType::kTH2D, {centAxis, nchAxis1}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_V0ATracks_afterSel", "", {HistType::kTH2D, {nchAxis3, nchAxis1}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_T0ATracks_afterSel", "", {HistType::kTH2D, {nchAxis2, nchAxis1}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_V0ATracks_T0CTracks_afterSel", "", {HistType::kTH2D, {nchAxis2, nchAxis3}}); + } + histos.add("Hist2D_globalTracks_PVTracks", "", {HistType::kTH2D, {nchAxis, nchAxis}}); histos.add("Hist2D_cent_nch", "", {HistType::kTH2D, {nchAxis, centAxis}}); histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.2, 4.}}); histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); histos.add("hPhi", ";#phi", kTH1F, {{100, 0., o2::constants::math::TwoPI}}); histos.add("hEta", ";#eta", kTH1F, {{100, -2.01, 2.01}}); - histos.add("hDcaXY", ";#it{dca}_{XY}", kTH1F, {{1000, -5, 5}}); - histos.add("hDcaZ", ";#it{dca}_{Z}", kTH1F, {{1000, -5, 5}}); + histos.add("hDcaXY", ";#it{dca}_{XY}", kTH1F, {{1000, -0.5, 0.5}}); + histos.add("hDcaZ", ";#it{dca}_{Z}", kTH1F, {{1000, -0.5, 0.5}}); histos.add("hMeanPt", "", kTProfile, {centAxis}); + // phi weight hist for non-uniform acceptance correction + histos.add("h3DVtxZetaPhi", "", kTH3D, {{20, -10, 10}, {16, -0.8, +0.8}, {100, 0., o2::constants::math::TwoPI}}); + // 2D histograms of nSigma // before cut histos.add("h2DnsigmaPionTpcVsPtBeforeCut", "2D hist of nSigmaTPC vs. pT (pion)", kTH2F, {ptAxis, nSigmaAxis}); @@ -244,10 +347,23 @@ struct V0ptHadPiKaProt { histos.add("Prof_Bone_prot", "", {HistType::kTProfile2D, {centAxis, noAxis}}); histos.add("Prof_Btwo_prot", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + // Analysis profile for v02(pT) + histos.add("Prof_XY", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_XYZ_had", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_Z_had", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_XYZ_pi", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_Z_pi", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_XYZ_ka", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_Z_ka", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_XYZ_prot", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_Z_prot", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + // initial array subSample.resize(cfgNSubsample); + subSampleV02.resize(cfgNSubsample); for (int i = 0; i < cfgNSubsample; i++) { subSample[i].resize(20); + subSampleV02[i].resize(9); } for (int i = 0; i < cfgNSubsample; i++) { subSample[i][0] = std::get>(histos.add(Form("subSample_%d/Prof_A_had", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); @@ -273,7 +389,52 @@ struct V0ptHadPiKaProt { subSample[i][17] = std::get>(histos.add(Form("subSample_%d/Prof_D_prot", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); subSample[i][18] = std::get>(histos.add(Form("subSample_%d/Prof_Bone_prot", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); subSample[i][19] = std::get>(histos.add(Form("subSample_%d/Prof_Btwo_prot", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + + subSampleV02[i][0] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_XY", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSampleV02[i][1] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_XYZ_had", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSampleV02[i][2] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_Z_had", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSampleV02[i][3] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_XYZ_pi", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSampleV02[i][4] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_Z_pi", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSampleV02[i][5] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_XYZ_ka", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSampleV02[i][6] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_Z_ka", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSampleV02[i][7] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_XYZ_prot", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSampleV02[i][8] = std::get>(histosAnalysis.add(Form("subSampleV02_%d/Prof_Z_prot", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + } + + if (cfgEvSelMultCorrelation) { + cfgFuncParas.multT0CCutPars = cfgFuncParas.cfgMultT0CCutPars; + cfgFuncParas.multPVT0CCutPars = cfgFuncParas.cfgMultPVT0CCutPars; + cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; + cfgFuncParas.multMultV0ACutPars = cfgFuncParas.cfgMultMultV0ACutPars; + cfgFuncParas.fMultPVT0CCutLow = new TF1("fMultPVT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutLow->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutHigh = new TF1("fMultPVT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutHigh->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultT0CCutLow = new TF1("fMultT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutLow->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutHigh = new TF1("fMultT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutHigh->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultGlobalPVCutLow = new TF1("fMultGlobalPVCutLow", cfgFuncParas.cfgMultMultPVLowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutLow->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutHigh = new TF1("fMultGlobalPVCutHigh", cfgFuncParas.cfgMultMultPVHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultMultV0ACutLow = new TF1("fMultMultV0ACutLow", cfgFuncParas.cfgMultMultV0ALowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutLow->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutHigh->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + cfgFuncParas.fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + if (cfgUsePtDepDCAxy) { + fPtDepDCAxy = new TF1("ptDepDCAxy", Form("%s", cfgDCAxyFunc->c_str()), 0.001, 1000); } + if (cfgUsePtDepDCAz) { + fPtDepDCAz = new TF1("ptDepDCAz", Form("%s", cfgDCAzFunc->c_str()), 0.001, 1000); + } + } // end init //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -444,28 +605,139 @@ struct V0ptHadPiKaProt { return pid; // 0 = not identified, 1 = pion, 2 = kaon, 3 = proton } - // process Data - void process(AodCollisions::iterator const& coll, aod::BCsWithTimestamps const&, AodTracks const& inputTracks) + // additional multiplicity correlation based event selection cuts + template + bool eventSelectedSmallion(TCollision collision, const int multTrk, const float centrality) { + auto multNTracksPV = collision.multNTracksPV(); + + if (cfgEvSelMultCorrelation) { + if (cfgFuncParas.cfgMultPVT0CCutEnabled) { + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(centrality)) + return 0; + } + + if (cfgFuncParas.cfgMultT0CCutEnabled) { + if (multTrk < cfgFuncParas.fMultT0CCutLow->Eval(centrality)) + return 0; + if (multTrk > cfgFuncParas.fMultT0CCutHigh->Eval(centrality)) + return 0; + } + + if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { + if (multTrk < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + return 0; + if (multTrk > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + return 0; + } + + if (cfgFuncParas.cfgMultMultV0ACutEnabled) { + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(multTrk)) + return 0; + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(multTrk)) + return 0; + } + } + + float sigma = 5.0; + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + + return 1; + } + + template + bool eventSelectionDefaultCuts(TCollision coll) + { + histos.fill(HIST("hEventStatData"), 0.5); if (!coll.sel8()) { - return; + return 0; } + + histos.fill(HIST("hEventStatData"), 1.5); if (cfgUseGoodITSLayerAllCut && !(coll.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { - return; + return 0; } + + histos.fill(HIST("hEventStatData"), 2.5); if (cfgEvSelkNoSameBunchPileup && !(coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { - return; + return 0; } + + histos.fill(HIST("hEventStatData"), 3.5); if (cfgEvSelkNoITSROFrameBorder && !(coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { - return; + return 0; } + + histos.fill(HIST("hEventStatData"), 4.5); if (cfgEvSelkNoTimeFrameBorder && !(coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { - return; + return 0; } + + histos.fill(HIST("hEventStatData"), 5.5); if (cfgEvSelUseGoodZvtxFT0vsPV && !(coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))) { + return 0; + } + + histos.fill(HIST("hEventStatData"), 6.5); + return 1; + } + + template + void fillMultCorrPlotsBeforeSel(C const& coll, T const& inputTracks) + { + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_PVTracks_beforeSel"), coll.multNTracksPV(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_centFT0C_beforeSel"), coll.centFT0C(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_PVTracks_centFT0C_beforeSel"), coll.centFT0C(), coll.multNTracksPV()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_V0ATracks_beforeSel"), coll.multFV0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_T0ATracks_beforeSel"), coll.multFT0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_V0ATracks_T0CTracks_beforeSel"), coll.multFT0C(), coll.multFV0A()); + } + + template + void fillMultCorrPlotsAfterSel(C const& coll, T const& inputTracks) + { + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_PVTracks_afterSel"), coll.multNTracksPV(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_centFT0C_afterSel"), coll.centFT0C(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_PVTracks_centFT0C_afterSel"), coll.centFT0C(), coll.multNTracksPV()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_V0ATracks_afterSel"), coll.multFV0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_T0ATracks_afterSel"), coll.multFT0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_V0ATracks_T0CTracks_afterSel"), coll.multFT0C(), coll.multFV0A()); + } + + template + float getPhiWeight(const T& candidate, float vtxz) + { + if (!cfgLoadPhiWeights || !hWeightPhiFunctionVzEtaPhi) { + return 1.0; + } + int bin = hWeightPhiFunctionVzEtaPhi->FindBin(vtxz, candidate.eta(), candidate.phi()); + float weight = hWeightPhiFunctionVzEtaPhi->GetBinContent(bin); + if (!std::isfinite(weight) || weight <= 0) { + return 1.0; + } + return weight; + } + + // process Data + void process(AodCollisions::iterator const& coll, aod::BCsWithTimestamps const&, AodTracks const& inputTracks) + { + if (!eventSelectionDefaultCuts(coll)) { return; } + fillMultCorrPlotsBeforeSel(coll, inputTracks); + + const auto centralityFT0C = coll.centFT0C(); + if (cfgUseSmallIonAdditionalEventCut && !eventSelectedSmallion(coll, inputTracks.size(), centralityFT0C)) + return; + + if (cfgUseSmallIonAdditionalEventCut) { + fillMultCorrPlotsAfterSel(coll, inputTracks); + } + // Centrality double cent = 0.0; if (cfgCentralityChoice == kFT0C) @@ -482,7 +754,7 @@ struct V0ptHadPiKaProt { histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), inputTracks.size()); histos.fill(HIST("Hist2D_cent_nch"), inputTracks.size(), cent); - // Analysis variables + // Analysis variables for v0(pT) int nbinsHad = 20; int nbinsPid = 18; double binsarray[21] = {0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.5, 4.0, 5.0, 6.0, 8.0, 10.0}; @@ -498,6 +770,18 @@ struct V0ptHadPiKaProt { double nSumEtaLeftKa = 0.0; double nSumEtaLeftProt = 0.0; + // Analysis variables for v02(pT) + TH1D* fPtProfileHadInWinB = new TH1D("fPtProfileHadInWinB", "fPtProfileHadInWinB", 20, binsarray); + TH1D* fPtProfilePiInWinB = new TH1D("fPtProfilePiInWinB", "fPtProfilePiInWinB", 20, binsarray); + TH1D* fPtProfileKaInWinB = new TH1D("fPtProfileKaInWinB", "fPtProfileKaInWinB", 20, binsarray); + TH1D* fPtProfileProtInWinB = new TH1D("fPtProfileProtInWinB", "fPtProfileProtInWinB", 20, binsarray); + double nSumInWinB = 0.0; // for Z = f(pT) = n(pT)/N_B in window B + + double nSumInWinA = 0.0; // for X (in window A) to calculate v2^2 + double nSumInWinC = 0.0; // for Y (in window C) to calculate v2^2 + TComplex vecQInWinA = TComplex(0., 0.); + TComplex vecQInWinC = TComplex(0., 0.); + for (const auto& track : inputTracks) { // Loop over tracks if (!track.has_collision()) { @@ -512,6 +796,13 @@ struct V0ptHadPiKaProt { continue; } + if (cfgUsePtDepDCAxy && !(std::abs(track.dcaXY()) < fPtDepDCAxy->Eval(track.pt()))) { + continue; + } + if (cfgUsePtDepDCAz && !(std::abs(track.dcaZ()) < fPtDepDCAz->Eval(track.pt()))) { + continue; + } + histos.fill(HIST("hP"), track.p()); histos.fill(HIST("hPt"), track.pt()); histos.fill(HIST("hEta"), track.eta()); @@ -521,6 +812,7 @@ struct V0ptHadPiKaProt { double trkPt = track.pt(); double trkEta = track.eta(); + double trkPhi = track.phi(); // inclusive charged particles if (track.sign() != 0) { @@ -535,6 +827,33 @@ struct V0ptHadPiKaProt { } } + // fill subevent B for f(pT) in v02(pT) + if (track.sign() != 0 && trkPt < cfgCutPtMaxForV02) { + if (std::abs(trkEta) < cfgCutEtaWindowB) { + fPtProfileHadInWinB->Fill(trkPt); + nSumInWinB += 1.0; + } + } + double phiweight = 1.0; + if (cfgLoadPhiWeights) { + phiweight = getPhiWeight(track, coll.posZ()); + } + // fill subevent C for v2^2 in v02(pT) + if (track.sign() != 0 && trkPt < cfgCutPtMaxForV02) { + histos.fill(HIST("h3DVtxZetaPhi"), coll.posZ(), trkEta, trkPhi); + if (cfgCutEtaWindowB < trkEta && trkEta < 0.8) { + vecQInWinC += phiweight * TComplex(TMath::Cos(2. * trkPhi), TMath::Sin(2. * trkPhi)); + nSumInWinC += phiweight; + } + } + // fill subevent A for v2^2 in v02(pT) + if (track.sign() != 0 && trkPt < cfgCutPtMaxForV02) { + if (-0.8 < trkEta && trkEta < -1.0 * cfgCutEtaWindowB) { + vecQInWinA += phiweight * TComplex(TMath::Cos(2. * trkPhi), TMath::Sin(2. * trkPhi)); + nSumInWinA += phiweight; + } + } + // PID QAs before selection double nSigmaTpcPi = track.tpcNSigmaPi(); double nSigmaTpcKa = track.tpcNSigmaKa(); @@ -607,6 +926,21 @@ struct V0ptHadPiKaProt { } } + // fill subevent B for ***identified particles'*** f(pT) in v02(pT) + if (track.sign() != 0 && trkPt < cfgCutPtMaxForV02) { + if (std::abs(trkEta) < cfgCutEtaWindowB) { + if (isPion) { + fPtProfilePiInWinB->Fill(trkPt); + } + if (isKaon) { + fPtProfileKaInWinB->Fill(trkPt); + } + if (isProton && trkPt > cfgCutPtLowerProt) { + fPtProfileProtInWinB->Fill(trkPt); + } + } + } + } // End track loop // selecting subsample and filling profiles @@ -676,11 +1010,68 @@ struct V0ptHadPiKaProt { } } + if (nSumInWinA > 4 && nSumInWinB > 4 && nSumInWinC > 4) { + double twoParCorr = (vecQInWinA * TComplex::Conjugate(vecQInWinC)).Re(); + twoParCorr *= 1.0 / (nSumInWinA * nSumInWinC); + histos.get(HIST("Prof_XY"))->Fill(cent, 0.5, twoParCorr); + + subSampleV02[sampleIndex][0]->Fill(cent, 0.5, twoParCorr); + + // hadrons + for (int i = 0; i < cfgNbinsV02pt; i++) { + double threeParCorrHad = (vecQInWinA * TComplex::Conjugate(vecQInWinC) * fPtProfileHadInWinB->GetBinContent(i + 1)).Re(); + threeParCorrHad *= 1.0 / (nSumInWinA * nSumInWinC * nSumInWinB); + histos.get(HIST("Prof_XYZ_had"))->Fill(cent, fPtProfileHadInWinB->GetBinCenter(i + 1), threeParCorrHad); + histos.get(HIST("Prof_Z_had"))->Fill(cent, fPtProfileHadInWinB->GetBinCenter(i + 1), (fPtProfileHadInWinB->GetBinContent(i + 1) / nSumInWinB)); + + subSampleV02[sampleIndex][1]->Fill(cent, fPtProfileHadInWinB->GetBinCenter(i + 1), threeParCorrHad); + subSampleV02[sampleIndex][2]->Fill(cent, fPtProfileHadInWinB->GetBinCenter(i + 1), (fPtProfileHadInWinB->GetBinContent(i + 1) / nSumInWinB)); + } + + // pions + for (int i = 0; i < cfgNbinsV02pt; i++) { + double threeParCorrPi = (vecQInWinA * TComplex::Conjugate(vecQInWinC) * fPtProfilePiInWinB->GetBinContent(i + 1)).Re(); + threeParCorrPi *= 1.0 / (nSumInWinA * nSumInWinC * nSumInWinB); + histos.get(HIST("Prof_XYZ_pi"))->Fill(cent, fPtProfilePiInWinB->GetBinCenter(i + 1), threeParCorrPi); + histos.get(HIST("Prof_Z_pi"))->Fill(cent, fPtProfilePiInWinB->GetBinCenter(i + 1), (fPtProfilePiInWinB->GetBinContent(i + 1) / nSumInWinB)); + + subSampleV02[sampleIndex][3]->Fill(cent, fPtProfilePiInWinB->GetBinCenter(i + 1), threeParCorrPi); + subSampleV02[sampleIndex][4]->Fill(cent, fPtProfilePiInWinB->GetBinCenter(i + 1), (fPtProfilePiInWinB->GetBinContent(i + 1) / nSumInWinB)); + } + + // kaons + for (int i = 0; i < cfgNbinsV02pt; i++) { + double threeParCorrKa = (vecQInWinA * TComplex::Conjugate(vecQInWinC) * fPtProfileKaInWinB->GetBinContent(i + 1)).Re(); + threeParCorrKa *= 1.0 / (nSumInWinA * nSumInWinC * nSumInWinB); + histos.get(HIST("Prof_XYZ_ka"))->Fill(cent, fPtProfileKaInWinB->GetBinCenter(i + 1), threeParCorrKa); + histos.get(HIST("Prof_Z_ka"))->Fill(cent, fPtProfileKaInWinB->GetBinCenter(i + 1), (fPtProfileKaInWinB->GetBinContent(i + 1) / nSumInWinB)); + + subSampleV02[sampleIndex][5]->Fill(cent, fPtProfileKaInWinB->GetBinCenter(i + 1), threeParCorrKa); + subSampleV02[sampleIndex][6]->Fill(cent, fPtProfileKaInWinB->GetBinCenter(i + 1), (fPtProfileKaInWinB->GetBinContent(i + 1) / nSumInWinB)); + } + + // protons + for (int i = 1; i < cfgNbinsV02pt; i++) { + double threeParCorrProt = (vecQInWinA * TComplex::Conjugate(vecQInWinC) * fPtProfileProtInWinB->GetBinContent(i + 1)).Re(); + threeParCorrProt *= 1.0 / (nSumInWinA * nSumInWinC * nSumInWinB); + histos.get(HIST("Prof_XYZ_prot"))->Fill(cent, fPtProfileProtInWinB->GetBinCenter(i + 1), threeParCorrProt); + histos.get(HIST("Prof_Z_prot"))->Fill(cent, fPtProfileProtInWinB->GetBinCenter(i + 1), (fPtProfileProtInWinB->GetBinContent(i + 1) / nSumInWinB)); + + subSampleV02[sampleIndex][7]->Fill(cent, fPtProfileProtInWinB->GetBinCenter(i + 1), threeParCorrProt); + subSampleV02[sampleIndex][8]->Fill(cent, fPtProfileProtInWinB->GetBinCenter(i + 1), (fPtProfileProtInWinB->GetBinContent(i + 1) / nSumInWinB)); + } + } + fPtProfileHad->Delete(); fPtProfilePi->Delete(); fPtProfileKa->Delete(); fPtProfileProt->Delete(); + fPtProfileHadInWinB->Delete(); + fPtProfilePiInWinB->Delete(); + fPtProfileKaInWinB->Delete(); + fPtProfileProtInWinB->Delete(); + } // End process loop }; diff --git a/PWGCF/Femto/Core/baseSelection.h b/PWGCF/Femto/Core/baseSelection.h index ceb2184a96a..fcce0c11c13 100644 --- a/PWGCF/Femto/Core/baseSelection.h +++ b/PWGCF/Femto/Core/baseSelection.h @@ -40,9 +40,9 @@ namespace o2::analysis::femto /// It evaluates which selections are fulfilled, assembles a final bitmask, and tracks required vs. optional cuts. /// /// \tparam T Type of observable values (mostly floats). -/// \tparam BitmaskType Type used for internal bitmask operations (e.g., uint32_t, uint64_t). +/// \tparam BitmaskType Integer type used for bitmask operations (e.g., uint32_t, uint64_t). /// \tparam NumObservables Total number of observables handled. -template +template class BaseSelection { public: @@ -53,57 +53,41 @@ class BaseSelection virtual ~BaseSelection() = default; /// \brief Add a static-value based selection for a specific observable. - /// \param selectionValues Vector of threshold values. /// \param observableIndex Index of the observable. + /// \param selectionName Name of the selection. + /// \param selectionValues Vector of threshold values. /// \param limitType Type of limit (from limits::LimitType). - /// \param skipMostPermissiveBit Whether to skip the loosest threshold in the bitmask. - /// \param isMinimalCut Whether this cut is mandatory or optional. + /// \param skipMostPermissiveBit Whether to skip the loosest threshold when assembling the bitmask. + /// \param isMinimalCut Whether this cut is mandatory (must be passed for the candidate to be accepted). + /// \param isOptionalCut Whether this cut is optional (candidate is accepted if any optional cut passes). void addSelection(int observableIndex, std::string const& selectionName, std::vector const& selectionValues, limits::LimitType limitType, bool skipMostPermissiveBit, bool isMinimalCut, - bool isOptionCut) + bool isOptionalCut) { // check index - if (static_cast(observableIndex) >= NumObservables) { + if (static_cast(observableIndex) >= NumObservables) { LOG(fatal) << "Observable is not valid. Observable (index) has to be smaller than " << NumObservables; } // init selection container for selection at given index - mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, selectionValues, limitType, skipMostPermissiveBit, isMinimalCut, isOptionCut); - - // check if any selections are configured - if (mSelectionContainers.at(observableIndex).isEmpty()) { - return; - } - - // keep track of selections and bits - mNSelectionBits += mSelectionContainers.at(observableIndex).getShift(); - mNSelection += mSelectionContainers.at(observableIndex).getNSelections(); + mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, selectionValues, limitType, skipMostPermissiveBit, isMinimalCut, isOptionalCut); - if (mNSelectionBits > sizeof(BitmaskType) * CHAR_BIT) { - LOG(fatal) << "Too many selections. At most " << sizeof(BitmaskType) * CHAR_BIT << " number of bits are supported"; - } - // check if any selection is minimal - if (mSelectionContainers.at(observableIndex).isMinimalCut()) { - mHasMinimalSelection = true; - } - // check if selection is optional - if (mSelectionContainers.at(observableIndex).isOptionalCut()) { - mHasOptionalSelection = true; - } + init(observableIndex); } /// \brief Add a function-based selection for a specific observable. - /// \param baseName Base name for TF1 functions. - /// \param lowerLimit Lower bound for the TF1 domain. - /// \param upperLimit Upper bound for the TF1 domain. - /// \param selectionValues Function definitions as strings. /// \param observableIndex Index of the observable. - /// \param limitType Type of limit. - /// \param skipMostPermissiveBit Whether to skip the loosest threshold in the bitmask. - /// \param isMinimalCut Whether this cut is mandatory or optional. + /// \param selectionName Name of the selection. + /// \param lowerLimit Lower bound of the TF1 domain. + /// \param upperLimit Upper bound of the TF1 domain. + /// \param functions Selection threshold functions as strings (parsed as TF1 expressions). + /// \param limitType Type of limit (from limits::LimitType). + /// \param skipMostPermissiveBit Whether to skip the loosest threshold when assembling the bitmask. + /// \param isMinimalCut Whether this cut is mandatory (must be passed for the candidate to be accepted). + /// \param isOptionalCut Whether this cut is optional (candidate is accepted if any optional cut passes). void addSelection(int observableIndex, std::string const& selectionName, T lowerLimit, @@ -114,73 +98,75 @@ class BaseSelection bool isMinimalCut, bool isOptionalCut) { - if (static_cast(observableIndex) >= NumObservables) { + if (static_cast(observableIndex) >= NumObservables) { LOG(fatal) << "Observable is not valid. Observable (index) has to be smaller than " << NumObservables; } mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, lowerLimit, upperLimit, functions, limitType, skipMostPermissiveBit, isMinimalCut, isOptionalCut); - // check if any selections are configured - if (mSelectionContainers.at(observableIndex).isEmpty()) { - return; - } - - // advance mNSelections so we can use it as offset for next selection - mNSelectionBits += mSelectionContainers.at(observableIndex).getShift(); - mNSelection += mSelectionContainers.at(observableIndex).getNSelections(); + init(observableIndex); + } - if (mNSelectionBits > sizeof(BitmaskType) * CHAR_BIT) { - LOG(fatal) << "Too many selections. At most " << sizeof(BitmaskType) * CHAR_BIT << " are supported"; - } - // keep track of selection selections - // check if any cut is minimal - if (mSelectionContainers.at(observableIndex).isMinimalCut()) { - mHasMinimalSelection = true; - } - // check if any selection is optional - if (mSelectionContainers.at(observableIndex).isOptionalCut()) { - mHasOptionalSelection = true; + /// \brief Add a static-value based selection for a specific observable. + /// \param observableIndex Index of the observable. + /// \param selectionName Name of the selection. + /// \param selectionValues Vector of threshold values. + /// \param limitType Type of limit (from limits::LimitType). + /// \param skipMostPermissiveBit Whether to skip the loosest threshold when assembling the bitmask. + /// \param isMinimalCut Whether this cut is mandatory (must be passed for the candidate to be accepted). + /// \param isOptionalCut Whether this cut is optional (candidate is accepted if any optional cut passes). + void addSelection(int observableIndex, + std::string const& selectionName, + std::vector const& selectionRanges, + bool skipMostPermissiveBit, + bool isMinimalCut, + bool isOptionalCut) + { + // check index + if (static_cast(observableIndex) >= NumObservables) { + LOG(fatal) << "Observable is not valid. Observable (index) has to be smaller than " << NumObservables; } + // init selection container for selection at given index + mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, selectionRanges, skipMostPermissiveBit, isMinimalCut, isOptionalCut); + + init(observableIndex); } - /// \brief Add a boolean based selection for a specific observable. - /// \param mode Whether the selection is not applied, minimal or optional cut + /// \brief Add a boolean-based selection for a specific observable. /// \param observableIndex Index of the observable. + /// \param selectionName Name of the selection. + /// \param mode Controls how the cut is applied: + /// -1 = optional cut, bit is stored in bitmask; + /// 0 = cut is disabled, no bit stored; + /// 1 = minimal (mandatory) cut, no extra bit stored since only one threshold exists. void addSelection(int observableIndex, std::string const& selectionName, int mode) { switch (mode) { - case -1: // cut is optional and we store bit for the cut + case -1: // cut is optional and we store a bit for it mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, std::vector{1}, limits::LimitType::kEqual, false, false, true); - mHasOptionalSelection = true; - mNSelectionBits += 1; - mNSelection += 1; break; - case 0: // cut is not applied, initalize with empty vector, so we bail out later + case 0: // cut is disabled; initialize with empty vector so evaluation bails out early mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, std::vector{}, limits::LimitType::kEqual, false, false, false); break; - case 1: // cut is added as mininal selection (since it is only one value, no extra bit is stored) + case 1: // mandatory cut; only one threshold so the most permissive bit is skipped and no extra bit is stored mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, std::vector{1}, limits::LimitType::kEqual, true, true, false); - mHasMinimalSelection = true; - mNSelection += 1; break; default: LOG(fatal) << "Invalid switch for boolean selection"; } - if (mNSelectionBits > sizeof(BitmaskType) * CHAR_BIT) { - LOG(fatal) << "Too many selections. At most " << sizeof(BitmaskType) * CHAR_BIT << " are supported"; - } + init(observableIndex); } /// \brief Update the limits of a function-based selection for a specific observable. /// \param observable Index of the observable. - /// \param value Value at which to evaluate the selection functions. + /// \param value Value at which to re-evaluate the selection functions. void updateLimits(int observable, T value) { mSelectionContainers.at(observable).updateLimits(value); } - /// \brief Reset the internal bitmask and evaluation flags before evaluating a new event. + /// \brief Reset the internal bitmask and evaluation flags before processing a new candidate. void reset() { mFinalBitmask.reset(); @@ -195,6 +181,8 @@ class BaseSelection } } + /// \brief Reset the selection container for a single observable. + /// \param observableIndex Index of the observable to reset. void reset(int observableIndex) { mSelectionContainers.at(observableIndex).reset(); } /// \brief Evaluate a single observable against its configured selections. @@ -206,22 +194,20 @@ class BaseSelection if (mSelectionContainers.at(observableIndex).isEmpty()) { return; } - // if any previous observable did not pass minimal selections, there is no point in setting bitmask for other observables - // minimal selection for each observable is computed after adding it + // if a previous observable already failed a minimal selection, + // there is no point in evaluating further observables if (!mPassesMinimalSelections) { return; } // set bitmask for given observable mSelectionContainers.at(observableIndex).evaluate(value); - // check if minimal selction for this observable holds - // if one minimal selection is not fullfilled, the condition failes + // if any minimal selection is not fulfilled, the candidate is rejected if (mHasMinimalSelection) { if (!mSelectionContainers.at(observableIndex).passesAsMinimalCut()) { mPassesMinimalSelections = false; } } - // check if any optional selection holds - // if one optional selection is fullfilled, the condition succeeds + // if any optional selection is fulfilled, the candidate is accepted if (mHasOptionalSelection) { if (mSelectionContainers.at(observableIndex).passesAsOptionalCut()) { mPassesOptionalSelections = true; @@ -231,39 +217,41 @@ class BaseSelection /// \brief Evaluate a single observable against its configured selections. /// \param observableIndex Index of the observable. - /// \param values vector of values of the observable. + /// \param values Vector of values of the observable. void evaluateObservable(int observableIndex, std::vector values) { // if there are no selections configured, bail out if (mSelectionContainers.at(observableIndex).isEmpty()) { return; } - // if any previous observable did not pass minimal selections, there is no point in setting bitmask for other observables - // minimal selection for each observable is computed after adding it + // if a previous observable already failed a minimal selection, + // there is no point in evaluating further observables if (!mPassesMinimalSelections) { return; } // set bitmask for given observable mSelectionContainers.at(observableIndex).evaluate(values); - // check if minimal selction for this observable holds + // if any minimal selection is not fulfilled, the candidate is rejected if (mHasMinimalSelection) { - if (mSelectionContainers.at(observableIndex).passesAsMinimalCut() == false) { + if (!mSelectionContainers.at(observableIndex).passesAsMinimalCut()) { mPassesMinimalSelections = false; } } - // check if any optional selection holds + // if any optional selection is fulfilled, the candidate is accepted if (mHasOptionalSelection) { - if (mSelectionContainers.at(observableIndex).passesAsOptionalCut() == true) { + if (mSelectionContainers.at(observableIndex).passesAsOptionalCut()) { mPassesOptionalSelections = true; } } } - /// \brief Add comments to specific observabel + /// \brief Add comments to the selections of a specific observable. + /// \param observableIndex Index of the observable. + /// \param comments Vector of comment strings, one per selection threshold. void addComments(int observableIndex, std::vector const& comments) { mSelectionContainers.at(observableIndex).addComments(comments); } - /// \brief Check if all required (minimal) and optional cuts are passed. - /// \return True if all required and at least one optional cut (if present) is passed. + /// \brief Check whether all required and optional cuts are passed. + /// \return True if all minimal cuts pass and, if optional cuts are present, at least one of them passes. bool passesAllRequiredSelections() const { if (mHasMinimalSelection && !mHasOptionalSelection) { @@ -275,23 +263,25 @@ class BaseSelection if (mHasMinimalSelection && mHasOptionalSelection) { return mPassesMinimalSelections && mPassesOptionalSelections; } + // if there are no minimal or optional selections, we pass let it pass with true return true; } - /// \brief Check if the optional selection for a specific observable is passed. + /// \brief Check whether the optional selection for a specific observable is passed. /// \param observableIndex Index of the observable. - /// \return True if at least one optional selection is fulfilled. + /// \return True if at least one optional selection for this observable is fulfilled. bool passesOptionalSelection(int observableIndex) const { return mSelectionContainers.at(observableIndex).passesAsOptionalCut(); } - /// \brief Assemble the global selection bitmask from individual observable selections. + /// \brief Assemble the global selection bitmask from all individual observable selections. + /// \tparam HistName Name of the histogram used to track selection statistics. template void assembleBitmask() { mHistRegistry->fill(HIST(HistName), mNSelection); - // if the required selections are not passed, we can break early + // if the required selections are not passed, clear the bitmask and return early if (!this->passesAllRequiredSelections()) { mFinalBitmask.reset(); return; @@ -299,17 +289,16 @@ class BaseSelection mHistRegistry->fill(HIST(HistName), mNSelection + 1); int binCenter = 0; - // to assemble bitmask, convert all bitmask into integers - // shift the current one and add the new bits + // assemble the final bitmask by shifting each container's bitmask to its offset and OR-ing it in for (auto const& selectionContainer : mSelectionContainers) { - // if there are no selections for a certain observable, skip + // skip observables with no configured selections if (selectionContainer.isEmpty()) { continue; } - // Shift the result to its offset and add the new values + // shift the container's bitmask to its offset and merge mFinalBitmask |= (selectionContainer.getBitmask() << selectionContainer.getOffset()); - for (int j = 0; j < selectionContainer.getNSelections(); ++j) { + for (std::size_t j = 0; j < selectionContainer.getNSelections(); ++j) { if (j == 0 && selectionContainer.isMinimalCut()) { // minimal cuts are always filled mHistRegistry->fill(HIST(HistName), binCenter); @@ -325,28 +314,36 @@ class BaseSelection } /// \brief Retrieve the assembled bitmask as an integer value. - /// \return The combined selection bitmask. + /// \return The combined selection bitmask for all observables. BitmaskType getBitmask() const { return static_cast(mFinalBitmask.to_ullong()); } - /// \brief Retrieve the assembled bitmask as an integer value. - /// \return The combined selection bitmask. + /// \brief Retrieve the bitmask for a single observable as an integer value. + /// \param observableIndex Index of the observable. + /// \return The selection bitmask for the specified observable. BitmaskType getBitmask(int observableIndex) const { return static_cast(mSelectionContainers.at(observableIndex).getBitmask().to_ullong()); } - /// \brief Set the assembled bitmask for on observable - /// \return The combined selection bitmask. + /// \brief Manually set the bitmask for a specific observable. + /// \tparam R Integer type of the bitmask value. + /// \param observableIndex Index of the observable. + /// \param bitmask Bitmask value to set. template void setBitmask(int observableIndex, R bitmask) { mSelectionContainers.at(observableIndex).setBitmask(bitmask); } + /// \brief Retrieve the loosest (most permissive) selection threshold for a specific observable. + /// \param observableIndex Index of the observable. + /// \return The loosest threshold value configured for this observable. T getLoosestSelection(int observableIndex) const { return mSelectionContainers.at(observableIndex).getLoosestSelection(); } + /// \brief Print the full configuration of all selections to the log. + /// \param objectName Name of the object owning this selection (used as label in the log output). void printSelections(const std::string& objectName) const { LOG(info) << "Printing Configuration of " << objectName; for (size_t idx = 0; idx < mSelectionContainers.size(); ++idx) { - const auto& container = mSelectionContainers[idx]; + const auto& container = mSelectionContainers.at(idx); if (container.isEmpty()) { continue; } @@ -360,15 +357,11 @@ class BaseSelection LOG(info) << " Bitmask shift : " << container.getShift(); LOG(info) << " Selections:"; - const bool useFunctions = container.isUsingFunctions(); - const auto& values = container.getSelectionValues(); - const auto& functions = container.getSelectionFunction(); - const auto& comments = container.getComments(); - - for (int j = 0; j < container.getNSelections(); ++j) { + for (std::size_t j = 0; j < container.getNSelections(); ++j) { std::stringstream line; - std::string sel = useFunctions ? std::string(functions[j].GetExpFormula().Data()) : std::to_string(values[j]); + std::string sel = container.getValueAsString(j); + std::string comment = container.getComment(j); line << " " << std::left << std::setw(25) << sel; @@ -379,8 +372,8 @@ class BaseSelection line << "-> Bit: 0x" << std::hex << std::uppercase << (1ULL << bit) << std::dec; } - if (!comments.empty()) { - line << " (" << comments.at(j) << ")"; + if (!comment.empty()) { + line << " (" << comment << ")"; } LOG(info) << line.str(); } @@ -390,24 +383,27 @@ class BaseSelection LOG(info) << "Printing done"; } + /// \brief Initialize histograms and set bitmask offsets for all configured observables. + /// \tparam HistName Name of the histogram to create in the registry. + /// \param registry Pointer to the histogram registry. template void setupContainers(o2::framework::HistogramRegistry* registry) { mHistRegistry = registry; - // Create histogram with correct number of bins + // create histogram with one bin per selection, plus two summary bins (all analyzed, all passed) int nBins = mNSelection + 2; mHistRegistry->add(HistName, "; Selection Bits; Entries", o2::framework::kTH1F, {{nBins, -0.5, nBins - 0.5}}); - size_t binIndex = 0; + int binIndex = 0; int offset = 0; - for (size_t idx = 0; idx < mSelectionContainers.size(); ++idx) { + for (std::size_t idx = 0; idx < mSelectionContainers.size(); ++idx) { auto& container = mSelectionContainers[idx]; if (container.isEmpty()) { continue; } container.setOffset(offset); offset += container.getShift(); - for (int j = 0; j < container.getNSelections(); j++) { + for (std::size_t j = 0; j < container.getNSelections(); j++) { std::string label = container.getBinLabel(j); mHistRegistry->get(HIST(HistName))->GetXaxis()->SetBinLabel(binIndex + 1, label.c_str()); binIndex++; @@ -418,15 +414,40 @@ class BaseSelection } protected: + void init(int observableIndex) + { + // check if any selections are configured + if (mSelectionContainers.at(observableIndex).isEmpty()) { + return; + } + + // track the number of occupied bits and total selections + mNSelectionBits += mSelectionContainers.at(observableIndex).getShift(); + mNSelection += mSelectionContainers.at(observableIndex).getNSelections(); + + // check if any selection is minimal + if (mSelectionContainers.at(observableIndex).isMinimalCut()) { + mHasMinimalSelection = true; + } + // check if selection is optional + if (mSelectionContainers.at(observableIndex).isOptionalCut()) { + mHasOptionalSelection = true; + } + + if (mNSelectionBits > sizeof(BitmaskType) * CHAR_BIT) { + LOG(fatal) << "Too many selections. At most " << sizeof(BitmaskType) * CHAR_BIT << " number of bits are supported"; + } + } + o2::framework::HistogramRegistry* mHistRegistry = nullptr; - std::array, NumObservables> mSelectionContainers = {}; ///< Array containing all selections - std::bitset mFinalBitmask = {}; ///< final bitmaks - std::size_t mNSelectionBits = 0; ///< Number of selections (all - minimal selections) - int mNSelection = 0; ///< Number of selections all selections - bool mHasMinimalSelection = false; ///< Set to true if all minimal (mandatory) selections are passed - bool mPassesMinimalSelections = true; ///< Set to true if all minimal (mandatory) selections are passed - bool mHasOptionalSelection = false; ///< Set to true if at least one selections is optional - bool mPassesOptionalSelections = false; ///< Set to true if at least one optional (non-mandatory) selections is passed + std::array, NumObservables> mSelectionContainers = {}; ///< Array of selection containers, one per observable + std::bitset mFinalBitmask = {}; ///< Assembled bitmask combining all observable selections + std::size_t mNSelectionBits = 0; ///< Number of bits occupied in the bitmask (excludes skipped most-permissive bits) + std::size_t mNSelection = 0; ///< Total number of configured selection thresholds across all observables + bool mHasMinimalSelection = false; ///< True if at least one observable has a mandatory (minimal) cut configured + bool mPassesMinimalSelections = true; ///< True if all mandatory (minimal) cuts have been passed so far + bool mHasOptionalSelection = false; ///< True if at least one observable has an optional cut configured + bool mPassesOptionalSelections = false; ///< True if at least one optional cut has been passed }; } // namespace o2::analysis::femto diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index d14bbf76196..ae2ee46a3f9 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -17,25 +17,32 @@ #define PWGCF_FEMTO_CORE_PARTITIONS_H_ // collsion selection -#define MAKE_COLLISION_FILTER(selection) \ - (o2::aod::femtocollisions::posZ >= selection.vtxZMin && o2::aod::femtocollisions::posZ <= selection.vtxZMax) && \ - (o2::aod::femtocollisions::mult >= selection.multMin && o2::aod::femtocollisions::mult <= selection.multMax) && \ - (o2::aod::femtocollisions::cent >= selection.centMin && o2::aod::femtocollisions::cent <= selection.centMax) && \ - (o2::aod::femtocollisions::magField >= static_cast(selection.magFieldMin) && o2::aod::femtocollisions::magField <= static_cast(selection.magFieldMax)) && \ +#define MAKE_COLLISION_FILTER(selection) \ + (o2::aod::femtocollisions::posZ >= selection.vtxZMin && o2::aod::femtocollisions::posZ <= selection.vtxZMax) && \ + (o2::aod::femtocollisions::mult >= selection.multMin && o2::aod::femtocollisions::mult <= selection.multMax) && \ + (o2::aod::femtocollisions::cent >= selection.centMin && o2::aod::femtocollisions::cent <= selection.centMax) && \ + (o2::aod::femtocollisions::magField >= o2::framework::expressions::as(selection.magFieldMin) && \ + o2::aod::femtocollisions::magField <= o2::framework::expressions::as(selection.magFieldMax)) && \ ncheckbit(o2::aod::femtocollisions::mask, selection.collisionMask) +// macro for track momentum, i.e. ||q|*pT/q| * cosh(eta) +// there is no ncosh function, so we have to make our own, i.e. cosh(x) = (exp(x)+exp(-x))/2 +#define TRACK_MOMENTUM(chargeAbs, signedPt, eta) nabs((chargeAbs) * (signedPt)) * (nexp(eta) + nexp(-1.f * (eta))) / 2.f + // standard track partition -#define MAKE_TRACK_PARTITION(selection) \ - ifnode(selection.chargeSign.node() != 0, ifnode(selection.chargeSign.node() > 0, o2::aod::femtobase::stored::signedPt > 0.f, o2::aod::femtobase::stored::signedPt < 0.f), true) && \ - (nabs(selection.chargeAbs.node() * o2::aod::femtobase::stored::signedPt) > selection.ptMin) && \ - (nabs(selection.chargeAbs.node() * o2::aod::femtobase::stored::signedPt) < selection.ptMax) && \ - (o2::aod::femtobase::stored::eta > selection.etaMin) && \ - (o2::aod::femtobase::stored::eta < selection.etaMax) && \ - (o2::aod::femtobase::stored::phi > selection.phiMin) && \ - (o2::aod::femtobase::stored::phi < selection.phiMax) && \ - ifnode(nabs(selection.chargeAbs.node() * o2::aod::femtobase::stored::signedPt) * (nexp(o2::aod::femtobase::stored::eta) + nexp(-1.f * o2::aod::femtobase::stored::eta)) / (2.f) <= selection.pidThres, \ - ncheckbit(o2::aod::femtotracks::mask, selection.maskLowMomentum), \ - ncheckbit(o2::aod::femtotracks::mask, selection.maskHighMomentum)) +#define MAKE_TRACK_PARTITION(selection) \ + ifnode(selection.chargeSign.node() != 0, ifnode(selection.chargeSign.node() > 0, o2::aod::femtobase::stored::signedPt > 0.f, o2::aod::femtobase::stored::signedPt < 0.f), true) && \ + (nabs(selection.chargeAbs * o2::aod::femtobase::stored::signedPt) > selection.ptMin) && \ + (nabs(selection.chargeAbs * o2::aod::femtobase::stored::signedPt) < selection.ptMax) && \ + (o2::aod::femtobase::stored::eta > selection.etaMin) && \ + (o2::aod::femtobase::stored::eta < selection.etaMax) && \ + (o2::aod::femtobase::stored::phi > selection.phiMin) && \ + (o2::aod::femtobase::stored::phi < selection.phiMax) && \ + ifnode(TRACK_MOMENTUM(selection.chargeAbs, o2::aod::femtobase::stored::signedPt, o2::aod::femtobase::stored::eta) <= selection.pidThres, \ + ncheckbit(o2::aod::femtotracks::mask, selection.maskLowMomentum) && \ + (o2::aod::femtotracks::mask & selection.rejectionMaskLowMomentum) == static_cast(0), \ + ncheckbit(o2::aod::femtotracks::mask, selection.maskHighMomentum) && \ + (o2::aod::femtotracks::mask & selection.rejectionMaskHighMomentum) == static_cast(0)) // partition for phis and rhos, i.e. resonance that are their own antiparticle #define MAKE_RESONANCE_0_PARTITON(selection) \ diff --git a/PWGCF/Femto/Core/selectionContainer.h b/PWGCF/Femto/Core/selectionContainer.h index e9d67e6354a..d67819b6f8d 100644 --- a/PWGCF/Femto/Core/selectionContainer.h +++ b/PWGCF/Femto/Core/selectionContainer.h @@ -27,8 +27,10 @@ #include #include #include +#include #include #include +#include #include namespace o2::analysis::femto @@ -37,20 +39,21 @@ namespace o2::analysis::femto /// Limit type for selections namespace limits { -enum LimitType { kUpperLimit, ///< simple upper limit for the value, e.g. p_T < 1 GeV/c - kAbsUpperLimit, ///< upper limit of the absolute value, e.g. |eta| < 0.8 - kLowerLimit, ///< simple lower limit for the value, e.g. p_T > 0.2 GeV/c - kAbsLowerLimit, ///< lower limit of the absolute value, e.g. |DCA_xyz| > 0.05 cm - kUpperFunctionLimit, ///< simple upper limit of a function value, e.g. DCA_xy > f(pt) - kAbsUpperFunctionLimit, ///< upper limit of an absolute value given by a function, e.g. |DCA_xy| > f(pt) - kLowerFunctionLimit, ///< simple lower limit of a function value, e.g. DCA_xy < f(pt) - kAbsLowerFunctionLimit, ///< lower limit of an absolute value given by a function, e.g. |DCA_xy| < f(pt) - kEqual, ///< values need to be equal, e.g. sign = 1 - kEqualArray, ///< values inside an array need to be equal +enum LimitType { kUpperLimit, ///< simple upper limit, e.g. p_T < 1 GeV/c + kAbsUpperLimit, ///< upper limit on the absolute value, e.g. |eta| < 0.8 + kLowerLimit, ///< simple lower limit, e.g. p_T > 0.2 GeV/c + kAbsLowerLimit, ///< lower limit on the absolute value, e.g. |DCA_xy| > 0.05 cm + kUpperFunctionLimit, ///< upper limit given by a function, e.g. DCA_xy < f(pt) + kAbsUpperFunctionLimit, ///< upper limit on the absolute value given by a function, e.g. |DCA_xy| < f(pt) + kLowerFunctionLimit, ///< lower limit given by a function, e.g. DCA_xy > f(pt) + kAbsLowerFunctionLimit, ///< lower limit on the absolute value given by a function, e.g. |DCA_xy| > f(pt) + kEqual, ///< value must equal a fixed threshold, e.g. sign == 1 + kEqualArray, ///< each element of a value array must equal the corresponding threshold + kRange, ///< value must fall within [lower, upper]; either bound can be omitted (open interval) kLimitTypeLast }; -std::unordered_map limitTypeAsStrings = { +inline const std::unordered_map limitTypeAsStrings = { {kUpperLimit, "Upper Limit"}, {kAbsUpperLimit, "Absolute Upper Limit"}, {kLowerLimit, "Lower Limit"}, @@ -61,283 +64,358 @@ std::unordered_map limitTypeAsStrings = { {kAbsLowerFunctionLimit, "Absolute Lower Function Limit"}, {kEqual, "Equal"}, {kEqualArray, "EqualArray"}, - + {kRange, "Range"}, + {kLimitTypeLast, "Last Limit Type"}, }; }; // namespace limits /// \class SelectionContainer -/// \brief Class for storing and evaluating multiple selection thresholds for a single observable. -/// \tparam T Data type for selection values (mostly floats) -/// \tparam BitmaskType Type used for bitmask storage (e.g., uint8_t, uint32_t). +/// \brief Stores and evaluates multiple selection thresholds for a single observable. +/// +/// Selections can be based on static threshold values or dynamically evaluated TF1 functions. +/// Thresholds are sorted from most permissive to most restrictive so that evaluation can bail +/// out early once a threshold fails. +/// +/// \tparam T Data type for selection values (mostly floats). +/// \tparam BitmaskType Integer type used for bitmask storage (e.g., uint8_t, uint32_t). template class SelectionContainer { public: - /// Default constructor + /// \brief Default constructor. SelectionContainer() = default; + + /// \brief Destructor. ~SelectionContainer() = default; - /// \brief Constructor for static value-based selection. - /// \param SelectionValues Vector of values for the selection. + /// \brief Constructor for static value-based selections. + /// \param selectionName Name of the observable this container manages. + /// \param selectionValues Vector of threshold values. /// \param limitType Type of limit (from limits::LimitType). - /// \param SkipMostPermissiveBit Whether to skip the most permissive bit in the bitmask. - /// \param IsMinimalCut Whether this selection should be treated as a minimal required cut. - SelectionContainer(std::string const& SelectionName, - std::vector const& SelectionValues, + /// \param skipMostPermissiveBit Whether to skip the most permissive threshold when assembling the bitmask. + /// \param isMinimalCut Whether this selection is mandatory (candidate is rejected if it fails). + /// \param isOptionalCut Whether this selection is optional (candidate is accepted if any optional cut passes). + SelectionContainer(std::string const& selectionName, + std::vector const& selectionValues, limits::LimitType limitType, - bool SkipMostPermissiveBit, - bool IsMinimalCut, + bool skipMostPermissiveBit, + bool isMinimalCut, bool isOptionalCut) - : mSelectionName(SelectionName), - mSelectionValues(SelectionValues), + : mSelectionName(selectionName), + mSelectionValues(selectionValues), mLimitType(limitType), - mSkipMostPermissiveBit(SkipMostPermissiveBit), - mIsMinimalCut(IsMinimalCut), + mSkipMostPermissiveBit(skipMostPermissiveBit), + mIsMinimalCut(isMinimalCut), mIsOptionalCut(isOptionalCut) { if (mSelectionValues.size() > sizeof(BitmaskType) * CHAR_BIT) { LOG(fatal) << "Too many selections for single a observable. Limit is " << sizeof(BitmaskType) * CHAR_BIT; } + if (isMinimalCut && isOptionalCut) { + LOG(fatal) << "A selection cannot be both minimal and optional"; + } // values for selection are not necessarily ordered correctly sortSelections(); } - /// \brief Constructor for function-based dynamic selection. - /// \param baseName Base name for TF1 functions. - /// \param lowerLimit Lower bound for TF1 domain. - /// \param upperLimit Upper bound for TF1 domain. - /// \param functions Vector of strings defining TF1 functions. - /// \param limitType Type of limit. - /// \param skipMostPermissiveBit Whether to skip the most permissive bit in the bitmask. - /// \param IsMinimalCut Whether this selection should be treated as a minimal required cut. - SelectionContainer(std::string const& SelectionName, + /// \brief Constructor for range-based selections defined as "lower;upper" strings. + /// Either bound may be omitted to represent an open interval, e.g. ";1.0" means value < 1.0. + /// \param selectionName Name of the observable this container manages. + /// \param rangeStrings Vector of range strings, each of the form "lower;upper". + /// \param skipMostPermissiveBit Whether to skip the most permissive threshold when assembling the bitmask. + /// \param isMinimalCut Whether this selection is mandatory (candidate is rejected if it fails). + /// \param isOptionalCut Whether this selection is optional (candidate is accepted if any optional cut passes). + SelectionContainer(std::string const& selectionName, + std::vector const& rangeStrings, + bool skipMostPermissiveBit, + bool isMinimalCut, + bool isOptionalCut) + : mSelectionName(selectionName), + mLimitType(limits::kRange), + mSkipMostPermissiveBit(skipMostPermissiveBit), + mIsMinimalCut(isMinimalCut), + mIsOptionalCut(isOptionalCut) + { + if (rangeStrings.size() > sizeof(BitmaskType) * CHAR_BIT) { + LOG(fatal) << "Too many selections for a single observable. Limit is " << sizeof(BitmaskType) * CHAR_BIT; + } + if (isMinimalCut && isOptionalCut) { + LOG(fatal) << "A selection cannot be both minimal and optional"; + } + for (auto const& rangeStr : rangeStrings) { + T lower, upper; + parseRangeString(rangeStr, lower, upper); + mSelectionRanges.emplace_back(lower, upper); + } + // ranges are sorted by their lenghts, i.e. from widest range to tightest range + // in principle the ranges do not have to include each other, exepct this is configured as minimal cut, check is added at the end + // to cover both cases, this also means we always check all ranges, when assembling the bit mask + sortSelections(); + // init mSelectionValues to be the widths of the intervals + for (std::size_t i = 0; i < mSelectionRanges.size(); i++) { + mSelectionValues.push_back(mSelectionRanges[i].second - mSelectionRanges[i].first); + } + + // for minimal range cut, ranges must be strictly nested (each range contains all narrower ones) + // this is required for the early-exit logic in passesAsMinimalCut() to be correct + if (isMinimalCut) { + for (std::size_t i = 0; i + 1 < mSelectionRanges.size(); i++) { + if (mSelectionRanges[i].first > mSelectionRanges[i + 1].first || + mSelectionRanges[i].second < mSelectionRanges[i + 1].second) { + LOG(fatal) << "Ranges for minimal cut " << selectionName + << " are not nested. Range [" << mSelectionRanges[i].first << ";" << mSelectionRanges[i].second + << "] does not contain [" << mSelectionRanges[i + 1].first << ";" << mSelectionRanges[i + 1].second << "]"; + } + } + } + } + + /// \brief Constructor for function-based dynamic selections. + /// \param selectionName Name of the observable this container manages. + /// \param lowerLimit Lower bound of the TF1 domain. + /// \param upperLimit Upper bound of the TF1 domain. + /// \param functions Vector of strings defining TF1 threshold functions. + /// \param limitType Type of limit (from limits::LimitType). + /// \param skipMostPermissiveBit Whether to skip the most permissive threshold when assembling the bitmask. + /// \param isMinimalCut Whether this selection is mandatory (candidate is rejected if it fails). + /// \param isOptionalCut Whether this selection is optional (candidate is accepted if any optional cut passes). + SelectionContainer(std::string const& selectionName, T lowerLimit, T upperLimit, std::vector const& functions, limits::LimitType limitType, bool skipMostPermissiveBit, - bool IsMinimalCut, + bool isMinimalCut, bool isOptionalCut) - : mSelectionName(SelectionName), + : mSelectionName(selectionName), mLimitType(limitType), mSkipMostPermissiveBit(skipMostPermissiveBit), - mIsMinimalCut(IsMinimalCut), + mIsMinimalCut(isMinimalCut), mIsOptionalCut(isOptionalCut) { if (functions.size() > sizeof(BitmaskType) * CHAR_BIT) { LOG(fatal) << "Too many selections for single a observable. Limit is " << sizeof(BitmaskType) * CHAR_BIT; } + if (isMinimalCut && isOptionalCut) { + LOG(fatal) << "A selection cannot be both minimal and optional"; + } for (std::size_t i = 0; i < functions.size(); i++) { mSelectionFunctions.emplace_back((mSelectionName + std::to_string(i)).c_str(), functions.at(i).c_str(), lowerLimit, upperLimit); } - // functions for selection are not necessarily ordered correctly - // use value at midpoint to order them - // here we rely on the user that the functions can be ordered like this over the whole interval + // functions are not necessarily ordered correctly; + // use the midpoint of the domain to establish their order. + // this relies on the user ensuring the ordering is consistent across the whole interval. T midPoint = (lowerLimit + upperLimit) / 2.; sortFunctions(midPoint); - // initialize the values also to the midpoint + // initialize threshold values to the functions evaluated at the midpoint for (std::size_t i = 0; i < functions.size(); i++) { mSelectionValues.push_back(mSelectionFunctions.at(i).Eval(midPoint)); } } - /// \brief Sort static selection values based on the limit type. - void sortSelections() + /// \brief Attach comments to the selection thresholds, one per threshold in the same order as the input values. + /// \param comments Vector of comment strings. + void addComments(std::vector const& comments) { - switch (mLimitType) { - case (limits::kUpperLimit): - case (limits::kAbsUpperLimit): - std::sort(mSelectionValues.begin(), mSelectionValues.end(), [](T a, T b) { return a > b; }); - break; - case (limits::kLowerLimit): - case (limits::kAbsLowerLimit): - std::sort(mSelectionValues.begin(), mSelectionValues.end(), [](T a, T b) { return a < b; }); - break; - default: - break; + // note: threshold values may be reordered by sortSelections() or sortFunctions(), + // so comments must be provided in the already-sorted order + if (comments.size() != getNSelections()) { + LOG(fatal) << "Number of comments and number of selections are inconsistent"; } + mComments = comments; } - /// \brief Sort selection functions based on evaluation at a given point. - /// \param value Point at which to evaluate the functions for ordering. - void sortFunctions(T value) + /// \brief Get comments attached to the selection thresholds. + /// \return Vector of comment strings. + std::string getComment(int selectionIndex) const { - switch (mLimitType) { - case (limits::kUpperFunctionLimit): - case (limits::kAbsUpperFunctionLimit): - std::sort(mSelectionFunctions.begin(), mSelectionFunctions.end(), [value](TF1 const& a, TF1 const& b) { return a.Eval(value) > b.Eval(value); }); - break; - case (limits::kLowerFunctionLimit): - case (limits::kAbsLowerFunctionLimit): - std::sort(mSelectionFunctions.begin(), mSelectionFunctions.end(), [value](TF1 const& a, TF1 const& b) { return a.Eval(value) < b.Eval(value); }); - break; - default: - break; + if (mComments.empty()) { + return std::string(""); } + return mComments.at(selectionIndex); } - /// \brief Add comments to the selection values - /// \param comments Vector of comments - void addComments(std::vector const& comments) - { - // make sure that the comments are in correct order - // the values passed to the selection container can be reordered based on the limit type - mComments = comments; - } - - std::vector const& getComments() const { return mComments; } + /// \brief Get the name of this selection. + /// \return Selection name string. std::string const& getSelectionName() const { return mSelectionName; } - /// \brief Update selection limits using internal functions evaluated at a given value. - /// \param value Input value to evaluate functions at. + /// \brief Update threshold values by re-evaluating the internal TF1 functions at a given point. + /// \param value Input value at which to evaluate the functions. void updateLimits(T value) { - // functions are ordered so just add the values in the same order + // functions are already sorted, so evaluate in the same order as mSelectionValues for (std::size_t i = 0; i < mSelectionValues.size(); i++) { mSelectionValues.at(i) = mSelectionFunctions.at(i).Eval(value); } } - /// \brief Evaluate which selection criteria are fulfilled for a given value. + /// \brief Evaluate which selection thresholds are passed for a given observable value. /// \param value Value of the observable to evaluate. void evaluate(T value) { - // better safe than sorry and reset the bitmask before you evaluate and set minimal selection to true + // reset the bitmask before evaluating mBitmask.reset(); - // the values are ordered, from most loose to most tight, as soon as one comparison is not true, we can break out of the loop - bool breakLoop = false; - // iterate over all limits and set the corresponding bit if we pass the selection, otherwise break out as soon as we can - // only break if the observable is used for the minimal selection - for (size_t i = 0; i < mSelectionValues.size(); i++) { - switch (mLimitType) { - case (limits::kUpperLimit): - case (limits::kUpperFunctionLimit): + + // switch on limit type once outside the loop; + // thresholds are sorted from most permissive to most restrictive, + // so we can break early as soon as one comparison fails + switch (mLimitType) { + case (limits::kUpperLimit): + case (limits::kUpperFunctionLimit): + for (std::size_t i = 0; i < mSelectionValues.size(); i++) { if (value <= mSelectionValues.at(i)) { mBitmask.set(i); } else { - breakLoop = true; + break; } - break; - case (limits::kAbsUpperLimit): - case (limits::kAbsUpperFunctionLimit): + } + break; + case (limits::kAbsUpperLimit): + case (limits::kAbsUpperFunctionLimit): + for (std::size_t i = 0; i < mSelectionValues.size(); i++) { if (std::abs(value) <= mSelectionValues.at(i)) { mBitmask.set(i); } else { - breakLoop = true; + break; } - break; - case (limits::kLowerLimit): - case (limits::kLowerFunctionLimit): + } + break; + case (limits::kLowerLimit): + case (limits::kLowerFunctionLimit): + for (std::size_t i = 0; i < mSelectionValues.size(); i++) { if (value >= mSelectionValues.at(i)) { mBitmask.set(i); } else { - breakLoop = true; + break; } - break; - case (limits::kAbsLowerLimit): - case (limits::kAbsLowerFunctionLimit): + } + break; + case (limits::kAbsLowerLimit): + case (limits::kAbsLowerFunctionLimit): + for (std::size_t i = 0; i < mSelectionValues.size(); i++) { if (std::abs(value) >= mSelectionValues.at(i)) { mBitmask.set(i); } else { - breakLoop = true; + break; } - break; - case (limits::kEqual): - // special case for kEqual since here we cannot really establish an order so we need to check all cases explicitly and we cannot bail early + } + break; + case (limits::kRange): + // ranges are sorted widest-first but a narrower range passing does not imply a wider one fails (no check on boundries), + // so all ranges must be checked explicitly — no early exit + for (std::size_t i = 0; i < mSelectionRanges.size(); i++) { + if (value >= mSelectionRanges.at(i).first && value <= mSelectionRanges.at(i).second) { + mBitmask.set(i); + } + } + break; + case (limits::kEqual): + // kEqual has no natural ordering, so all thresholds must be checked and we cannot bail early + for (std::size_t i = 0; i < mSelectionValues.size(); i++) { if (std::fabs(value - mSelectionValues.at(i)) < constants::math::Epsilon) { mBitmask.set(i); } - break; - default: - breakLoop = true; - } - // bail early if a comparison fails - // the values are ordered, so all following we also fail, there there is no point in contiuing - if (breakLoop) { + } break; - } + default: + LOG(warn) << "Limit type not known, no selection is applied"; } } - /// \brief Evaluate which selection criteria are fulfilled for a given value. - /// \param values Values of the observable to evaluate + /// \brief Evaluate which selection thresholds are passed for a vector of observable values. + /// Only kEqualArray is supported for now; each element is compared against the corresponding threshold. + /// \param values Values of the observable to evaluate. void evaluate(std::vector const& values) { if (values.size() != mSelectionValues.size()) { LOG(fatal) << "Wrong number of values have been passed"; } - for (size_t i = 0; i < mSelectionValues.size(); i++) { - switch (mLimitType) { - case (limits::kEqualArray): + // reset the bitmask before evaluating + mBitmask.reset(); + + switch (mLimitType) { + case (limits::kEqualArray): + for (std::size_t i = 0; i < mSelectionValues.size(); i++) { if (std::fabs(values.at(i) - mSelectionValues.at(i)) < constants::math::Epsilon) { mBitmask.set(i); } - break; - default: - continue; - } + } + break; + default: + LOG(warn) << "Limit type not known, no selection is applied"; } } - /// \brief Retrieve the bitmask indicating which selections were passed. + /// \brief Retrieve the bitmask indicating which thresholds were passed. + /// If mSkipMostPermissiveBit is set, the bit for the loosest threshold is removed by shifting. /// \return Bitset representing passed selections. std::bitset getBitmask() const { - // if we do not skip the last bit, return full bitmask - if (mSkipMostPermissiveBit == false) { + if (!mSkipMostPermissiveBit) { return mBitmask; } else { - // for the other selections we can remove the first bit since it is the minimal selection and therefore always true + // remove the first (most permissive) bit since it corresponds to the minimal selection and is always true return mBitmask >> 1; } } + + /// \brief Manually set the internal bitmask. + /// \tparam R Integer type of the bitmask value. + /// \param bitmask Bitmask value to set. template void setBitmask(R bitmask) { mBitmask = std::bitset(bitmask); } - /// \brief Check whether the minimal cut condition is fulfilled. - /// \return True if minimal selection is fulfilled, false otherwise. + /// \brief Reset the internal bitmask to zero. + void reset() { mBitmask.reset(); } + + /// \brief Check whether the mandatory (minimal) cut condition is fulfilled. + /// \return True if the minimal selection passes or if this container is not marked as a minimal cut. bool passesAsMinimalCut() const { if (mIsMinimalCut) { - // check if any bit is set - // in case were bits are evaluted in order, if the loosests fails, all fail, so testing any is safe here - return mBitmask.any(); + // if any bit is set the loosest threshold passed; since thresholds are ordered, + // the loosest passing implies all looser ones also pass + return mBitmask.test(0); } - // if a selection is not marked as minimal cut we return true by default + // not a minimal cut — return true by default so it does not block the candidate return true; } - /// \brief Check whether any optional cuts are fulfilled. - /// \return True if at least one optional cut is passed. + /// \brief Check whether any optional cut is fulfilled. + /// \return True if at least one optional threshold is passed, false if this container is not marked as optional. bool passesAsOptionalCut() const { if (mIsOptionalCut) { - // check if any bit is set - // in case were bits are evaluted in order, if the loosests fails, all fail, so testing any is safe here + // if any bit is set the loosest threshold passed return mBitmask.any(); } - // if a selection is not marked as optional cut we return false by default + // not an optional cut — return false by default so it does not accidentally accept the candidate return false; } - /// \brief Get the loosest (most permissive) selection value. - /// \return First (loosest) selection value. - T getLoosestSelection() const { return mSelectionValues.at(0); } + /// \brief Get the loosest (most permissive) selection threshold value. + /// \return The first element of the sorted threshold vector. + T getLoosestSelection() const + { + if (mSelectionValues.empty()) { + LOG(fatal) << "No selections configured"; + } + return mSelectionValues.at(0); + } - /// \brief Check if there are any selection values configured. We also init values in case of function so this is safe - /// \return True if no selections are configured. + /// \brief Check whether any selection thresholds are configured. + /// For function-based selections, mSelectionValues is always populated (initialised at the midpoint), + /// so this check is safe for both static and function-based containers. + /// \return True if no thresholds are configured. bool isEmpty() const { return mSelectionValues.empty(); } - /// \brief Check if there are any selection values configured. - /// \return True if no selections are configured. - bool isUsingFunctions() const { return !mSelectionFunctions.empty(); } - - /// \brief Get the number of bits to shift for the final bitmask. - /// \return Number of bits to shift. + /// \brief Get the number of bits this container contributes to the global bitmask. + /// If the most permissive bit is skipped, the contribution is reduced by one. + /// \return Number of bits to add to the global bitmask offset. int getShift() const { if (mSelectionValues.empty()) { @@ -345,22 +423,47 @@ class SelectionContainer } if (mSkipMostPermissiveBit) { return static_cast(mSelectionValues.size() - 1); - } else { - return static_cast(mSelectionValues.size()); } + return static_cast(mSelectionValues.size()); } + /// \brief Set the bit offset of this container within the global bitmask. + /// \param offset Bit position at which this container's bits start. void setOffset(int offset) { mOffset = offset; } + + /// \brief Get the bit offset of this container within the global bitmask. + /// \return Bit offset. int getOffset() const { return mOffset; } - int getNSelections() const { return mSelectionValues.size(); } + /// \brief Get the total number of configured selection thresholds. + /// \return Number of thresholds. + std::size_t getNSelections() const { return mSelectionValues.size(); } + /// \brief Build a histogram bin label string encoding the full configuration of a single threshold. + /// \param selectionIndex Index of the threshold within this container. + /// \return Encoded label string. std::string getBinLabel(int selectionIndex) const { std::ostringstream oss; std::string sectionDelimiter = ":::"; std::string valueDelimiter = "___"; std::string noValue = "X"; + + // Determine value string + std::string valueStr; + + if (mLimitType == limits::kRange) { + // Print actual lower;upper interval + const auto& range = mSelectionRanges.at(selectionIndex); + std::ostringstream rangeStream; + rangeStream << range.first << ";" << range.second; + valueStr = rangeStream.str(); + } else if (mSelectionFunctions.empty()) { + valueStr = std::to_string(mSelectionValues.at(selectionIndex)); + } else { + valueStr = mSelectionFunctions.at(selectionIndex).GetExpFormula().Data(); + } + oss << "SelectionName" << valueDelimiter << mSelectionName << sectionDelimiter << "LimitType" << valueDelimiter << getLimitTypeAsString() << sectionDelimiter << "MinimalCut" << valueDelimiter << (mIsMinimalCut ? "1" : "0") << sectionDelimiter @@ -368,12 +471,32 @@ class SelectionContainer << "OptionalCut" << valueDelimiter << (mIsOptionalCut ? "1" : "0") << sectionDelimiter << "Shift" << valueDelimiter << getShift() << sectionDelimiter << "Offset" << valueDelimiter << mOffset << sectionDelimiter - << "Value" << valueDelimiter << (mSelectionFunctions.empty() ? std::to_string(mSelectionValues.at(selectionIndex)) : mSelectionFunctions.at(selectionIndex).GetExpFormula().Data()) << sectionDelimiter + << "Value" << valueDelimiter << valueStr << sectionDelimiter << "BitPosition" << valueDelimiter << (mSkipMostPermissiveBit ? (selectionIndex == 0 ? noValue : std::to_string(mOffset + selectionIndex - 1)) : std::to_string(mOffset + selectionIndex)) << sectionDelimiter << "Comment" << valueDelimiter << (mComments.empty() ? noValue : mComments.at(selectionIndex)); return oss.str(); } + std::string getValueAsString(int selectionIndex) const + { + if (this->isEmpty()) { + return std::string("No value configured"); + } + if (!mSelectionFunctions.empty()) { + return std::string(mSelectionFunctions.at(selectionIndex).GetExpFormula().Data()); + } + if (!mSelectionRanges.empty()) { + std::ostringstream oss; + oss << mSelectionRanges.at(selectionIndex).first << ";" << mSelectionRanges.at(selectionIndex).second; + return oss.str(); + } + return std::to_string(mSelectionValues.at(selectionIndex)); + } + + /// \brief Get the global bit position of a threshold within the final bitmask. + /// Calling this for the skipped most-permissive threshold is a fatal error. + /// \param selectionIndex Index of the threshold within this container. + /// \return Global bit position. int getBitPosition(int selectionIndex) const { if (selectionIndex == 0 && mSkipMostPermissiveBit) { @@ -387,43 +510,107 @@ class SelectionContainer } } - /// \brief Get string representation of the limit type. - /// \return String name of the limit type. - std::string getLimitTypeAsString() const { return limits::limitTypeAsStrings[mLimitType]; } + /// \brief Get the string representation of the configured limit type. + /// \return Human-readable limit type name. + std::string getLimitTypeAsString() const { return limits::limitTypeAsStrings.at(mLimitType); } - /// \brief Get a copy of all selection values. - /// \return Vector of selection values. + /// \brief Get the configured static threshold values. + /// \return Const reference to the vector of threshold values. std::vector const& getSelectionValues() const { return mSelectionValues; } - /// \brief Get a copy of all selection values. - /// \return Vector of selection values. + /// \brief Get the configured TF1 threshold functions. + /// \return Const reference to the vector of TF1 functions. std::vector const& getSelectionFunction() const { return mSelectionFunctions; } - /// \brief Check if this container is marked as minimal cut - /// \return True if minimal cut, false otherwise. + /// \brief Check whether this container is marked as a mandatory (minimal) cut. + /// \return True if this is a minimal cut. bool isMinimalCut() const { return mIsMinimalCut; } - /// \brief Check if this container is marked as optional cut - /// \return True if minimal cut, false otherwise. + /// \brief Check whether this container is marked as an optional cut. + /// \return True if this is an optional cut. bool isOptionalCut() const { return mIsOptionalCut; } - /// \brief Check whether the most permissive bit is skipped. - /// \return True if skipped, false otherwise. + /// \brief Check whether the most permissive threshold bit is skipped when assembling the bitmask. + /// \return True if the most permissive bit is skipped. bool skipMostPermissiveBit() const { return mSkipMostPermissiveBit; } - void reset() { mBitmask.reset(); } - private: - std::string mSelectionName = std::string(""); - std::vector mSelectionValues = {}; ///< Values used for the selection - std::vector mSelectionFunctions = {}; ///< Function used for the selection - limits::LimitType mLimitType = limits::kLimitTypeLast; ///< Limit type of selection - bool mSkipMostPermissiveBit = false; ///< whether to skip the last bit or not - bool mIsMinimalCut = false; ///< whether to use this observable for minimal selection or not - bool mIsOptionalCut = false; ///< whether to use this observable for minimal selection or not - std::vector mComments = {}; ///< Comments for the values - std::bitset mBitmask = {}; ///< bitmask for the observable - int mOffset = 0; + /// \brief Sort static threshold values from most permissive to most restrictive based on the limit type. + void sortSelections() + { + switch (mLimitType) { + case (limits::kUpperLimit): + case (limits::kAbsUpperLimit): + std::sort(mSelectionValues.begin(), mSelectionValues.end(), [](T a, T b) { return a > b; }); + break; + case (limits::kLowerLimit): + case (limits::kAbsLowerLimit): + std::sort(mSelectionValues.begin(), mSelectionValues.end(), [](T a, T b) { return a < b; }); + break; + case (limits::kRange): + // sort by range width descending so the most permissive (widest) range comes first + std::sort(mSelectionRanges.begin(), mSelectionRanges.end(), + [](std::pair const& a, std::pair const& b) { + return (a.second - a.first) > (b.second - b.first); + }); + break; + default: + break; + } + } + + /// \brief Sort selection functions from most permissive to most restrictive, evaluated at a given point. + /// \param value Point at which to evaluate the functions for ordering. + void sortFunctions(T value) + { + switch (mLimitType) { + case (limits::kUpperFunctionLimit): + case (limits::kAbsUpperFunctionLimit): + std::sort(mSelectionFunctions.begin(), mSelectionFunctions.end(), [value](TF1 const& a, TF1 const& b) { return a.Eval(value) > b.Eval(value); }); + break; + case (limits::kLowerFunctionLimit): + case (limits::kAbsLowerFunctionLimit): + std::sort(mSelectionFunctions.begin(), mSelectionFunctions.end(), [value](TF1 const& a, TF1 const& b) { return a.Eval(value) < b.Eval(value); }); + break; + default: + break; + } + } + + /// \brief Parse a range string of the form "lower;upper" into a lower and upper bound. + /// Either bound may be omitted (e.g. ";1.0" or "0.5;"), in which case + /// -/+ numeric_limits::max() is used respectively. + /// \param rangeStr Input string to parse. + /// \param lower Output lower bound. + /// \param upper Output upper bound. + void parseRangeString(std::string const& rangeStr, T& lower, T& upper) const + { + auto pos = rangeStr.find(';'); + if (pos == std::string::npos) { + LOG(fatal) << "Range string '" << rangeStr << "' is missing ';' separator. Expected format: 'lower;upper'"; + } + std::string lowerStr = rangeStr.substr(0, pos); + std::string upperStr = rangeStr.substr(pos + 1); + + lower = lowerStr.empty() ? -std::numeric_limits::max() : static_cast(std::stod(lowerStr)); + upper = upperStr.empty() ? std::numeric_limits::max() : static_cast(std::stod(upperStr)); + + if (lower >= upper) { + LOG(fatal) << "Range string '" << rangeStr << "' has lower bound >= upper bound"; + } + } + + std::string mSelectionName = ""; + std::vector mSelectionValues = {}; ///< Threshold values, sorted from most permissive to most restrictive + std::vector mSelectionFunctions = {}; ///< TF1 threshold functions (empty for static selections) + std::vector> mSelectionRanges = {}; ///< Lower and upper bounds for kRange selections, one pair per threshold + limits::LimitType mLimitType = limits::kLimitTypeLast; ///< Comparison type applied during evaluation + bool mSkipMostPermissiveBit = false; ///< If true, the most permissive threshold does not occupy a bit in the global bitmask + bool mIsMinimalCut = false; ///< If true, this selection is mandatory; failing it rejects the candidate + bool mIsOptionalCut = false; ///< If true, this selection is optional; passing it accepts the candidate + std::vector mComments = {}; ///< Optional comments per threshold, in the same order as mSelectionValues + std::bitset mBitmask = {}; ///< Bitmask indicating which thresholds were passed during the last evaluation + int mOffset = 0; ///< Bit offset of this container within the global bitmask }; } // namespace o2::analysis::femto diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h index c33b5850468..ffb5df80c37 100644 --- a/PWGCF/Femto/Core/trackBuilder.h +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -67,65 +67,65 @@ struct ConfTrackBits : o2::framework::ConfigurableGroup { // Electron PID cuts o2::framework::Configurable requirePidElectron{"requirePidElectron", false, "Make election PID optional"}; o2::framework::Configurable minMomTofElectron{"minMomTofElectron", 0.3, "Minimum momentum to required TOF PID for Electron"}; - o2::framework::Configurable> itsElectron{"itsElectron", {}, "Maximum |nsigma| for Electron PID"}; - o2::framework::Configurable> tpcElectron{"tpcElectron", {}, "Maximum |nsigma| for Electron PID"}; - o2::framework::Configurable> tofElectron{"tofElectron", {}, "Maximum |nsigma| for Electron PID"}; - o2::framework::Configurable> tpcitsElectron{"tpcitsElectron", {}, "Maximum |nsigma| for Electron PID"}; - o2::framework::Configurable> tpctofElectron{"tpctofElectron", {}, "Maximum |nsigma| for Electron PID"}; + o2::framework::Configurable> itsElectron{"itsElectron", {}, "Ranges LowerLimit;UpperLimit for nsigma_ITS for Electron PID"}; + o2::framework::Configurable> tpcElectron{"tpcElectron", {}, "Ranges LowerLimit;UpperLimit for nsigma_TPC for Electron PID"}; + o2::framework::Configurable> tofElectron{"tofElectron", {}, "Ranges LowerLimit;UpperLimit for nsigma_TOF for Electron PID"}; + o2::framework::Configurable> tpcitsElectron{"tpcitsElectron", {}, "Maximum nsigma_TPCITS for Electron PID"}; + o2::framework::Configurable> tpctofElectron{"tpctofElectron", {}, "Maximum nsigma_TPCTOF for Electron PID"}; // Pion PID cuts o2::framework::Configurable requirePidPion{"requirePidPion", false, "Make election PID optional"}; o2::framework::Configurable minMomTofPion{"minMomTofPion", 0.5, "Minimum momentum to required TOF PID for Pion"}; - o2::framework::Configurable> itsPion{"itsPion", {}, "Maximum |nsigma| for Pion PID"}; - o2::framework::Configurable> tpcPion{"tpcPion", {}, "Maximum |nsigma| for Pion PID"}; - o2::framework::Configurable> tofPion{"tofPion", {}, "Maximum |nsigma| for Pion PID"}; - o2::framework::Configurable> tpcitsPion{"tpcitsPion", {}, "Maximum |nsigma| for Pion PID"}; - o2::framework::Configurable> tpctofPion{"tpctofPion", {}, "Maximum |nsigma| for Pion PID"}; + o2::framework::Configurable> itsPion{"itsPion", {}, "Ranges LowerLimit;UpperLimit for nsigma_ITS for Pion PID"}; + o2::framework::Configurable> tpcPion{"tpcPion", {}, "Ranges LowerLimit;UpperLimit for nsigma_TPC for Pion PID"}; + o2::framework::Configurable> tofPion{"tofPion", {}, "Ranges LowerLimit;UpperLimit for nsigma_TOF for Pion PID"}; + o2::framework::Configurable> tpcitsPion{"tpcitsPion", {}, "Maximum nsigma_TPCITS for Pion PID"}; + o2::framework::Configurable> tpctofPion{"tpctofPion", {}, "Maximum nsigma_TPCTOF for Pion PID"}; // Kaon PID cuts o2::framework::Configurable requirePidKaon{"requirePidKaon", false, "Make election PID optional"}; o2::framework::Configurable minMomTofKaon{"minMomTofKaon", 0.4, "Minimum momentum to required TOF PID for Kaon"}; - o2::framework::Configurable> itsKaon{"itsKaon", {}, "Maximum |nsigma| for Kaon PID"}; - o2::framework::Configurable> tpcKaon{"tpcKaon", {}, "Maximum |nsigma| for Kaon PID"}; - o2::framework::Configurable> tofKaon{"tofKaon", {}, "Maximum |nsigma| for Kaon PID"}; - o2::framework::Configurable> tpcitsKaon{"tpcitsKaon", {}, "Maximum |nsigma| for Kaon PID"}; - o2::framework::Configurable> tpctofKaon{"tpctofKaon", {}, "Maximum |nsigma| for Kaon PID"}; + o2::framework::Configurable> itsKaon{"itsKaon", {}, "Ranges LowerLimit;UpperLimit for nsigma_ITS for Kaon PID"}; + o2::framework::Configurable> tpcKaon{"tpcKaon", {}, "Ranges LowerLimit;UpperLimit for nsigma_TPC for Kaon PID"}; + o2::framework::Configurable> tofKaon{"tofKaon", {}, "Ranges LowerLimit;UpperLimit for nsigma_TOF for Kaon PID"}; + o2::framework::Configurable> tpcitsKaon{"tpcitsKaon", {}, "Maximum nsigma_TPCITS for Kaon PID"}; + o2::framework::Configurable> tpctofKaon{"tpctofKaon", {}, "Maximum nsigma_TPCTOF for Kaon PID"}; // Proton PID cuts o2::framework::Configurable requirePidProton{"requirePidProton", true, "Make election PID optional"}; o2::framework::Configurable minMomTofProton{"minMomTofProton", 0.75, "Minimum momentum to required TOF PID for Proton"}; - o2::framework::Configurable> itsProton{"itsProton", {}, "Maximum |nsigma| for Proton PID"}; - o2::framework::Configurable> tpcProton{"tpcProton", {}, "Maximum |nsigma| for Proton PID"}; - o2::framework::Configurable> tofProton{"tofProton", {}, "Maximum |nsigma| for Proton PID"}; - o2::framework::Configurable> tpcitsProton{"tpcitsProton", {}, "Maximum |nsigma| for Proton PID"}; - o2::framework::Configurable> tpctofProton{"tpctofProton", {}, "Maximum |nsigma| for Proton PID"}; + o2::framework::Configurable> itsProton{"itsProton", {}, "Ranges LowerLimit;UpperLimit for nsigma_ITS for Proton PID"}; + o2::framework::Configurable> tpcProton{"tpcProton", {}, "Ranges LowerLimit;UpperLimit for nsigma_TPC for Proton PID"}; + o2::framework::Configurable> tofProton{"tofProton", {}, "Ranges LowerLimit;UpperLimit for nsigma_TOF for Proton PID"}; + o2::framework::Configurable> tpcitsProton{"tpcitsProton", {}, "Maximum nsigma_TPCITS for Proton PID"}; + o2::framework::Configurable> tpctofProton{"tpctofProton", {}, "Maximum nsigma_TPCTOF for Proton PID"}; // Deuteron PID cuts o2::framework::Configurable requirePidDeuteron{"requirePidDeuteron", false, "Make election PID optional"}; o2::framework::Configurable minMomTofDeuteron{"minMomTofDeuteron", 1.2, "Minimum momentum to required TOF PID for Deuteron"}; - o2::framework::Configurable> itsDeuteron{"itsDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; - o2::framework::Configurable> tpcDeuteron{"tpcDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; - o2::framework::Configurable> tofDeuteron{"tofDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; - o2::framework::Configurable> tpcitsDeuteron{"tpcitsDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; - o2::framework::Configurable> tpctofDeuteron{"tpctofDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; + o2::framework::Configurable> itsDeuteron{"itsDeuteron", {}, "Ranges LowerLimit;UpperLimit for nsigma_ITS for Deuteron PID"}; + o2::framework::Configurable> tpcDeuteron{"tpcDeuteron", {}, "Ranges LowerLimit;UpperLimit for nsigma_TPC for Deuteron PID"}; + o2::framework::Configurable> tofDeuteron{"tofDeuteron", {}, "Ranges LowerLimit;UpperLimit for nsigma_TOF for Deuteron PID"}; + o2::framework::Configurable> tpcitsDeuteron{"tpcitsDeuteron", {}, "Maximum nsigma_TPCITS for Deuteron PID"}; + o2::framework::Configurable> tpctofDeuteron{"tpctofDeuteron", {}, "Maximum nsigma_TPCTOF for Deuteron PID"}; // Triton PID cuts o2::framework::Configurable requirePidTriton{"requirePidTriton", false, "Make election PID optional"}; o2::framework::Configurable minMomTofTriton{"minMomTofTriton", 1.4, "Minimum momentum to required TOF PID for Triton"}; - o2::framework::Configurable> itsTriton{"itsTriton", {}, "Maximum |nsigma| for Triton PID"}; - o2::framework::Configurable> tpcTriton{"tpcTriton", {}, "Maximum |nsigma| for Triton PID"}; - o2::framework::Configurable> tofTriton{"tofTriton", {}, "Maximum |nsigma| for Triton PID"}; - o2::framework::Configurable> tpcitsTriton{"tpcitsTriton", {}, "Maximum |nsigma| for Triton PID"}; - o2::framework::Configurable> tpctofTriton{"tpctofTriton", {}, "Maximum |nsigma| for Triton PID"}; + o2::framework::Configurable> itsTriton{"itsTriton", {}, "Ranges LowerLimit;UpperLimit for nsigma_ITS for Triton PID"}; + o2::framework::Configurable> tpcTriton{"tpcTriton", {}, "Ranges LowerLimit;UpperLimit for nsigma_TPC for Triton PID"}; + o2::framework::Configurable> tofTriton{"tofTriton", {}, "Ranges LowerLimit;UpperLimit for nsigma_TOF for Triton PID"}; + o2::framework::Configurable> tpcitsTriton{"tpcitsTriton", {}, "Maximum nsigma_TPCITS for Triton PID"}; + o2::framework::Configurable> tpctofTriton{"tpctofTriton", {}, "Maximum nsigma_TPCTOF for Triton PID"}; // Helium PID cuts o2::framework::Configurable requirePidHelium{"requirePidHelium", false, "Make election PID optional"}; o2::framework::Configurable minMomTofHelium{"minMomTofHelium", 1.6, "Minimum momentum to required TOF PID for Helium"}; - o2::framework::Configurable> itsHelium{"itsHelium", {}, "Maximum |nsigma| for Helium PID"}; - o2::framework::Configurable> tpcHelium{"tpcHelium", {}, "Maximum |nsigma| for Helium PID"}; - o2::framework::Configurable> tofHelium{"tofHelium", {}, "Maximum |nsigma| for Helium PID"}; - o2::framework::Configurable> tpcitsHelium{"tpcitsHelium", {}, "Maximum |nsigma| for Helium PID"}; - o2::framework::Configurable> tpctofHelium{"tpctofHelium", {}, "Maximum |nsigma| for Helium PID"}; + o2::framework::Configurable> itsHelium{"itsHelium", {}, "Ranges LowerLimit;UpperLimit for nsigma_ITS for Helium PID"}; + o2::framework::Configurable> tpcHelium{"tpcHelium", {}, "Ranges LowerLimit;UpperLimit for nsigma_TPC for Helium PID"}; + o2::framework::Configurable> tofHelium{"tofHelium", {}, "Ranges LowerLimit;UpperLimit for nsigma_TOF for Helium PID"}; + o2::framework::Configurable> tpcitsHelium{"tpcitsHelium", {}, "Maximum nsigma_TPCITS for Helium PID"}; + o2::framework::Configurable> tpctofHelium{"tpctofHelium", {}, "Maximum nsigma_TPCTOF for Helium PID"}; }; // define the template structure for TrackSelection @@ -144,8 +144,11 @@ struct ConfTrackSelection : public o2::framework::ConfigurableGroup { o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; // track selection masks - o2::framework::Configurable maskLowMomentum{"maskLowMomentum", 0x2u, "Bitmask for selections below momentum threshold"}; - o2::framework::Configurable maskHighMomentum{"maskHighMomentum", 0x1u, "Bitmask for selections above momentum threshold"}; + o2::framework::Configurable maskLowMomentum{"maskLowMomentum", 1ul, "Bitmask for selections below momentum threshold"}; + o2::framework::Configurable maskHighMomentum{"maskHighMomentum", 2ul, "Bitmask for selections above momentum threshold"}; + // track rejection masks + o2::framework::Configurable rejectionMaskLowMomentum{"rejectionMaskLowMomentum", 0ul, "Bitmask for rejections below momentum threshold"}; + o2::framework::Configurable rejectionMaskHighMomentum{"rejectionMaskHighMomentum", 0ul, "Bitmask for rejections above momentum threshold"}; // momentum threshold for PID usage o2::framework::Configurable pidThres{"pidThres", 1.2f, "Momentum threshold for using TPCTOF/TOF pid for tracks with large momentum (GeV/c)"}; }; @@ -283,12 +286,12 @@ class TrackSelection : public BaseSelection void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter) { - mPtMin = filter.ptMin; - mPtMax = filter.ptMax; - mEtaMin = filter.etaMin; - mEtaMax = filter.etaMax; - mPhiMin = filter.phiMin; - mPhiMax = filter.phiMax; + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; // add selections for track quality this->addSelection(kTPCnClsMin, trackSelectionNames.at(kTPCnClsMin), config.tpcClustersMin.value, limits::kLowerLimit, true, true, false); @@ -298,61 +301,61 @@ class TrackSelection : public BaseSelectionaddSelection(kTPCsClsFracMax, trackSelectionNames.at(kTPCsClsFracMax), config.tpcSharedClusterFractionMax.value, limits::kUpperLimit, true, true, false); this->addSelection(kITSnClsMin, trackSelectionNames.at(kITSnClsMin), config.itsClustersMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kITSnClsIbMin, trackSelectionNames.at(kITSnClsIbMin), config.itsIbClustersMin.value, limits::kLowerLimit, true, true, false); - this->addSelection(kDCAxyMax, trackSelectionNames.at(kDCAxyMax), filter.ptMin, filter.ptMax.value, config.dcaxyMax.value, limits::kAbsUpperFunctionLimit, true, true, false); + this->addSelection(kDCAxyMax, trackSelectionNames.at(kDCAxyMax), filter.ptMin.value, filter.ptMax.value, config.dcaxyMax.value, limits::kAbsUpperFunctionLimit, true, true, false); this->addSelection(kDCAzMax, trackSelectionNames.at(kDCAzMax), filter.ptMin.value, filter.ptMax.value, config.dcazMax.value, limits::kAbsUpperFunctionLimit, true, true, false); // add selections for Electron pid - this->addSelection(kItsElectron, trackSelectionNames.at(kItsElectron), config.itsElectron.value, limits::kAbsUpperLimit, false, false, config.requirePidElectron); - this->addSelection(kTpcElectron, trackSelectionNames.at(kTpcElectron), config.tpcElectron.value, limits::kAbsUpperLimit, false, false, config.requirePidElectron); - this->addSelection(kTofElectron, trackSelectionNames.at(kTofElectron), config.tofElectron.value, limits::kAbsUpperLimit, false, false, config.requirePidElectron); + this->addSelection(kItsElectron, trackSelectionNames.at(kItsElectron), config.itsElectron.value, false, false, config.requirePidElectron); + this->addSelection(kTpcElectron, trackSelectionNames.at(kTpcElectron), config.tpcElectron.value, false, false, config.requirePidElectron); + this->addSelection(kTofElectron, trackSelectionNames.at(kTofElectron), config.tofElectron.value, false, false, config.requirePidElectron); this->addSelection(kTpcitsElectron, trackSelectionNames.at(kTpcitsElectron), config.tpcitsElectron.value, limits::kUpperLimit, false, false, config.requirePidElectron); this->addSelection(kTpctofElectron, trackSelectionNames.at(kTpctofElectron), config.tpctofElectron.value, limits::kUpperLimit, false, false, config.requirePidElectron); mElectronTofThres = config.minMomTofElectron.value; // add selections for Pion pid - this->addSelection(kItsPion, trackSelectionNames.at(kItsPion), config.itsPion.value, limits::kAbsUpperLimit, false, false, config.requirePidPion); - this->addSelection(kTpcPion, trackSelectionNames.at(kTpcPion), config.tpcPion.value, limits::kAbsUpperLimit, false, false, config.requirePidPion); - this->addSelection(kTofPion, trackSelectionNames.at(kTofPion), config.tofPion.value, limits::kAbsUpperLimit, false, false, config.requirePidPion); + this->addSelection(kItsPion, trackSelectionNames.at(kItsPion), config.itsPion.value, false, false, config.requirePidPion); + this->addSelection(kTpcPion, trackSelectionNames.at(kTpcPion), config.tpcPion.value, false, false, config.requirePidPion); + this->addSelection(kTofPion, trackSelectionNames.at(kTofPion), config.tofPion.value, false, false, config.requirePidPion); this->addSelection(kTpcitsPion, trackSelectionNames.at(kTpcitsPion), config.tpcitsPion.value, limits::kUpperLimit, false, false, config.requirePidPion); this->addSelection(kTpctofPion, trackSelectionNames.at(kTpctofPion), config.tpctofPion.value, limits::kUpperLimit, false, false, config.requirePidPion); mPionTofThres = config.minMomTofPion.value; // add selections for Kaon pid - this->addSelection(kItsKaon, trackSelectionNames.at(kItsKaon), config.itsKaon.value, limits::kAbsUpperLimit, false, false, config.requirePidKaon); - this->addSelection(kTpcKaon, trackSelectionNames.at(kTpcKaon), config.tpcKaon.value, limits::kAbsUpperLimit, false, false, config.requirePidKaon); - this->addSelection(kTofKaon, trackSelectionNames.at(kTofKaon), config.tofKaon.value, limits::kAbsUpperLimit, false, false, config.requirePidKaon); + this->addSelection(kItsKaon, trackSelectionNames.at(kItsKaon), config.itsKaon.value, false, false, config.requirePidKaon); + this->addSelection(kTpcKaon, trackSelectionNames.at(kTpcKaon), config.tpcKaon.value, false, false, config.requirePidKaon); + this->addSelection(kTofKaon, trackSelectionNames.at(kTofKaon), config.tofKaon.value, false, false, config.requirePidKaon); this->addSelection(kTpcitsKaon, trackSelectionNames.at(kTpcitsKaon), config.tpcitsKaon.value, limits::kUpperLimit, false, false, config.requirePidKaon); this->addSelection(kTpctofKaon, trackSelectionNames.at(kTpctofKaon), config.tpctofKaon.value, limits::kUpperLimit, false, false, config.requirePidKaon); mKaonTofThres = config.minMomTofKaon.value; // add selections for Proton pid - this->addSelection(kItsProton, trackSelectionNames.at(kItsProton), config.itsProton.value, limits::kAbsUpperLimit, false, false, config.requirePidProton); - this->addSelection(kTpcProton, trackSelectionNames.at(kTpcProton), config.tpcProton.value, limits::kAbsUpperLimit, false, false, config.requirePidProton); - this->addSelection(kTofProton, trackSelectionNames.at(kTofProton), config.tofProton.value, limits::kAbsUpperLimit, false, false, config.requirePidProton); + this->addSelection(kItsProton, trackSelectionNames.at(kItsProton), config.itsProton.value, false, false, config.requirePidProton); + this->addSelection(kTpcProton, trackSelectionNames.at(kTpcProton), config.tpcProton.value, false, false, config.requirePidProton); + this->addSelection(kTofProton, trackSelectionNames.at(kTofProton), config.tofProton.value, false, false, config.requirePidProton); this->addSelection(kTpcitsProton, trackSelectionNames.at(kTpcitsProton), config.tpcitsProton.value, limits::kUpperLimit, false, false, config.requirePidProton); this->addSelection(kTpctofProton, trackSelectionNames.at(kTpctofProton), config.tpctofProton.value, limits::kUpperLimit, false, false, config.requirePidProton); mProtonTofThres = config.minMomTofProton.value; // add selections for Deuteron pid - this->addSelection(kItsDeuteron, trackSelectionNames.at(kItsDeuteron), config.itsDeuteron.value, limits::kAbsUpperLimit, false, false, config.requirePidDeuteron); - this->addSelection(kTpcDeuteron, trackSelectionNames.at(kTpcDeuteron), config.tpcDeuteron.value, limits::kAbsUpperLimit, false, false, config.requirePidDeuteron); - this->addSelection(kTofDeuteron, trackSelectionNames.at(kTofDeuteron), config.tofDeuteron.value, limits::kAbsUpperLimit, false, false, config.requirePidDeuteron); + this->addSelection(kItsDeuteron, trackSelectionNames.at(kItsDeuteron), config.itsDeuteron.value, false, false, config.requirePidDeuteron); + this->addSelection(kTpcDeuteron, trackSelectionNames.at(kTpcDeuteron), config.tpcDeuteron.value, false, false, config.requirePidDeuteron); + this->addSelection(kTofDeuteron, trackSelectionNames.at(kTofDeuteron), config.tofDeuteron.value, false, false, config.requirePidDeuteron); this->addSelection(kTpcitsDeuteron, trackSelectionNames.at(kTpcitsDeuteron), config.tpcitsDeuteron.value, limits::kUpperLimit, false, false, config.requirePidDeuteron); this->addSelection(kTpctofDeuteron, trackSelectionNames.at(kTpctofDeuteron), config.tpctofDeuteron.value, limits::kUpperLimit, false, false, config.requirePidDeuteron); mDeuteronTofThres = config.minMomTofDeuteron.value; // add selections for Triton pid - this->addSelection(kItsTriton, trackSelectionNames.at(kItsTriton), config.itsTriton.value, limits::kAbsUpperLimit, false, false, config.requirePidTriton); - this->addSelection(kTpcTriton, trackSelectionNames.at(kTpcTriton), config.tpcTriton.value, limits::kAbsUpperLimit, false, false, config.requirePidTriton); - this->addSelection(kTofTriton, trackSelectionNames.at(kTofTriton), config.tofTriton.value, limits::kAbsUpperLimit, false, false, config.requirePidTriton); + this->addSelection(kItsTriton, trackSelectionNames.at(kItsTriton), config.itsTriton.value, false, false, config.requirePidTriton); + this->addSelection(kTpcTriton, trackSelectionNames.at(kTpcTriton), config.tpcTriton.value, false, false, config.requirePidTriton); + this->addSelection(kTofTriton, trackSelectionNames.at(kTofTriton), config.tofTriton.value, false, false, config.requirePidTriton); this->addSelection(kTpcitsTriton, trackSelectionNames.at(kTpcitsTriton), config.tpcitsTriton.value, limits::kUpperLimit, false, false, config.requirePidTriton); this->addSelection(kTpctofTriton, trackSelectionNames.at(kTpctofTriton), config.tpctofTriton.value, limits::kUpperLimit, false, false, config.requirePidTriton); mTritonTofThres = config.minMomTofTriton.value; // add selections for Helium pid - this->addSelection(kItsHelium, trackSelectionNames.at(kItsHelium), config.itsHelium.value, limits::kAbsUpperLimit, false, false, config.requirePidHelium); - this->addSelection(kTpcHelium, trackSelectionNames.at(kTpcHelium), config.tpcHelium.value, limits::kAbsUpperLimit, false, false, config.requirePidHelium); - this->addSelection(kTofHelium, trackSelectionNames.at(kTofHelium), config.tofHelium.value, limits::kAbsUpperLimit, false, false, config.requirePidHelium); + this->addSelection(kItsHelium, trackSelectionNames.at(kItsHelium), config.itsHelium.value, false, false, config.requirePidHelium); + this->addSelection(kTpcHelium, trackSelectionNames.at(kTpcHelium), config.tpcHelium.value, false, false, config.requirePidHelium); + this->addSelection(kTofHelium, trackSelectionNames.at(kTofHelium), config.tofHelium.value, false, false, config.requirePidHelium); this->addSelection(kTpcitsHelium, trackSelectionNames.at(kTpcitsHelium), config.tpcitsHelium.value, limits::kUpperLimit, false, false, config.requirePidHelium); this->addSelection(kTpctofHelium, trackSelectionNames.at(kTpctofHelium), config.tpctofHelium.value, limits::kUpperLimit, false, false, config.requirePidHelium); mHeliumTofThres = config.minMomTofHelium.value; @@ -378,30 +381,20 @@ class TrackSelection : public BaseSelectionevaluateObservable(its, nsigmaIts); - this->evaluateObservable(tpc, nsigmaTpc); - this->evaluateObservable(tpcits, std::hypot(nsigmaTpc, nsigmaIts)); - this->evaluateObservable(tof, nsigmaTof); - this->evaluateObservable(tpctof, std::hypot(nsigmaTpc, nsigmaTof)); + // above threshold without TOF: skip entirely unless forced + // forced evaluation is used in the second pass to populate rejection bits + if (!ignoreThreshold && Track.p() >= tofThreshold && !Track.hasTOF()) { return; } - // if track is above threshold, check if TOF PID is available - // if not, we dont check any selection and they stay at reseted values, i.e. the cut fails + this->evaluateObservable(its, nsigmaIts); + this->evaluateObservable(tpc, nsigmaTpc); + this->evaluateObservable(tpcits, std::hypot(nsigmaTpc, nsigmaIts)); if (Track.hasTOF()) { - // if tof inforamtion is available, check them first this->evaluateObservable(tof, nsigmaTof); this->evaluateObservable(tpctof, std::hypot(nsigmaTpc, nsigmaTof)); - // if both failed, the bitmask will be 0 and there is no need to check tpc and its information since we do not want to have this track - // so if we just bail out here, the PID for this particle type will failed for its, tpc and tof - if (this->passesOptionalSelection(tof) || this->passesOptionalSelection(tpctof)) { - this->evaluateObservable(its, nsigmaIts); - this->evaluateObservable(tpc, nsigmaTpc); - this->evaluateObservable(tpcits, std::hypot(nsigmaTpc, nsigmaIts)); - } } } @@ -416,90 +409,34 @@ class TrackSelection : public BaseSelectionevaluateObservable(kTPCsClsFracMax, static_cast(Track.tpcNClsShared()) / static_cast(Track.tpcNClsFound())); this->evaluateObservable(kITSnClsMin, Track.itsNCls()); this->evaluateObservable(kITSnClsIbMin, Track.itsNClsInnerBarrel()); - - // evalue bitmask for pt dependent dca cuts this->updateLimits(kDCAxyMax, Track.pt()); this->evaluateObservable(kDCAxyMax, Track.dcaXY()); - this->updateLimits(kDCAzMax, Track.pt()); this->evaluateObservable(kDCAzMax, Track.dcaZ()); - this->evaluatePid(Track, - mElectronTofThres, - Track.itsNSigmaEl(), - Track.tpcNSigmaEl(), - Track.tofNSigmaEl(), - kItsElectron, - kTpcElectron, - kTofElectron, - kTpcitsElectron, - kTpctofElectron); - - this->evaluatePid(Track, - mPionTofThres, - Track.itsNSigmaPi(), - Track.tpcNSigmaPi(), - Track.tofNSigmaPi(), - kItsPion, - kTpcPion, - kTofPion, - kTpcitsPion, - kTpctofPion); - - this->evaluatePid(Track, - mKaonTofThres, - Track.itsNSigmaKa(), - Track.tpcNSigmaKa(), - Track.tofNSigmaKa(), - kItsKaon, - kTpcKaon, - kTofKaon, - kTpcitsKaon, - kTpctofKaon); - - this->evaluatePid(Track, - mProtonTofThres, - Track.itsNSigmaPr(), - Track.tpcNSigmaPr(), - Track.tofNSigmaPr(), - kItsProton, - kTpcProton, - kTofProton, - kTpcitsProton, - kTpctofProton); - - this->evaluatePid(Track, - mDeuteronTofThres, - Track.itsNSigmaDe(), - Track.tpcNSigmaDe(), - Track.tofNSigmaDe(), - kItsDeuteron, - kTpcDeuteron, - kTofDeuteron, - kTpcitsDeuteron, - kTpctofDeuteron); - - this->evaluatePid(Track, - mTritonTofThres, - Track.itsNSigmaTr(), - Track.tpcNSigmaTr(), - Track.tofNSigmaTr(), - kItsTriton, - kTpcTriton, - kTofTriton, - kTpcitsTriton, - kTpctofTriton); - - this->evaluatePid(Track, - mHeliumTofThres, - Track.itsNSigmaHe(), - Track.tpcNSigmaHe(), - Track.tofNSigmaHe(), - kItsHelium, - kTpcHelium, - kTofHelium, - kTpcitsHelium, - kTpctofHelium); + // first pass: threshold-aware PID evaluation + // determines if the track passes any optional selection and should be stored + this->evaluatePid(Track, mElectronTofThres, Track.itsNSigmaEl(), Track.tpcNSigmaEl(), Track.tofNSigmaEl(), kItsElectron, kTpcElectron, kTofElectron, kTpcitsElectron, kTpctofElectron); + this->evaluatePid(Track, mPionTofThres, Track.itsNSigmaPi(), Track.tpcNSigmaPi(), Track.tofNSigmaPi(), kItsPion, kTpcPion, kTofPion, kTpcitsPion, kTpctofPion); + this->evaluatePid(Track, mKaonTofThres, Track.itsNSigmaKa(), Track.tpcNSigmaKa(), Track.tofNSigmaKa(), kItsKaon, kTpcKaon, kTofKaon, kTpcitsKaon, kTpctofKaon); + this->evaluatePid(Track, mProtonTofThres, Track.itsNSigmaPr(), Track.tpcNSigmaPr(), Track.tofNSigmaPr(), kItsProton, kTpcProton, kTofProton, kTpcitsProton, kTpctofProton); + this->evaluatePid(Track, mDeuteronTofThres, Track.itsNSigmaDe(), Track.tpcNSigmaDe(), Track.tofNSigmaDe(), kItsDeuteron, kTpcDeuteron, kTofDeuteron, kTpcitsDeuteron, kTpctofDeuteron); + this->evaluatePid(Track, mTritonTofThres, Track.itsNSigmaTr(), Track.tpcNSigmaTr(), Track.tofNSigmaTr(), kItsTriton, kTpcTriton, kTofTriton, kTpcitsTriton, kTpctofTriton); + this->evaluatePid(Track, mHeliumTofThres, Track.itsNSigmaHe(), Track.tpcNSigmaHe(), Track.tofNSigmaHe(), kItsHelium, kTpcHelium, kTofHelium, kTpcitsHelium, kTpctofHelium); + + // second pass: if the track passes minimal and any optional selection, + // re-evaluate all species ignoring thresholds so rejection bits are fully + // populated for all competing hypotheses. evaluate() resets each container + // before writing, so no explicit reset is needed before this pass. + if (this->passesAllRequiredSelections()) { + this->evaluatePid(Track, mElectronTofThres, Track.itsNSigmaEl(), Track.tpcNSigmaEl(), Track.tofNSigmaEl(), kItsElectron, kTpcElectron, kTofElectron, kTpcitsElectron, kTpctofElectron, true); + this->evaluatePid(Track, mPionTofThres, Track.itsNSigmaPi(), Track.tpcNSigmaPi(), Track.tofNSigmaPi(), kItsPion, kTpcPion, kTofPion, kTpcitsPion, kTpctofPion, true); + this->evaluatePid(Track, mKaonTofThres, Track.itsNSigmaKa(), Track.tpcNSigmaKa(), Track.tofNSigmaKa(), kItsKaon, kTpcKaon, kTofKaon, kTpcitsKaon, kTpctofKaon, true); + this->evaluatePid(Track, mProtonTofThres, Track.itsNSigmaPr(), Track.tpcNSigmaPr(), Track.tofNSigmaPr(), kItsProton, kTpcProton, kTofProton, kTpcitsProton, kTpctofProton, true); + this->evaluatePid(Track, mDeuteronTofThres, Track.itsNSigmaDe(), Track.tpcNSigmaDe(), Track.tofNSigmaDe(), kItsDeuteron, kTpcDeuteron, kTofDeuteron, kTpcitsDeuteron, kTpctofDeuteron, true); + this->evaluatePid(Track, mTritonTofThres, Track.itsNSigmaTr(), Track.tpcNSigmaTr(), Track.tofNSigmaTr(), kItsTriton, kTpcTriton, kTofTriton, kTpcitsTriton, kTpctofTriton, true); + this->evaluatePid(Track, mHeliumTofThres, Track.itsNSigmaHe(), Track.tpcNSigmaHe(), Track.tofNSigmaHe(), kItsHelium, kTpcHelium, kTofHelium, kTpcitsHelium, kTpctofHelium, true); + } this->assembleBitmask(); } diff --git a/PWGCF/Femto/Macros/cutculator.py b/PWGCF/Femto/Macros/cutculator.py index 9e1d771b6da..34f9b2054c3 100755 --- a/PWGCF/Femto/Macros/cutculator.py +++ b/PWGCF/Femto/Macros/cutculator.py @@ -49,12 +49,20 @@ def ask_user_selection(group): Prompt user to select bin(s) for this selection group. - If minimal selections contain exactly 1 entry → auto-select it. - Optional selections remain user-selectable. + - Neither minimal nor optional selections are shown with a warning — useful for rejection masks. """ selection_name = group[0].get("SelectionName", "unknown") - # Separate minimal and optional bins + # Separate bins by type minimal_bins = [b for b in group if b.get("MinimalCut", "0") == "1" and b.get("OptionalCut", "0") == "0"] optional_bins = [b for b in group if b.get("OptionalCut", "0") == "1"] + neutral_bins = [ + b + for b in group + if b.get("MinimalCut", "0") == "0" + and b.get("OptionalCut", "0") == "0" + and b.get("BitPosition", "X").upper() != "X" + ] selected_bins = [] @@ -107,7 +115,34 @@ def ask_user_selection(group): b = optional_bins[i - 1] selected_bins.append(b) chosen.append(format_value_with_comment(b)) + print("Selected: " + ", ".join(chosen)) + break + except ValueError: + pass + + print("Invalid input. Please enter valid indices separated by space.") + # ----- Neither minimal nor optional----- + if neutral_bins: + print(f"\nSelection: {selection_name} (Neither minimal nor optional, 0 to skip)") + for idx, b in enumerate(neutral_bins, start=1): + print(f" [{idx}] {format_value_with_comment(b)}") + + while True: + sel_input = input("Enter indices separated by space (0 to skip): ") + if not sel_input.strip() or sel_input.strip() == "0": + print("Selected: (skipped)") + break + + try: + indices = [int(x) for x in sel_input.split()] + if all(0 <= i <= len(neutral_bins) for i in indices): + chosen = [] + for i in indices: + if i != 0: + b = neutral_bins[i - 1] + selected_bins.append(b) + chosen.append(format_value_with_comment(b)) print("Selected: " + ", ".join(chosen)) break except ValueError: diff --git a/PWGCF/Femto/Macros/cutculatorGui.py b/PWGCF/Femto/Macros/cutculatorGui.py new file mode 100755 index 00000000000..db776251e77 --- /dev/null +++ b/PWGCF/Femto/Macros/cutculatorGui.py @@ -0,0 +1,437 @@ +#!/usr/bin/env python3 + +# Copyright 2019-2025 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 CutCulator GUI (Compute bitmask for selecting particles in the Femto Framework) +@author Anton Riedel , Technical University of Munich +""" + +import tkinter as tk +from tkinter import ttk, filedialog, messagebox +import argparse +import sys + +try: + import ROOT + + ROOT.gROOT.SetBatch(True) +except ImportError: + ROOT = None + +VALUE_DELIM = "___" +SECTION_DELIM = ":::" + +# ── Colours ────────────────────────────────────────────────────────────────── +BG = "#1e1e2e" +BG_CARD = "#2a2a3e" +BG_HOVER = "#3a3a50" +ACCENT = "#89b4fa" # blue – minimal +ACCENT_OPT = "#a6e3a1" # green – optional +ACCENT_REJ = "#f38ba8" # red – rejection / neutral +FG = "#cdd6f4" +FG_DIM = "#6c7086" +BORDER = "#45475a" +SEL_BG = "#313244" + +FONT_TITLE = ("Inter", 15, "bold") +FONT_HEAD = ("Inter", 11, "bold") +FONT_BODY = ("Inter", 10) +FONT_MONO = ("JetBrains Mono", 11, "bold") +FONT_SMALL = ("Inter", 9) + + +# ── Helpers ─────────────────────────────────────────────────────────────────── +def parse_bin_label(label): + result = {} + for sec in label.split(SECTION_DELIM): + if VALUE_DELIM in sec: + k, v = sec.split(VALUE_DELIM, 1) + result[k.strip()] = v.strip() + return result + + +def format_value_with_comment(b): + val = b.get("Value", "") + comment = b.get("Comment", "") + if comment and comment.upper() != "X": + return f"{val} ({comment})" + return val + + +def bin_type(b): + """Return 'minimal', 'optional', 'neutral', or 'skip'.""" + is_min = b.get("MinimalCut", "0") == "1" + is_opt = b.get("OptionalCut", "0") == "1" + pos = b.get("BitPosition", "X") + if pos.upper() == "X": + return "skip" + if is_min and not is_opt: + return "minimal" + if is_opt: + return "optional" + return "neutral" + + +def load_bins_from_hist(hist): + nbins = hist.GetNbinsX() + bins = [] + for i in range(1, nbins - 2 + 1): + label = hist.GetXaxis().GetBinLabel(i) + if not label: + continue + b = parse_bin_label(label) + b["_bin_index"] = i + bins.append(b) + # group by SelectionName preserving order + groups = {} + for b in bins: + name = b.get("SelectionName", f"unknown_{b['_bin_index']}") + groups.setdefault(name, []).append(b) + return groups + + +# ── Main Application ────────────────────────────────────────────────────────── +class CutCulatorApp(tk.Tk): + def __init__(self, rootfile=None, tdir="femto-producer"): + super().__init__() + self.title("CutCulator") + self.configure(bg=BG) + self.geometry("920x720") + self.minsize(780, 560) + self.resizable(True, True) + + self._rootfile_path = rootfile + self._tdir_path = tdir + self._root_file = None + self._hist = None + self._groups = {} # SelectionName → list[bin_dict] + self._vars = {} # (SelectionName, idx) → BooleanVar + + self._build_ui() + + if rootfile: + self._load_file(rootfile) + + # ── UI skeleton ────────────────────────────────────────────────────────── + def _build_ui(self): + # ── top bar ── + top = tk.Frame(self, bg=BG, pady=10, padx=18) + top.pack(fill="x") + + tk.Label(top, text="✂ CutCulator", font=FONT_TITLE, bg=BG, fg=ACCENT).pack(side="left") + + btn_frame = tk.Frame(top, bg=BG) + btn_frame.pack(side="right") + self._btn_open = self._make_button(btn_frame, "📂 Open ROOT file", self._open_file_dialog, ACCENT) + self._btn_open.pack(side="left", padx=4) + + # ── file + histogram selector bar ── + bar = tk.Frame(self, bg=BG_CARD, pady=8, padx=18) + bar.pack(fill="x") + + tk.Label(bar, text="File:", font=FONT_BODY, bg=BG_CARD, fg=FG_DIM).pack(side="left") + self._lbl_file = tk.Label(bar, text="(none)", font=FONT_BODY, bg=BG_CARD, fg=FG, wraplength=400, anchor="w") + self._lbl_file.pack(side="left", padx=6) + + tk.Label(bar, text="Histogram:", font=FONT_BODY, bg=BG_CARD, fg=FG_DIM).pack(side="left", padx=(20, 0)) + self._hist_var = tk.StringVar() + self._hist_combo = ttk.Combobox(bar, textvariable=self._hist_var, state="disabled", width=30, font=FONT_BODY) + self._hist_combo.pack(side="left", padx=6) + self._hist_combo.bind("<>", self._on_hist_selected) + + self._style_combobox() + + # ── legend ── + legend = tk.Frame(self, bg=BG, pady=4, padx=18) + legend.pack(fill="x") + for color, label in [(ACCENT, "Minimal"), (ACCENT_OPT, "Optional"), (ACCENT_REJ, "Neutral")]: + dot = tk.Label(legend, text="●", font=FONT_BODY, bg=BG, fg=color) + dot.pack(side="left") + tk.Label(legend, text=label, font=FONT_SMALL, bg=BG, fg=FG_DIM).pack(side="left", padx=(2, 12)) + + # ── scrollable selection area ── + outer = tk.Frame(self, bg=BG) + outer.pack(fill="both", expand=True, padx=12, pady=4) + + self._canvas = tk.Canvas(outer, bg=BG, highlightthickness=0, bd=0) + vsb = ttk.Scrollbar(outer, orient="vertical", command=self._canvas.yview) + self._canvas.configure(yscrollcommand=vsb.set) + vsb.pack(side="right", fill="y") + self._canvas.pack(side="left", fill="both", expand=True) + + self._inner = tk.Frame(self._canvas, bg=BG) + self._canvas_win = self._canvas.create_window((0, 0), window=self._inner, anchor="nw") + self._inner.bind("", self._on_inner_configure) + self._canvas.bind("", self._on_canvas_configure) + self._canvas.bind_all("", self._on_mousewheel) + self._canvas.bind_all("", self._on_mousewheel) + self._canvas.bind_all("", self._on_mousewheel) + + # ── bottom result bar ── + bottom = tk.Frame(self, bg=BG_CARD, pady=10, padx=18) + bottom.pack(fill="x", side="bottom") + + tk.Label(bottom, text="Bitmask:", font=FONT_HEAD, bg=BG_CARD, fg=FG).pack(side="left") + + self._lbl_dec = tk.Label(bottom, text="—", font=FONT_MONO, bg=BG_CARD, fg=ACCENT, width=14, anchor="w") + self._lbl_dec.pack(side="left", padx=8) + + self._lbl_hex = tk.Label(bottom, text="—", font=FONT_MONO, bg=BG_CARD, fg=ACCENT_OPT, width=14, anchor="w") + self._lbl_hex.pack(side="left", padx=8) + + self._lbl_bin = tk.Label(bottom, text="—", font=FONT_MONO, bg=BG_CARD, fg=FG_DIM, anchor="w") + self._lbl_bin.pack(side="left", padx=8) + + copy_frame = tk.Frame(bottom, bg=BG_CARD) + copy_frame.pack(side="right") + self._make_button(copy_frame, "Copy Dec", lambda: self._copy(self._lbl_dec["text"]), ACCENT).pack( + side="left", padx=3 + ) + self._make_button(copy_frame, "Copy Hex", lambda: self._copy(self._lbl_hex["text"]), ACCENT_OPT).pack( + side="left", padx=3 + ) + + # ── Combobox styling ────────────────────────────────────────────────────── + def _style_combobox(self): + s = ttk.Style(self) + s.theme_use("clam") + s.configure( + "TCombobox", + fieldbackground=BG_CARD, + background=BG_CARD, + foreground=FG, + selectbackground=SEL_BG, + selectforeground=FG, + bordercolor=BORDER, + arrowcolor=ACCENT, + ) + s.map("TCombobox", fieldbackground=[("readonly", BG_CARD)]) + s.configure("TScrollbar", troughcolor=BG, background=BORDER) + + # ── Canvas resize helpers ───────────────────────────────────────────────── + def _on_inner_configure(self, _e=None): + self._canvas.configure(scrollregion=self._canvas.bbox("all")) + + def _on_canvas_configure(self, e): + self._canvas.itemconfig(self._canvas_win, width=e.width) + + def _on_mousewheel(self, e): + if e.num == 4: + self._canvas.yview_scroll(-1, "units") + elif e.num == 5: + self._canvas.yview_scroll(1, "units") + else: + self._canvas.yview_scroll(int(-1 * (e.delta / 120)), "units") + + # ── File / histogram loading ────────────────────────────────────────────── + def _open_file_dialog(self): + path = filedialog.askopenfilename( + title="Open ROOT file", filetypes=[("ROOT files", "*.root"), ("All files", "*.*")] + ) + if path: + self._load_file(path) + + def _load_file(self, path): + if ROOT is None: + messagebox.showerror("Missing dependency", "PyROOT is not available. Please install ROOT.") + return + f = ROOT.TFile.Open(path) + if not f or f.IsZombie(): + messagebox.showerror("Error", f"Cannot open ROOT file:\n{path}") + return + self._root_file = f + self._lbl_file.config(text=path) + + d = f.Get(self._tdir_path) + if not d: + messagebox.showerror("Error", f"Directory '{self._tdir_path}' not found in file.") + return + + histograms = [k.GetName() for k in d.GetListOfKeys() if k.ReadObj().InheritsFrom("TH1")] + if not histograms: + messagebox.showwarning("Warning", "No TH1 histograms found in directory.") + return + + self._hist_combo.config(values=histograms, state="readonly") + self._hist_combo.current(0) + self._on_hist_selected() + + def _on_hist_selected(self, _e=None): + if self._root_file is None: + return + d = self._root_file.Get(self._tdir_path) + if not d: + return + hname = self._hist_var.get() + hist = d.Get(hname) + if not hist: + return + self._hist = hist + self._groups = load_bins_from_hist(hist) + self._vars = {} + self._build_selections() + self._update_bitmask() + + # ── Selection cards ─────────────────────────────────────────────────────── + def _build_selections(self): + for w in self._inner.winfo_children(): + w.destroy() + + for sel_name, group in self._groups.items(): + self._build_group_card(sel_name, group) + + self._on_inner_configure() + + def _build_group_card(self, sel_name, group): + # categorise + minimal = [(i, b) for i, b in enumerate(group) if bin_type(b) == "minimal"] + optional = [(i, b) for i, b in enumerate(group) if bin_type(b) == "optional"] + neutral = [(i, b) for i, b in enumerate(group) if bin_type(b) == "neutral"] + + if not (minimal or optional or neutral): + return # nothing to show (all "skip") + + card = tk.Frame(self._inner, bg=BG_CARD, bd=0, highlightthickness=1, highlightbackground=BORDER) + card.pack(fill="x", padx=10, pady=5, ipadx=8, ipady=6) + + # header row + hdr = tk.Frame(card, bg=BG_CARD) + hdr.pack(fill="x", padx=6, pady=(4, 2)) + tk.Label(hdr, text=sel_name, font=FONT_HEAD, bg=BG_CARD, fg=FG).pack(side="left") + + # show the loosest (most permissive) minimal threshold as a hint. + # the truly loosest threshold has mSkipMostPermissiveBit=true so its + # BitPosition is "X" — it lands in the "skip" category. check there first, + # then fall back to the loosest bit-carrying minimal bin. + skipped_minimal = [ + b for b in group if b.get("MinimalCut", "0") == "1" and b.get("BitPosition", "X").upper() == "X" + ] + if skipped_minimal: + loosest_val = format_value_with_comment(skipped_minimal[0]) + tk.Label( + hdr, text=f"minimal cut → loosest selection: {loosest_val}", font=FONT_SMALL, bg=BG_CARD, fg=FG_DIM + ).pack(side="left", padx=10) + elif minimal: + loosest_val = format_value_with_comment(minimal[0][1]) + tk.Label( + hdr, text=f"minimal cut → loosest selection: {loosest_val}", font=FONT_SMALL, bg=BG_CARD, fg=FG_DIM + ).pack(side="left", padx=10) + elif optional: + tk.Label(hdr, text="optional", font=FONT_SMALL, bg=BG_CARD, fg=ACCENT_OPT).pack(side="left", padx=10) + elif neutral: + tk.Label(hdr, text="neutral", font=FONT_SMALL, bg=BG_CARD, fg=ACCENT_REJ).pack(side="left", padx=10) + + # separator + tk.Frame(card, bg=BORDER, height=1).pack(fill="x", padx=6, pady=2) + + # bins + bins_frame = tk.Frame(card, bg=BG_CARD) + bins_frame.pack(fill="x", padx=6, pady=4) + + for i, b in minimal: + self._build_bin_row(bins_frame, sel_name, i, b, "minimal") + for i, b in optional: + self._build_bin_row(bins_frame, sel_name, i, b, "optional") + for i, b in neutral: + self._build_bin_row(bins_frame, sel_name, i, b, "neutral") + + def _build_bin_row(self, parent, sel_name, idx, b, kind): + color = {"minimal": ACCENT, "optional": ACCENT_OPT, "neutral": ACCENT_REJ}[kind] + label_text = format_value_with_comment(b) + + var = tk.BooleanVar(value=False) + + self._vars[(sel_name, idx)] = var + + row = tk.Frame(parent, bg=BG_CARD) + row.pack(fill="x", pady=1) + + # coloured dot + tk.Label(row, text="●", font=FONT_BODY, bg=BG_CARD, fg=color).pack(side="left", padx=(0, 4)) + + # checkbox styled as a toggle button + cb = tk.Checkbutton( + row, + text=label_text, + variable=var, + font=FONT_BODY, + bg=BG_CARD, + fg=FG, + activebackground=BG_HOVER, + activeforeground=FG, + selectcolor=SEL_BG, + relief="flat", + bd=0, + highlightthickness=0, + cursor="hand2", + command=self._update_bitmask, + ) + cb.pack(side="left", fill="x", expand=True) + + # bit-position badge + pos = b.get("BitPosition", "X") + if pos.upper() != "X": + tk.Label(row, text=f"bit {pos}", font=FONT_SMALL, bg=BG_CARD, fg=FG_DIM, width=8).pack(side="right", padx=4) + + # ── Bitmask computation ─────────────────────────────────────────────────── + def _update_bitmask(self): + bitmask = 0 + for (sel_name, idx), var in self._vars.items(): + if not var.get(): + continue + b = self._groups[sel_name][idx] + pos = b.get("BitPosition", "X") + if pos.upper() == "X": + continue + bitmask |= 1 << int(pos) + + self._lbl_dec.config(text=str(bitmask)) + self._lbl_hex.config(text=hex(bitmask)) + self._lbl_bin.config(text=bin(bitmask)) + + # ── Utilities ───────────────────────────────────────────────────────────── + def _copy(self, text): + self.clipboard_clear() + self.clipboard_append(text) + self.update() + + @staticmethod + def _make_button(parent, text, cmd, color): + return tk.Button( + parent, + text=text, + command=cmd, + font=FONT_BODY, + bg=BG_CARD, + fg=color, + activebackground=BG_HOVER, + activeforeground=color, + relief="flat", + bd=0, + padx=10, + pady=4, + highlightthickness=1, + highlightbackground=color, + cursor="hand2", + ) + + +# ── Entry point ─────────────────────────────────────────────────────────────── +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="CutCulator GUI") + parser.add_argument("rootfile", nargs="?", default=None, help="Path to ROOT file (optional, can be opened via GUI)") + parser.add_argument("--dir", default="femto-producer", help="TDirectory path in ROOT file") + args = parser.parse_args() + + app = CutCulatorApp(rootfile=args.rootfile, tdir=args.dir) + app.mainloop() diff --git a/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h b/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h index 538675f3a9d..8a455f073eb 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h @@ -223,6 +223,10 @@ class FemtoDreamCollisionSelection mHistogramQn->add("Event/centVsqnVsSpher", "; cent; qn; Sphericity", kTH3F, {{10, 0, 100}, {100, 0, 1000}, {100, 0, 1}}); mHistogramQn->add("Event/qnBin", "; qnBin; entries", kTH1F, {{20, 0, 20}}); mHistogramQn->add("Event/psiEP", "; #Psi_{EP} (deg); entries", kTH1F, {{100, 0, 180}}); + mHistogramQn->add("Event/epReso_FT0CTPC", "; cent; qnBin; reso_ft0c_tpc", kTH2F, {{10, 0, 100}, {10, 0, 10}}); + mHistogramQn->add("Event/epReso_FT0ATPC", "; cent; qnBin; reso_ft0a_tpc", kTH2F, {{10, 0, 100}, {10, 0, 10}}); + mHistogramQn->add("Event/epReso_FT0CFT0A", "; cent; qnBin; reso_ft0c_ft0a", kTH2F, {{10, 0, 100}, {10, 0, 10}}); + mHistogramQn->add("Event/epReso_count", "; cent; qnBin; count", kTH2F, {{10, 0, 100}, {10, 0, 10}}); return; } @@ -330,9 +334,17 @@ class FemtoDreamCollisionSelection /// \param col Collision /// \return value of the qn-vector of FT0C of the event template - float computeqnVec(T const& col) + float computeqnVec(T const& col, int qvecMod = 0) { - double qn = std::sqrt(col.qvecFT0CReVec()[0] * col.qvecFT0CReVec()[0] + col.qvecFT0CImVec()[0] * col.qvecFT0CImVec()[0]) * std::sqrt(col.sumAmplFT0C()); + double qn = -999.f; + if (qvecMod == 0) { + qn = std::sqrt(col.qvecFT0CReVec()[0] * col.qvecFT0CReVec()[0] + col.qvecFT0CImVec()[0] * col.qvecFT0CImVec()[0]) * std::sqrt(col.sumAmplFT0C()); + } else if (qvecMod == 1) { + qn = std::sqrt(col.qvecFT0AReVec()[0] * col.qvecFT0AReVec()[0] + col.qvecFT0AImVec()[0] * col.qvecFT0AImVec()[0]) * std::sqrt(col.sumAmplFT0A()); + } else { + LOGP(error, "no selected detector of Qvec for ESE "); + return qn; + } return qn; } @@ -342,15 +354,43 @@ class FemtoDreamCollisionSelection /// \param nmode EP in which harmonic(default 2nd harmonic) /// \return angle of the event plane (rad) of FT0C of the event template - float computeEP(T const& col, int nmode) + float computeEP(T const& col, int nmode, int qvecMod) { - double EP = ((1. / nmode) * (TMath::ATan2(col.qvecFT0CImVec()[0], col.qvecFT0CReVec()[0]))); - if (EP < 0) + double EP = -999.f; + if (qvecMod == 0) { + EP = ((1. / nmode) * (TMath::ATan2(col.qvecFT0CImVec()[0], col.qvecFT0CReVec()[0]))); + } else if (qvecMod == 1) { + EP = ((1. / nmode) * (TMath::ATan2(col.qvecFT0AImVec()[0], col.qvecFT0AReVec()[0]))); + } else if (qvecMod == 2) { + EP = ((1. / nmode) * (TMath::ATan2(col.qvecTPCallImVec()[0], col.qvecTPCallReVec()[0]))); + } else { + LOGP(error, "no selected detector of Qvec for EP"); + return EP; + } + + if (EP < 0) { EP += TMath::Pi(); - // atan2 return in rad -pi/2-pi/2, then make it 0-pi + } // atan2 return in rad -pi/2-pi/2, then make it 0-pi return EP; } + /// Compute the event plane resolution of 3 sub-events + /// \tparam T type of the collision + /// \param col Collision + /// \param nmode EP in which harmonic(default 2nd harmonic) + template + void fillEPReso(T const& col, int nmode, float centrality) + { + const float psi_ft0c = ((1. / nmode) * (TMath::ATan2(col.qvecFT0CImVec()[0], col.qvecFT0CReVec()[0]))); + const float psi_ft0a = ((1. / nmode) * (TMath::ATan2(col.qvecFT0AImVec()[0], col.qvecFT0AReVec()[0]))); + const float psi_tpc = ((1. / nmode) * (TMath::ATan2(col.qvecTPCallImVec()[0], col.qvecTPCallReVec()[0]))); + + mHistogramQn->fill(HIST("Event/epReso_FT0CTPC"), centrality, mQnBin + 0.f, std::cos((psi_ft0c - psi_tpc) * nmode)); + mHistogramQn->fill(HIST("Event/epReso_FT0ATPC"), centrality, mQnBin + 0.f, std::cos((psi_ft0a - psi_tpc) * nmode)); + mHistogramQn->fill(HIST("Event/epReso_FT0CFT0A"), centrality, mQnBin + 0.f, std::cos((psi_ft0c - psi_ft0a) * nmode)); + mHistogramQn->fill(HIST("Event/epReso_count"), centrality, mQnBin + 0.f); + } + /// \return the 1-d qn-vector separator to 2-d std::vector> getQnBinSeparator2D(std::vector flat, const int numQnBins = 10) { @@ -413,13 +453,15 @@ class FemtoDreamCollisionSelection } /// \fill event-wise informations - void fillEPQA(float centrality, float fSpher, float qn, float psiEP) + template + void fillEPQA(T& col, float centrality, float fSpher, float qn, float psiEP, int nmode = 2) { mHistogramQn->fill(HIST("Event/centFT0CBeforeQn"), centrality); mHistogramQn->fill(HIST("Event/centVsqn"), centrality, qn); mHistogramQn->fill(HIST("Event/centVsqnVsSpher"), centrality, qn, fSpher); mHistogramQn->fill(HIST("Event/qnBin"), mQnBin + 0.f); mHistogramQn->fill(HIST("Event/psiEP"), psiEP); + fillEPReso(col, nmode, centrality); } /// \todo to be implemented! diff --git a/PWGCF/FemtoDream/Core/femtoDreamContainer.h b/PWGCF/FemtoDream/Core/femtoDreamContainer.h index a12b36fd8a2..4c3a5b24be0 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamContainer.h +++ b/PWGCF/FemtoDream/Core/femtoDreamContainer.h @@ -223,10 +223,26 @@ class FemtoDreamContainer mHistogramRegistry->add((folderName + "/relPair3dRmTMultPercentileQnPairphi").c_str(), ("; " + femtoDKout + femtoDKside + femtoDKlong + "; #it{m}_{T} (GeV/#it{c}); Centrality; qn; #varphi_{pair} - #Psi_{EP}").c_str(), kTHnSparseF, {femtoDKoutAxis, femtoDKsideAxis, femtoDKlongAxis, mTAxi4D, multPercentileAxis4D, qnAxis, pairPhiAxis}); } + template + void init_3Dqn_MC(std::string folderName, std::string femtoDKout, std::string femtoDKside, std::string femtoDKlong, + T& femtoDKoutAxis, T& femtoDKsideAxis, T& femtoDKlongAxis, bool smearingByOrigin = false) + { + mHistogramRegistry->add((folderName + "/hNoMCtruthPairsCounter").c_str(), "; Counter; Entries", kTH1I, {{1, 0, 1}}); + mHistogramRegistry->add((folderName + "/hFakePairsCounter").c_str(), "; Counter; Entries", kTH1I, {{1, 0, 1}}); + if (smearingByOrigin) { + const int nOriginBins = o2::aod::femtodreamMCparticle::ParticleOriginMCTruth::kNOriginMCTruthTypes; + mHistogramRegistry->add((folderName + "/relPair3dresolution").c_str(), (";" + femtoDKout + "mctruth;" + femtoDKout + "_reco;" + femtoDKside + "mctruth;" + femtoDKside + "_reco;" + femtoDKlong + "mctruth;" + femtoDKlong + "_reco;" + "MC origin particle 1; MC origin particle 2;").c_str(), + kTHnSparseF, {femtoDKoutAxis, femtoDKoutAxis, femtoDKsideAxis, femtoDKsideAxis, femtoDKlongAxis, femtoDKlongAxis, {nOriginBins, 0, nOriginBins}, {nOriginBins, 0, nOriginBins}}); + } else { + mHistogramRegistry->add((folderName + "/relPair3dresolution").c_str(), (";" + femtoDKout + "mctruth;" + femtoDKside + "mctruth;" + femtoDKlong + "mctruth;" + femtoDKout + "_reco;" + femtoDKside + "_reco;" + femtoDKlong + "_reco;").c_str(), + kTHnSparseF, {femtoDKoutAxis, femtoDKoutAxis, femtoDKsideAxis, femtoDKsideAxis, femtoDKlongAxis, femtoDKlongAxis}); + } + } + template void init_3Dqn(HistogramRegistry* registry, T& DKoutBins, T& DKsideBins, T& DKlongBins, T& mTBins4D, T& multPercentileBins4D, - bool isMC, ConfigurableAxis qnBins = {"qnBins", {10, 0, 10}, "qn binning"}, ConfigurableAxis pairPhiBins = {"phiBins", {10, 0 - 0.05, TMath::Pi() + 0.05}, "pair phi binning"}) + bool isMC, ConfigurableAxis qnBins = {"qnBins", {10, 0, 10}, "qn binning"}, ConfigurableAxis pairPhiBins = {"phiBins", {10, 0 - 0.05, TMath::Pi() + 0.05}, "pair phi binning"}, bool smearingByOrigin = false) { mHistogramRegistry = registry; @@ -251,6 +267,8 @@ class FemtoDreamContainer folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + static_cast("_3Dqn"); init_base_3Dqn(folderName, femtoObsDKout, femtoObsDKside, femtoObsDKlong, DKoutAxis, DKsideAxis, DKlongAxis, mTAxis4D, multPercentileAxis4D, qnAxis, pairPhiAxis); + init_3Dqn_MC(folderName, femtoObsDKout, femtoObsDKside, femtoObsDKlong, + DKoutAxis, DKsideAxis, DKlongAxis, smearingByOrigin); } } @@ -484,11 +502,26 @@ class FemtoDreamContainer mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("_3Dqn") + HIST("/relPair3dRmTMultPercentileQnPairphi"), femtoDKout, femtoDKside, femtoDKlong, mT, multPercentile, myQnBin, pairPhiEP); } + /// Called by setPair_3Dqn only in case of Monte Carlo truth + /// Fills resolution of DKout, DKside, DKlong + void setPair_3Dqn_MC(std::vector k3dMC, std::vector k3d, const int originPart1, const int originPart2, bool smearingByOrigin) + { + if (smearingByOrigin) { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("_3Dqn") + HIST("/relPair3dresolution"), k3dMC[1], k3d[1], k3dMC[2], k3d[2], k3dMC[3], k3d[3], originPart1, originPart2); + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("_3Dqn") + HIST("/relPair3dresolution"), k3dMC[1], k3d[1], k3dMC[2], k3d[2], k3dMC[3], k3d[3]); + } + } + template - void setPair_3Dqn(T1 const& part1, T2 const& part2, const float multPercentile, bool IsSameSpecies, const float myQnBin, const float eventPlane) + void setPair_3Dqn(T1 const& part1, T2 const& part2, const float multPercentile, bool IsSameSpecies, const float myQnBin, const float eventPlane, bool smearingByOrigin = false) { std::vector k3d = FemtoDreamMath::newpairfunc(part1, mMassOne, part2, mMassTwo, IsSameSpecies); + if (k3d.size() < 4) { + LOG(error) << "newpairfunc returned size=" << k3d.size(); + return; + } float DKout = k3d[1]; float DKside = k3d[2]; float DKlong = k3d[3]; @@ -503,12 +536,17 @@ class FemtoDreamContainer if constexpr (isMC) { if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { - std::vector k3dMC = FemtoDreamMath::newpairfunc(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, IsSameSpecies); + std::vector k3dMC = FemtoDreamMath::newpairfuncMC(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, IsSameSpecies); + if (k3dMC.size() < 4) { + LOG(error) << "newpairfunc returned size=" << k3d.size(); + return; + } const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); const float pairPhiEPMC = FemtoDreamMath::getPairPhiEP(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, eventPlane); if (std::abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && std::abs(part2.fdMCParticle().pdgMCTruth()) == mPDGTwo) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates setPair_3Dqn_base(k3dMC[1], k3dMC[2], k3dMC[3], mTMC, multPercentile, myQnBin, pairPhiEPMC); + setPair_3Dqn_MC(k3dMC, k3d, part1.fdMCParticle().partOriginMCTruth(), part2.fdMCParticle().partOriginMCTruth(), smearingByOrigin); } else { mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); } @@ -521,10 +559,14 @@ class FemtoDreamContainer } template - void setPair_3Dqn(T1 const& part1, T2 const& part2, const float multPercentile, bool IsSameSpecies, const float myQnBin, const float EP1, const float EP2) + void setPair_3Dqn(T1 const& part1, T2 const& part2, const float multPercentile, bool IsSameSpecies, const float myQnBin, const float EP1, const float EP2, bool smearingByOrigin = false) { std::vector k3d = FemtoDreamMath::newpairfunc(part1, mMassOne, part2, mMassTwo, IsSameSpecies); + if (k3d.size() < 4) { + LOG(error) << "newpairfunc returned size=" << k3d.size(); + return; + } float DKout = k3d[1]; float DKside = k3d[2]; float DKlong = k3d[3]; @@ -539,12 +581,17 @@ class FemtoDreamContainer if constexpr (isMC) { if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { - std::vector k3dMC = FemtoDreamMath::newpairfunc(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, IsSameSpecies); + std::vector k3dMC = FemtoDreamMath::newpairfuncMC(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, IsSameSpecies); + if (k3dMC.size() < 4) { + LOG(error) << "newpairfunc returned size=" << k3d.size(); + return; + } const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); const float pairPhiEPMC = FemtoDreamMath::getPairPhiEP(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, EP1, EP2); if (std::abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && std::abs(part2.fdMCParticle().pdgMCTruth()) == mPDGTwo) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates setPair_3Dqn_base(k3dMC[1], k3dMC[2], k3dMC[3], mTMC, multPercentile, myQnBin, pairPhiEPMC); + setPair_3Dqn_MC(k3dMC, k3d, part1.fdMCParticle().partOriginMCTruth(), part2.fdMCParticle().partOriginMCTruth(), smearingByOrigin); } else { mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); } diff --git a/PWGCF/FemtoDream/Core/femtoDreamMath.h b/PWGCF/FemtoDream/Core/femtoDreamMath.h index 867f519ba79..cbb8257f590 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamMath.h +++ b/PWGCF/FemtoDream/Core/femtoDreamMath.h @@ -249,6 +249,98 @@ class FemtoDreamMath return vect; } + /// Compute the 3d components of the pair momentum in LCMS and PRF + /// Copy from femto universe + /// \tparam T type of tracks + /// \param part1 Particle 1 + /// \param mass1 Mass of particle 1 + /// \param part2 Particle 2 + /// \param mass2 Mass of particle 2 + /// \param isiden Identical or non-identical particle pair + template + static std::vector newpairfuncMC(const T& part1, const float mass1, const T& part2, const float mass2, bool isiden) + { + const double trkPx1 = part1.pt() * std::cos(part1.phi()); + const double trkPy1 = part1.pt() * std::sin(part1.phi()); + const double trkPz1 = part1.pt() * std::sinh(part1.eta()); + + const double trkPx2 = part2.pt() * std::cos(part2.phi()); + const double trkPy2 = part2.pt() * std::sin(part2.phi()); + const double trkPz2 = part2.pt() * std::sinh(part2.eta()); + + const double e1 = std::sqrt(std::pow(trkPx1, 2) + std::pow(trkPy1, 2) + std::pow(trkPz1, 2) + std::pow(mass1, 2)); + const double e2 = std::sqrt(std::pow(trkPx2, 2) + std::pow(trkPy2, 2) + std::pow(trkPz2, 2) + std::pow(mass2, 2)); + + const ROOT::Math::PxPyPzEVector vecpart1(trkPx1, trkPy1, trkPz1, e1); + const ROOT::Math::PxPyPzEVector vecpart2(trkPx2, trkPy2, trkPz2, e2); + const ROOT::Math::PxPyPzEVector trackSum = vecpart1 + vecpart2; + + std::vector vect; + + const double tPx = trackSum.px(); + const double tPy = trackSum.py(); + const double tPz = trackSum.pz(); + const double tE = trackSum.E(); + + const double tPtSq = (tPx * tPx + tPy * tPy); + const double tMtSq = (tE * tE - tPz * tPz); + const double tM = std::sqrt(tMtSq - tPtSq); + const double tMt = std::sqrt(tMtSq); + const double tPt = std::sqrt(tPtSq); + + // Boost to LCMS + + const double beta_LCMS = tPz / tE; + const double gamma_LCMS = tE / tMt; + + const double fDKOut = (trkPx1 * tPx + trkPy1 * tPy) / tPt; + const double fDKSide = (-trkPx1 * tPy + trkPy1 * tPx) / tPt; + const double fDKLong = gamma_LCMS * (trkPz1 - beta_LCMS * e1); + const double fDE = gamma_LCMS * (e1 - beta_LCMS * trkPz1); + + const double px1LCMS = fDKOut; + const double py1LCMS = fDKSide; + const double pz1LCMS = fDKLong; + const double pE1LCMS = fDE; + + const double px2LCMS = (trkPx2 * tPx + trkPy2 * tPy) / tPt; + const double py2LCMS = (trkPy2 * tPx - trkPx2 * tPy) / tPt; + const double pz2LCMS = gamma_LCMS * (trkPz2 - beta_LCMS * e2); + const double pE2LCMS = gamma_LCMS * (e2 - beta_LCMS * trkPz2); + + const double fDKOutLCMS = px1LCMS - px2LCMS; + const double fDKSideLCMS = py1LCMS - py2LCMS; + const double fDKLongLCMS = pz1LCMS - pz2LCMS; + + // Boost to PRF + + const double betaOut = tPt / tMt; + const double gammaOut = tMt / tM; + + const double fDKOutPRF = gammaOut * (fDKOutLCMS - betaOut * (pE1LCMS - pE2LCMS)); + const double fDKSidePRF = fDKSideLCMS; + const double fDKLongPRF = fDKLongLCMS; + const double fKOut = gammaOut * (fDKOut - betaOut * fDE); + + const double qlcms = std::sqrt(fDKOutLCMS * fDKOutLCMS + fDKSideLCMS * fDKSideLCMS + fDKLongLCMS * fDKLongLCMS); + const double qinv = std::sqrt(fDKOutPRF * fDKOutPRF + fDKSidePRF * fDKSidePRF + fDKLongPRF * fDKLongPRF); + const double kstar = std::sqrt(fKOut * fKOut + fDKSide * fDKSide + fDKLong * fDKLong); + + if (isiden) { + vect.push_back(qinv); + vect.push_back(fDKOutLCMS); + vect.push_back(fDKSideLCMS); + vect.push_back(fDKLongLCMS); + vect.push_back(qlcms); + } else { + vect.push_back(kstar); + vect.push_back(fDKOut); + vect.push_back(fDKSide); + vect.push_back(fDKLong); + } + return vect; + } + /// Compute the phi angular of a pair with respect to the event plane /// \tparam T type of tracks /// \param part1 Particle 1 diff --git a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx index b8c1f48be09..15686d79e9b 100644 --- a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx @@ -61,10 +61,11 @@ namespace o2::aod using FemtoFullCollision = soa::Join::iterator; using FemtoFullCollision_noCent = soa::Join::iterator; using FemtoFullCollision_CentPbPb = soa::Join::iterator; -using FemtoFullCollision_CentPbPb_qvec = soa::Join::iterator; +using FemtoFullCollision_CentPbPb_qvec = soa::Join::iterator; using FemtoFullCollisionMC = soa::Join::iterator; using FemtoFullCollision_noCent_MC = soa::Join::iterator; using FemtoFullCollisionMC_CentPbPb = soa::Join::iterator; +using FemtoFullCollisionMC_CentPbPb_qvec = soa::Join::iterator; using FemtoFullMCgenCollisions = soa::Join; using FemtoFullMCgenCollision = FemtoFullMCgenCollisions::iterator; @@ -281,6 +282,9 @@ struct femtoDreamProducerTask { Configurable ConfCentralityMax{"ConfCentralityMax", 100.f, "Evt sel: Maximum Centrality cut"}; Configurable ConfCentBinWidth{"ConfCentBinWidth", 1.f, "Centrality bin length for qn separator"}; Configurable ConfNumQnBins{"ConfNumQnBins", 10, "Number of qn bins"}; + Configurable ConfMCQvec{"ConfMCQvec", false, "Enable Q vector table for Monte Carlo"}; + Configurable ConfQvecDetector{"ConfQvecDetector", 0, "Q-vec detector selection; 0 : FT0C; 1 : FT0A"}; + Configurable ConfEPDetector{"ConfEPDetector", 0, "Event-plane detector selection; 0 : FT0C; 1 : FT0A; 2 : TPC"}; } epCal; struct : o2::framework::ConfigurableGroup { @@ -307,10 +311,10 @@ struct femtoDreamProducerTask { void init(InitContext&) { - if (doprocessData == false && doprocessData_noCentrality == false && doprocessData_CentPbPb == false && doprocessData_CentPbPb_EP == false && doprocessMC == false && doprocessMC_noCentrality == false && doprocessMC_CentPbPb == false) { + if (doprocessData == false && doprocessData_noCentrality == false && doprocessData_CentPbPb == false && doprocessData_CentPbPb_EP == false && doprocessMC == false && doprocessMC_noCentrality == false && doprocessMC_CentPbPb == false && doprocessMC_CentPbPb_EP == false) { LOGF(fatal, "Neither processData nor processMC enabled. Please choose one."); } - if ((doprocessData == true && doprocessMC == true) || (doprocessData == true && doprocessMC_noCentrality == true) || (doprocessMC == true && doprocessMC_noCentrality == true) || (doprocessData_noCentrality == true && doprocessData == true) || (doprocessData_noCentrality == true && doprocessMC == true) || (doprocessData_noCentrality == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessData == true) || (doprocessData_CentPbPb == true && doprocessData_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC == true) || (doprocessData_CentPbPb == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC_CentPbPb == true) || (doprocessData_CentPbPb_EP == true && doprocessData == true) || (doprocessData_CentPbPb_EP == true && doprocessData_noCentrality == true) || (doprocessData_CentPbPb_EP == true && doprocessMC == true) || (doprocessData_CentPbPb_EP == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb_EP == true && doprocessMC_CentPbPb == true) || (doprocessData_CentPbPb_EP == true && doprocessData_CentPbPb == true)) { + if ((doprocessData == true && doprocessMC == true) || (doprocessData == true && doprocessMC_noCentrality == true) || (doprocessMC == true && doprocessMC_noCentrality == true) || (doprocessData_noCentrality == true && doprocessData == true) || (doprocessData_noCentrality == true && doprocessMC == true) || (doprocessData_noCentrality == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessData == true) || (doprocessData_CentPbPb == true && doprocessData_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC == true) || (doprocessData_CentPbPb == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC_CentPbPb == true) || (doprocessData_CentPbPb_EP == true && doprocessData == true) || (doprocessData_CentPbPb_EP == true && doprocessData_noCentrality == true) || (doprocessData_CentPbPb_EP == true && doprocessMC == true) || (doprocessData_CentPbPb_EP == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb_EP == true && doprocessMC_CentPbPb == true) || (doprocessData_CentPbPb_EP == true && doprocessData_CentPbPb == true) || (doprocessData_CentPbPb_EP == true && doprocessMC_CentPbPb_EP == true) || (doprocessMC_CentPbPb_EP == true && doprocessData == true) || (doprocessMC_CentPbPb_EP == true && doprocessData_noCentrality == true) || (doprocessMC_CentPbPb_EP == true && doprocessMC == true) || (doprocessMC_CentPbPb_EP == true && doprocessMC_noCentrality == true) || (doprocessMC_CentPbPb_EP == true && doprocessMC_CentPbPb == true) || (doprocessMC_CentPbPb_EP == true && doprocessData_CentPbPb == true)) { LOGF(fatal, "Cannot enable more than one process switch at the same time. " "Please choose one."); @@ -771,7 +775,7 @@ struct femtoDreamProducerTask { } if constexpr (doFlow) { - fillCollisionsFlow(col, tracks, mult, spher, epCal.ConfHarmonicOrder); + fillCollisionsFlow(col, tracks, mult, spher, epCal.ConfHarmonicOrder); } std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children @@ -1126,12 +1130,16 @@ struct femtoDreamProducerTask { } } - template + template void fillCollisionsFlow(CollisionType const& col, TrackType const& tracks, float mult, float spher, int EPHarmonic) { - float myqn = colCuts.computeqnVec(col); - float myEP = TMath::RadToDeg() * colCuts.computeEP(col, EPHarmonic); - // psi from rad(0-pi) to deg, in table psi would be in deg,from 0-180 + float myqn = 0.f; + float myEP = 0.f; + + if (!isMC || epCal.ConfMCQvec) { + myqn = colCuts.computeqnVec(col, epCal.ConfQvecDetector); + myEP = TMath::RadToDeg() * colCuts.computeEP(col, EPHarmonic, epCal.ConfEPDetector); // psi from rad(0-pi) to deg, in table psi would be in deg,from 0-180 + } if ((myqn >= 0 && myqn < 1e6) || (myEP >= 0 && myEP < 180)) { outputExtQnCollision(myqn, col.trackOccupancyInTimeRange()); @@ -1139,12 +1147,11 @@ struct femtoDreamProducerTask { } // Calculate flow via cumulant - - if (epCal.ConfQnSeparation) { + if (epCal.ConfQnSeparation && (!isMC || epCal.ConfMCQvec)) { colCuts.myqnBin(mult, epCal.ConfCentralityMax, epCal.ConfFillFlowQA, epCal.ConfQnBinSeparator, myqn, epCal.ConfNumQnBins, epCal.ConfCentBinWidth); } - if (epCal.ConfFillFlowQA) { - colCuts.fillEPQA(mult, spher, myqn, myEP); + if (epCal.ConfFillFlowQA && (!isMC || epCal.ConfMCQvec)) { + colCuts.fillEPQA(col, mult, spher, myqn, myEP, EPHarmonic); if (epCal.ConfDoCumlant) { colCuts.doCumulants(col, tracks, trackCuts, mult, epCal.ConfQnSeparation); } @@ -1277,6 +1284,21 @@ struct femtoDreamProducerTask { fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); } PROCESS_SWITCH(femtoDreamProducerTask, processMC_CentPbPb, "Provide MC data with centrality information for PbPb collisions", false); + + void processMC_CentPbPb_EP(aod::FemtoFullCollisionMC_CentPbPb_qvec const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::FemtoFullMCgenCollisions const&, + aod::McParticles const&, + soa::Join const& fullV0s, /// \todo with FilteredFullV0s + soa::Join const& fullCascades) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + PROCESS_SWITCH(femtoDreamProducerTask, processMC_CentPbPb_EP, "Provide MC data with centrality and q-vector table for PbPb collisions", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx index f2100431efd..0d97ae5b676 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx @@ -95,6 +95,7 @@ struct femtoDreamPairTaskTrackTrack { Configurable storeEvtTrkInfo{"storeEvtTrkInfo", false, "Fill info of track1 and track2 while pariing in divided qn bins"}; Configurable doQnSeparation{"doQnSeparation", false, "Do qn separation"}; Configurable doEPReClibForMixing{"doEPReClibForMixing", false, "While mixing, using respective event plane for participating particles azimuthal angle caulculation"}; + Configurable mcQvec{"mcQvec", false, "Enable Q vector table for Monte Carlo"}; Configurable> qnBinSeparator{"qnBinSeparator", std::vector{-999.f, -999.f, -999.f}, "Qn bin separator"}; Configurable numQnBins{"numQnBins", 10, "Number of qn bins"}; Configurable qnBinMin{"qnBinMin", 0, "Number of qn bins"}; @@ -113,6 +114,8 @@ struct femtoDreamPairTaskTrackTrack { using FilteredMCCollision = FilteredMCCollisions::iterator; using FilteredQnCollisions = soa::Filtered>; using FilteredQnCollision = FilteredQnCollisions::iterator; + using FilteredMCQnCollisions = soa::Filtered>; + using FilteredMCQnCollision = FilteredMCQnCollisions::iterator; using FilteredMaskedCollisions = soa::Filtered>; using FilteredMaskedCollision = FilteredMaskedCollisions::iterator; @@ -322,9 +325,9 @@ struct femtoDreamPairTaskTrackTrack { if (EPCal.do3DFemto) { sameEventQnCont.init_3Dqn(&Registry, EPCal.DKout, EPCal.DKside, EPCal.DKlong, - Binning4D.mT, Binning4D.multPercentile, Option.IsMC, EPCal.qnBins, EPCal.pairPhiBins); + Binning4D.mT, Binning4D.multPercentile, Option.IsMC, EPCal.qnBins, EPCal.pairPhiBins, Option.SmearingByOrigin); mixedEventQnCont.init_3Dqn(&Registry, EPCal.DKout, EPCal.DKside, EPCal.DKlong, - Binning4D.mT, Binning4D.multPercentile, Option.IsMC, EPCal.qnBins, EPCal.pairPhiBins); + Binning4D.mT, Binning4D.multPercentile, Option.IsMC, EPCal.qnBins, EPCal.pairPhiBins, Option.SmearingByOrigin); sameEventQnCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); mixedEventQnCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); if (EPCal.fillFlowQA) { @@ -377,7 +380,10 @@ struct femtoDreamPairTaskTrackTrack { (doprocessMixedEvent && doprocessMixedEventEP) || (doprocessMixedEventMasked && doprocessMixedEventEP) || (doprocessSameEventMC && doprocessSameEventMCMasked) || - (doprocessMixedEventMC && doprocessMixedEventMCMasked)) { + (doprocessSameEventMC && doprocessSameEventEPMC) || + (doprocessMixedEventMC && doprocessMixedEventMCMasked) || + (doprocessMixedEventMC && doprocessMixedEventEPMC) || + (doprocessMixedEventMCMasked && doprocessMixedEventEPMC)) { LOG(fatal) << "Normal and masked processing cannot be activated simultaneously!"; } }; @@ -704,17 +710,20 @@ struct femtoDreamPairTaskTrackTrack { } } - auto myEP = TMath::DegToRad() * col.eventPlane(); + float myEP = -999.f; int myqnBin = -999; - if (EPCal.doQnSeparation || EPCal.do3DFemto) { - myqnBin = epCalculator.myqnBin(col.multV0M(), EPCal.centMax, EPCal.fillFlowQA, EPCal.qnBinSeparator, col.qnVal(), EPCal.numQnBins, EPCal.centBinWidth); - if (myqnBin < EPCal.qnBinMin || myqnBin > EPCal.numQnBins) { - myqnBin = -999; - } - } - if (EPCal.fillFlowQA) { - epCalculator.fillEPQA(col.multV0M(), col.sphericity(), col.qnVal(), col.eventPlane()); + if (!isMC || EPCal.mcQvec) { + myEP = TMath::DegToRad() * col.eventPlane(); + if (EPCal.doQnSeparation || EPCal.do3DFemto) { + myqnBin = epCalculator.myqnBin(col.multV0M(), EPCal.centMax, EPCal.fillFlowQA, EPCal.qnBinSeparator, col.qnVal(), EPCal.numQnBins, EPCal.centBinWidth); + if (myqnBin < EPCal.qnBinMin || myqnBin > EPCal.numQnBins) { + myqnBin = -999; + } + } + } else { + myEP = 0.f; + myqnBin = 0; } /// Now build the combinations @@ -738,14 +747,14 @@ struct femtoDreamPairTaskTrackTrack { sameEventQnCont.setPair_EP(p1, p2, col.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? myqnBin + 0.f : myEP); } if (EPCal.do3DFemto) { - sameEventQnCont.setPair_3Dqn(p1, p2, col.multV0M(), Option.SameSpecies.value, myqnBin + 0.f, myEP); + sameEventQnCont.setPair_3Dqn(p1, p2, col.multV0M(), Option.SameSpecies.value, myqnBin + 0.f, myEP, Option.SmearingByOrigin); } } else { if (EPCal.do1DFemto) { sameEventQnCont.setPair_EP(p2, p1, col.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? myqnBin + 0.f : myEP); } if (EPCal.do3DFemto) { - sameEventQnCont.setPair_3Dqn(p2, p1, col.multV0M(), Option.SameSpecies.value, myqnBin + 0.f, myEP); + sameEventQnCont.setPair_3Dqn(p2, p1, col.multV0M(), Option.SameSpecies.value, myqnBin + 0.f, myEP, Option.SmearingByOrigin); } } } @@ -764,7 +773,7 @@ struct femtoDreamPairTaskTrackTrack { sameEventQnCont.setPair_EP(p1, p2, col.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? myqnBin + 0.f : myEP); } if (EPCal.do3DFemto) { - sameEventQnCont.setPair_3Dqn(p1, p2, col.multV0M(), Option.SameSpecies.value, myEP, myqnBin); + sameEventQnCont.setPair_3Dqn(p1, p2, col.multV0M(), Option.SameSpecies.value, myEP, myqnBin, Option.SmearingByOrigin); } } } @@ -789,6 +798,28 @@ struct femtoDreamPairTaskTrackTrack { } PROCESS_SWITCH(femtoDreamPairTaskTrackTrack, processSameEventEP, "Enable processing same event wrt azimuthal angle and event-plane ", false); + /// process function for to call doSameEventEP with MC Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processSameEventEPMC(FilteredMCQnCollision& col, + o2::aod::FDMCCollisions&, + soa::Join& parts, + o2::aod::FDMCParticles&) + { + if (EPCal.storeEvtTrkInfo) { + fillCollision(col); + } + auto SliceTrk1 = PartitionMCTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto SliceTrk2 = PartitionMCTrk2->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + if (SliceTrk1.size() == 0 && SliceTrk2.size() == 0) { + return; + } + if (EPCal.do1DFemto || EPCal.do3DFemto) { + doSameEventEP(SliceTrk1, SliceTrk2, parts, col); + } + } + PROCESS_SWITCH(femtoDreamPairTaskTrackTrack, processSameEventEPMC, "Enable processing same event of 3D for Monte Carlo", false); + template void doMixedEvent_NotMaskedEP(CollisionType& cols, PartType& parts, PartitionType& part1, PartitionType& part2, BinningType policy) { @@ -799,8 +830,16 @@ struct femtoDreamPairTaskTrackTrack { continue; } - auto myEP_event1 = TMath::DegToRad() * collision1.eventPlane(); - auto myEP_event2 = TMath::DegToRad() * collision2.eventPlane(); + auto myEP_event1 = -999.f; + auto myEP_event2 = -999.f; + + if (!isMC || EPCal.mcQvec) { + myEP_event1 = TMath::DegToRad() * collision1.eventPlane(); + myEP_event2 = TMath::DegToRad() * collision2.eventPlane(); + } else { + myEP_event1 = 0.f; + myEP_event2 = 0.f; + } for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceTrk2))) { if (Option.CPROn.value) { @@ -816,13 +855,13 @@ struct femtoDreamPairTaskTrackTrack { mixedEventQnCont.setPair_EP(p1, p2, collision1.multV0M(), EPCal.doQnSeparation, myEP_event1, myEP_event2); } if (EPCal.do3DFemto) { - mixedEventQnCont.setPair_3Dqn(p1, p2, collision1.multV0M(), Option.SameSpecies.value, 0.f, myEP_event1, myEP_event2); + mixedEventQnCont.setPair_3Dqn(p1, p2, collision1.multV0M(), Option.SameSpecies.value, 0.f, myEP_event1, myEP_event2, Option.SmearingByOrigin); } } else { if (EPCal.do1DFemto) mixedEventQnCont.setPair_EP(p1, p2, collision1.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? 0.f : myEP_event1); if (EPCal.do3DFemto) { - mixedEventQnCont.setPair_3Dqn(p1, p2, collision1.multV0M(), Option.SameSpecies.value, 0.f, myEP_event1); + mixedEventQnCont.setPair_3Dqn(p1, p2, collision1.multV0M(), Option.SameSpecies.value, 0.f, myEP_event1, Option.SmearingByOrigin); } } } @@ -855,6 +894,33 @@ struct femtoDreamPairTaskTrackTrack { } } PROCESS_SWITCH(femtoDreamPairTaskTrackTrack, processMixedEventEP, "Enable processing mixed events wrt azimuthal angle and event-plane", false); + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoDreamParticleTable + void processMixedEventEPMC(FilteredMCQnCollisions& cols, o2::aod::FDMCCollisions&, soa::Join& parts, o2::aod::FDMCParticles&) + { + switch (Mixing.Policy.value) { + case femtodreamcollision::kMult: + doMixedEvent_NotMaskedEP(cols, parts, PartitionMCTrk1, PartitionMCTrk2, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent_NotMaskedEP(cols, parts, PartitionMCTrk1, PartitionMCTrk2, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent_NotMaskedEP(cols, parts, PartitionMCTrk1, PartitionMCTrk2, colBinningMultMultPercentile); + break; + case femtodreamcollision::kMultPercentileQn: + doMixedEvent_NotMaskedEP(cols, parts, PartitionMCTrk1, PartitionMCTrk2, colBinningMultPercentileqn); + break; + case femtodreamcollision::kMultPercentileEP: + doMixedEvent_NotMaskedEP(cols, parts, PartitionMCTrk1, PartitionMCTrk2, colBinningMultPercentileEP); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(femtoDreamPairTaskTrackTrack, processMixedEventEPMC, "Enable processing mixed events wrt azimuthal angle and event-plane for Monte Carlo", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h index c939a4f269d..3a7738b2cc1 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h @@ -66,31 +66,31 @@ class FemtoUniverseDetaDphiStar if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { std::string dirName = static_cast(DirNames[0]); - histdetadpisame[0][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[0][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[0][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[0][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[0][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpisame[0][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[0][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[0][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); - histdetadpiqlcmssame = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][7])).c_str(), "; #it{q}_{LCMS}; #Delta #eta; #Delta #phi", kTH3F, {{100, 0.0, 0.5}, {100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpiqlcmsmixed = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][7])).c_str(), "; #it{q}_{LCMS}; #Delta #eta; #Delta #phi", kTH3F, {{100, 0.0, 0.5}, {100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiqlcmssame = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][7])).c_str(), "; #it{q}_{LCMS}; #Delta #eta; #Delta #phi", kTH3F, {{100, 0.0, 0.5}, {200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpiqlcmsmixed = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][7])).c_str(), "; #it{q}_{LCMS}; #Delta #eta; #Delta #phi", kTH3F, {{100, 0.0, 0.5}, {200, -0.3, 0.3}, {200, -0.3, 0.3}}); if (plotForEveryRadii) { for (int i = 0; i < 9; i++) { - histdetadpiRadii[0][i] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[0][i] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { for (int i = 0; i < 2; i++) { std::string dirName = static_cast(DirNames[1]); - histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); if (plotForEveryRadii) { for (int j = 0; j < 9; j++) { - histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } @@ -99,13 +99,13 @@ class FemtoUniverseDetaDphiStar /// V0-V0 combination for (int k = 0; k < 2; k++) { std::string dirName = static_cast(DirNames[2]); - histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); if (plotForEveryRadii) { for (int l = 0; l < 9; l++) { - histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } @@ -114,13 +114,13 @@ class FemtoUniverseDetaDphiStar /// Cascade-Cascade combination for (int k = 0; k < 7; k++) { std::string dirName = static_cast(DirNames[5]); - histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); if (plotForEveryRadii) { for (int l = 0; l < 9; l++) { - histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } @@ -129,13 +129,13 @@ class FemtoUniverseDetaDphiStar /// Track-Cascade combination for (int k = 0; k < 3; k++) { std::string dirName = static_cast(DirNames[6]); - histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); if (plotForEveryRadii) { for (int l = 0; l < 9; l++) { - histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } @@ -144,13 +144,13 @@ class FemtoUniverseDetaDphiStar /// V0-Cascade combination for (int k = 0; k < 3; k++) { std::string dirName = static_cast(DirNames[7]); - histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); if (plotForEveryRadii) { for (int l = 0; l < 9; l++) { - histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } @@ -165,7 +165,7 @@ class FemtoUniverseDetaDphiStar if (plotForEveryRadii) { for (int j = 0; j < 9; j++) { - histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #varphi*", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #varphi*", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } @@ -173,14 +173,14 @@ class FemtoUniverseDetaDphiStar if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { for (int i = 0; i < 2; i++) { std::string dirName = static_cast(DirNames[4]); - histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); + histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); if (plotForEveryRadii) { for (int j = 0; j < 9; j++) { - histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{200, -0.3, 0.3}, {200, -0.3, 0.3}}); } } } @@ -207,7 +207,7 @@ class FemtoUniverseDetaDphiStar histdetadphisamebeforekT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiBeforeSame").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); histdetadphimixedbeforekT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiBeforeMixed").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); histdetadphisameafterkT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiAfterSame").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadphimixedafterkT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiAfterMixed").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadphimixedafterkT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiAfterMixed").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {200, -0.3, 0.3}}); } } } diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx index 97d4e4f7437..af0370625ca 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx @@ -136,6 +136,7 @@ struct FemtoUniverseProducerTask { Configurable confFillCollExt{"confFillCollExt", false, "Option to fill collision extended table"}; Configurable confCollMCTruthOnlyReco{"confCollMCTruthOnlyReco", false, "Fill only MC truth collisions that were reconstructed and selected"}; + Configurable confFillMCTruthV0Daugh{"confFillMCTruthV0Daugh", true, "Fill MC truth daughters of V0"}; /// Event filtering (used for v0-cascade analysis) Configurable zorroMask{"zorroMask", "", "zorro trigger class to select on (empty: none)"}; @@ -880,12 +881,14 @@ struct FemtoUniverseProducerTask { template int32_t getMotherPDG(ParticleType particle) { - auto motherparticlesMC = particle.template mothers_as(); - if (!motherparticlesMC.empty()) { + if (particle.isPhysicalPrimary()) { + return 0; + } else if (particle.has_mothers()) { + auto motherparticlesMC = particle.template mothers_as(); auto motherparticleMC = motherparticlesMC.front(); - return particle.isPhysicalPrimary() ? 0 : motherparticleMC.pdgCode(); + return motherparticleMC.pdgCode(); } else { - return 9999; + return 999; } } @@ -925,7 +928,7 @@ struct FemtoUniverseProducerTask { outputPartsMCLabels(outputPartsMC.lastIndex()); } else { outputPartsMCLabels(-1); - outputDebugPartsMC(9999); + outputDebugPartsMC(-999); } } @@ -2168,7 +2171,7 @@ struct FemtoUniverseProducerTask { // aligned, so that they can be joined in the task. if constexpr (transientLabels) { outputPartsMCLabels(-1); - outputDebugPartsMC(9999); + outputDebugPartsMC(-999); } } if constexpr (resolveDaughs) { @@ -2213,7 +2216,7 @@ struct FemtoUniverseProducerTask { // aligned, so that they can be joined in the task. if constexpr (transientLabels) { outputPartsMCLabels(-1); - outputDebugPartsMC(9999); + outputDebugPartsMC(-999); } } } @@ -2913,7 +2916,11 @@ struct FemtoUniverseProducerTask { const auto colcheck = fillMCTruthCollisionsCentRun3(col); if (colcheck) { outputCollExtra(1.0, 1.0); - fillV0MCTruth(groupedMCParticles); // fills MC V0s and its daughters + if (confFillMCTruthV0Daugh) { + fillV0MCTruth(groupedMCParticles); // fills MC V0s and its daughters + } else { + fillParticles(groupedMCParticles, recoMcIds); // fills mc particles + } } } } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx index 4002a0a1cac..6417529d529 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx @@ -198,9 +198,9 @@ struct femtoUniversePairTaskTrackCascadeExtended { } } - bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle) + bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle, bool hasTOF) { - if (mom <= confmom) { + if (mom <= confmom || hasTOF == 0) { return (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticle); } else { return (TMath::Hypot(nsigmaTOFParticle, nsigmaTPCParticle) < confNsigmaCombinedParticle); @@ -231,7 +231,7 @@ struct femtoUniversePairTaskTrackCascadeExtended { const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id]); + return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id], (part.pidCut() & 512u) != 0); } void init(InitContext const&) @@ -462,13 +462,13 @@ struct femtoUniversePairTaskTrackCascadeExtended { rXiQA.fill(HIST("hInvMpTmult"), part.pt(), part.mLambda(), multCol); } - if constexpr (std::experimental::is_detected::value) { - for (const auto& part : groupPartsOne) { + for (const auto& part : groupPartsOne) { + if constexpr (std::experimental::is_detected::value) { /// PID plot for track particle const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - if (!isNSigmaCombined(part.p(), tpcNSigmas[confTrackChoicePartOne], tofNSigmas[confTrackChoicePartOne])) + if (!isNSigmaCombined(part.p(), tpcNSigmas[confTrackChoicePartOne], tofNSigmas[confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) continue; if (part.mAntiLambda() > 0) { @@ -480,8 +480,21 @@ struct femtoUniversePairTaskTrackCascadeExtended { qaRegistry.fill(HIST("Tracks_neg/nSigmaTOF"), part.p(), tofNSigmas[confTrackChoicePartOne]); trackHistoPartOneNeg.fillQA(part); } + } else { + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & (64u << confTrackChoicePartOne)) == 0) + continue; + } else if ((part.pidCut() & (1u << confTrackChoicePartOne)) == 0) { + continue; + } + if (part.mAntiLambda() > 0) { + trackHistoPartOnePos.fillQA(part); + } else if (part.mAntiLambda() < 0) { + trackHistoPartOneNeg.fillQA(part); + } } } + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Cascade inv mass cut (mLambda stores Xi mass, mAntiLambda stores Omega mass) if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType1)) @@ -491,8 +504,12 @@ struct femtoUniversePairTaskTrackCascadeExtended { if (!isParticleCombined(p1, confTrackChoicePartOne)) continue; } else { - if ((p1.pidCut() & (64u << confTrackChoicePartOne)) == 0) + if ((p1.pidCut() & 512u) != 0) { + if ((p1.pidCut() & (64u << confTrackChoicePartOne)) == 0) + continue; + } else if ((p1.pidCut() & (1u << confTrackChoicePartOne)) == 0) { continue; + } } // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { @@ -734,8 +751,12 @@ struct femtoUniversePairTaskTrackCascadeExtended { if (!isParticleCombined(p1, confTrackChoicePartOne)) continue; } else { - if ((p1.pidCut() & (64u << confTrackChoicePartOne)) == 0) + if ((p1.pidCut() & 512u) != 0) { + if ((p1.pidCut() & (64u << confTrackChoicePartOne)) == 0) + continue; + } else if ((p1.pidCut() & (1u << confTrackChoicePartOne)) == 0) { continue; + } } const auto& posChild = parts.iteratorAt(p2.globalIndex() - 3 - parts.begin().globalIndex()); @@ -1144,11 +1165,15 @@ struct femtoUniversePairTaskTrackCascadeExtended { if (mcpart.pdgMCTruth() != kProton) continue; if constexpr (std::experimental::is_detected::value) { - if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) continue; } else { - if ((part.pidCut() & 64u) == 0) + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & 64u) == 0) + continue; + } else if ((part.pidCut() & 1u) == 0) { continue; + } } registryMCreco.fill(HIST("plus/MCrecoPr"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("plus/MCrecoPrPt"), mcpart.pt()); @@ -1157,11 +1182,15 @@ struct femtoUniversePairTaskTrackCascadeExtended { if (mcpart.pdgMCTruth() != kProtonBar) continue; if constexpr (std::experimental::is_detected::value) { - if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) continue; } else { - if ((part.pidCut() & 64u) == 0) + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & 64u) == 0) + continue; + } else if ((part.pidCut() & 1u) == 0) { continue; + } } registryMCreco.fill(HIST("minus/MCrecoPr"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("minus/MCrecoPrPt"), mcpart.pt()); diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx index 76a3c989494..2fc0a3543b9 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx @@ -34,6 +34,8 @@ #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/PID.h" +#include "TRandom2.h" + #include #include @@ -173,7 +175,8 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Chosen CPR radii"}; + Configurable confRandomizeCPR{"confRandomizeCPR", false, "Fill Dete-Dphi histograms in random order: p1, p2 or p2, p1"}; Configurable isPairIdentical{"isPairIdentical", true, "'true' for identical particles, 'false' for non-identical particles"}; struct : o2::framework::ConfigurableGroup { @@ -230,6 +233,8 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { HistogramRegistry sphericityRegistry{"SphericityHisto", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + TRandom2* randgen; + /// TPC Pion/Kaon/Proton Sigma selection (general) bool isNSigma(float mom, float nsigmaTPC, float nsigmaTOF) { @@ -473,7 +478,21 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { } if (confIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + double rand; + auto part1 = p1; + auto part2 = p2; + + if (confRandomizeCPR) { + randgen = new TRandom2(0); + rand = randgen->Rndm(); + + if (rand > 0.5) { + part1 = p2; + part2 = p1; + } + delete randgen; + } + if (pairCloseRejection.isClosePair(part1, part2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -503,7 +522,21 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { } if (confIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + double rand; + auto part1 = p1; + auto part2 = p2; + + if (confRandomizeCPR) { + randgen = new TRandom2(0); + rand = randgen->Rndm(); + + if (rand > 0.5) { + part1 = p2; + part2 = p1; + } + delete randgen; + } + if (pairCloseRejection.isClosePair(part1, part2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -638,7 +671,21 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { } if (confIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { + double rand; + auto part1 = p1; + auto part2 = p2; + + if (confRandomizeCPR) { + randgen = new TRandom2(0); + rand = randgen->Rndm(); + + if (rand > 0.5) { + part1 = p2; + part2 = p1; + } + delete randgen; + } + if (pairCloseRejection.isClosePair(part1, part2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } @@ -799,7 +846,21 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { } if (confIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { + double rand; + auto part1 = p1; + auto part2 = p2; + + if (confRandomizeCPR) { + randgen = new TRandom2(0); + rand = randgen->Rndm(); + + if (rand > 0.5) { + part1 = p2; + part2 = p1; + } + delete randgen; + } + if (pairCloseRejection.isClosePair(part1, part2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { return; } } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx index c046f9f0ff9..f5a4409a2e7 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx @@ -191,7 +191,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { ConfigurableAxis confTempFitVarpTBins{"confTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; /// Correlation part - ConfigurableAxis confMultBinsCent{"confMultBinsCent", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - centrality"}; // \todo to be obtained from the hash task + ConfigurableAxis confMultBinsCent{"confMultBinsCent", {VARIABLE_WIDTH, 0.0f, 2.5f, 5.0f, 7.5f, 10.0f, 12.5f, 15.0f, 17.5f, 20.0f, 22.5f, 25.0f, 27.5f, 30.0f, 32.5f, 35.0f, 37.5f, 40.0f, 42.5f, 45.0f, 47.5f, 50.0f, 52.5f, 55.0f, 57.5f, 60.0f, 62.5f, 65.0f, 67.5f, 70.5f, 75.0f, 80.0f, 90.0f, 100.0f, 99999.f}, "Mixing bins - centrality"}; ConfigurableAxis confMultBinsMult{"confMultBinsMult", {VARIABLE_WIDTH, 0.0f, 400.0f, 800.0f, 1200.0f, 1600.0f, 2000.0f, 2500.0f, 3000.0f, 3500.0f, 4000.0f, 4500.0f, 5000.0f, 6000.0f, 7000.0f, 8000.0f, 9000.0f, 10000.0f, 11000.0f, 12000.0f, 13000.0f, 14000.0f, 15000.0f, 16000.0f, 17000.0f, 18000.0f, 99999.f}, "Mixing bins - centrality"}; ConfigurableAxis confMultKstarBins{"confMultKstarBins", {VARIABLE_WIDTH, 0.0f, 200.0f}, "Bins for kstar analysis in multiplicity or centrality bins (10 is maximum)"}; ConfigurableAxis confKtKstarBins{"confKtKstarBins", {VARIABLE_WIDTH, 0.1f, 0.2f, 0.3f, 0.4f}, "Bins for kstar analysis in kT bins"}; diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx index bcc85d0acc2..b49b9b98119 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx @@ -29,6 +29,7 @@ #include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" +#include "TRandom2.h" #include #include #include @@ -58,6 +59,8 @@ struct FemtoUniversePairTaskTrackV0Extended { using FemtoRecoParticles = soa::Join; Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; + using FemtoBasicParticles = soa::Join; + /// To apply narrow cut Configurable confZVertexCut{"confZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; Configurable confEta{"confEta", 0.8, "Eta cut for the global track"}; @@ -161,6 +164,7 @@ struct FemtoUniversePairTaskTrackV0Extended { Configurable confEtaBins{"confEtaBins", 29, "Number of eta bins in deta dphi"}; ConfigurableAxis confmTBins3D{"confmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; ConfigurableAxis confMultBins3D{"confMultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confMotherPDGBins{"confMotherPDGBins", {8001, -4000, 4000}, "Binning for the mothers' PDG code in pair fractions histogram"}; struct : o2::framework::ConfigurableGroup { Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; @@ -171,6 +175,7 @@ struct FemtoUniversePairTaskTrackV0Extended { Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confRandomizeCPR{"confRandomizeCPR", false, "Fill Dete-Dphi histograms in random order: v01, v02 or v02, v01 - does not apply to track-V0"}; } ConfCPR; // Efficiency @@ -201,9 +206,11 @@ struct FemtoUniversePairTaskTrackV0Extended { std::unique_ptr pEffHistp2; Service ccdb; - bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle) + TRandom2* randgen; + + bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle, bool hasTOF) { - if (mom <= confmom) { + if (mom <= confmom || hasTOF == 0) { return (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticle); } else { return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < confNsigmaCombinedParticle); @@ -234,7 +241,7 @@ struct FemtoUniversePairTaskTrackV0Extended { } } - bool isNSigmaTOF(float mom, float nsigmaTOFParticle, float hasTOF) + bool isNSigmaTOF(float mom, float nsigmaTOFParticle, bool hasTOF) { // Cut only on daughter tracks, that have TOF signal if (mom > confmom && hasTOF == 1) { @@ -254,7 +261,7 @@ struct FemtoUniversePairTaskTrackV0Extended { const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id]); + return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id], (part.pidCut() & 512u) != 0); } template @@ -328,7 +335,7 @@ struct FemtoUniversePairTaskTrackV0Extended { registryMCtruth.add("minus/MCtruthPrPt", "MC truth protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); if (doprocessPairFractionsMCTruthV0 || doprocessPairFractionsMCTruth) { - registryMCtruth.add("mothersTruth/motherParticle", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {{8001, -4000, 4000}, {8001, -4000, 4000}}}); + registryMCtruth.add("mothersTruth/motherParticle", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {confMotherPDGBins, confMotherPDGBins}}); } // MC reco @@ -354,8 +361,8 @@ struct FemtoUniversePairTaskTrackV0Extended { registryMCreco.add("minus/MCrecoPrPt", "MC reco protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); if (doprocessPairFractions || doprocessPairFractionsV0) { - registryMCreco.add("mothersReco/motherParticle", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {{8001, -4000, 4000}, {8001, -4000, 4000}}}); - registryMCreco.add("mothersReco/motherParticlePDGCheck", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {{8001, -4000, 4000}, {8001, -4000, 4000}}}); + registryMCreco.add("mothersReco/motherParticle", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {confMotherPDGBins, confMotherPDGBins}}); + registryMCreco.add("mothersReco/motherParticlePDGCheck", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {confMotherPDGBins, confMotherPDGBins}}); } sameEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); sameEventCont.setPDGCodes(ConfTrkSelection.confTrkPDGCodePartOne, ConfV0Selection.confV0PDGCodePartTwo); @@ -468,7 +475,7 @@ struct FemtoUniversePairTaskTrackV0Extended { const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne])) + if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) continue; if (part.sign() > 0) { qaRegistry.fill(HIST("Tracks_pos/nSigmaTPC"), part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne]); @@ -480,8 +487,12 @@ struct FemtoUniversePairTaskTrackV0Extended { trackHistoPartOneNeg.fillQA(part); } } else { - if ((part.pidCut() & (64u << ConfTrkSelection.confTrackChoicePartOne)) == 0) + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & (64u << ConfTrkSelection.confTrackChoicePartOne)) == 0) + continue; + } else if ((part.pidCut() & (1u << ConfTrkSelection.confTrackChoicePartOne)) == 0) { continue; + } if (ConfTrkSelection.confChargePart1 > 0) trackHistoPartOnePos.fillQA(part); if (ConfTrkSelection.confChargePart1 < 0) @@ -499,8 +510,12 @@ struct FemtoUniversePairTaskTrackV0Extended { if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) continue; } else { - if ((p1.pidCut() & (64u << ConfTrkSelection.confTrackChoicePartOne)) == 0) + if ((p1.pidCut() & 512u) != 0) { + if ((p1.pidCut() & (64u << ConfTrkSelection.confTrackChoicePartOne)) == 0) + continue; + } else if ((p1.pidCut() & (1u << ConfTrkSelection.confTrackChoicePartOne)) == 0) { continue; + } } // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { @@ -730,9 +745,23 @@ struct FemtoUniversePairTaskTrackV0Extended { } if (ConfCPR.confIsCPR.value) { - if (ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + double rand; + auto part1 = p1; + auto part2 = p2; + + if (ConfCPR.confRandomizeCPR) { + randgen = new TRandom2(0); + rand = randgen->Rndm(); + + if (rand > 0.5) { + part1 = p2; + part2 = p1; + } + delete randgen; + } + if (ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(part1, part2, parts, magFieldTesla, femto_universe_container::EventType::same)) { return false; - } else if (!ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + } else if (!ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(part1, part2, parts, magFieldTesla, femto_universe_container::EventType::same)) { return false; } } @@ -956,8 +985,12 @@ struct FemtoUniversePairTaskTrackV0Extended { if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) continue; } else { - if ((p1.pidCut() & (64u << ConfTrkSelection.confTrackChoicePartOne)) == 0) + if ((p1.pidCut() & 512u) != 0) { + if ((p1.pidCut() & (64u << ConfTrkSelection.confTrackChoicePartOne)) == 0) + continue; + } else if ((p1.pidCut() & (1u << ConfTrkSelection.confTrackChoicePartOne)) == 0) { continue; + } } const auto& posChild = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); @@ -1104,9 +1137,23 @@ struct FemtoUniversePairTaskTrackV0Extended { continue; } if (ConfCPR.confIsCPR.value) { - if (ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + double rand; + auto part1 = p1; + auto part2 = p2; + + if (ConfCPR.confRandomizeCPR) { + randgen = new TRandom2(0); + rand = randgen->Rndm(); + + if (rand > 0.5) { + part1 = p2; + part2 = p1; + } + delete randgen; + } + if (ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(part1, part2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { continue; - } else if (!ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + } else if (!ConfCPR.confRectV0V0CPR && pairCloseRejectionV0.isClosePair(part1, part2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { continue; } } @@ -1432,7 +1479,21 @@ struct FemtoUniversePairTaskTrackV0Extended { continue; } if (ConfCPR.confIsCPR.value) { - if (pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + double rand; + auto part1 = p1; + auto part2 = p2; + + if (ConfCPR.confRandomizeCPR) { + randgen = new TRandom2(0); + rand = randgen->Rndm(); + + if (rand > 0.5) { + part1 = p2; + part2 = p1; + } + delete randgen; + } + if (pairCloseRejectionV0.isClosePair(part1, part2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { continue; } } @@ -1450,6 +1511,7 @@ struct FemtoUniversePairTaskTrackV0Extended { continue; if ((ConfV0Selection.confV0Type2 == 0 && mcParticle2.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && mcParticle2.pdgMCTruth() != kLambda0Bar)) continue; + registryMCreco.fill(HIST("mothersReco/motherParticlePDGCheck"), p1.motherPDG(), p2.motherPDG()); } }; @@ -1533,7 +1595,8 @@ struct FemtoUniversePairTaskTrackV0Extended { } PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processPairFractionsMCTruthV0, "Process MC data to obtain pair fractions for V0V0 MC truth pairs", false); - void processMCReco(FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + template + void doMCReco(PartType const& parts, aod::FdMCParticles const& mcparts) { for (const auto& part : parts) { auto mcPartId = part.fdMCParticleId(); @@ -1543,54 +1606,119 @@ struct FemtoUniversePairTaskTrackV0Extended { // if (part.partType() == aod::femtouniverseparticle::ParticleType::kV0) { if (mcpart.pdgMCTruth() == kLambda0) { - const auto& posChild = parts.iteratorAt(part.globalIndex() - 2); - const auto& negChild = parts.iteratorAt(part.globalIndex() - 1); - /// Daughters that do not pass this condition are not selected - if (isParticleTPC(posChild, 0) && isParticleTPC(negChild, 1)) { - registryMCreco.fill(HIST("plus/MCrecoLambda"), mcpart.pt(), mcpart.eta()); // lambda - if (auto mcpartIdChild = posChild.fdMCParticleId(); mcpartIdChild != -1) { - const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); - registryMCreco.fill(HIST("plus/MCrecoLambdaChildPr"), mcpartChild.pt(), mcpartChild.eta()); // lambda proton child - } - if (auto mcpartIdChild = negChild.fdMCParticleId(); mcpartIdChild != -1) { - const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); - registryMCreco.fill(HIST("plus/MCrecoLambdaChildPi"), mcpartChild.pt(), mcpartChild.eta()); // lambda pion child + if (!invMLambda(part.mLambda(), part.mAntiLambda(), 0)) + continue; + const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + if constexpr (std::experimental::is_detected::value) { + /// Daughters that do not pass this condition are not selected + if (!isParticleTPC(posChild, 0) || !isParticleTPC(negChild, 1)) + continue; + + if (!isParticleTOF(posChild, 0) || !isParticleTOF(negChild, 1)) + continue; + + } else { + if ((posChild.pidCut() & (1u << 0)) == 0 || (negChild.pidCut() & (1u << 1)) == 0) + continue; + + if (ConfV0Selection.confUseStrangenessTOF) { + if ((part.pidCut() & 3) != 3) + continue; + } else { + if ((posChild.pidCut() & (8u << 0)) == 0 || (negChild.pidCut() & (8u << 1)) == 0) + continue; } } + registryMCreco.fill(HIST("plus/MCrecoLambda"), mcpart.pt(), mcpart.eta()); // lambda + } else if (mcpart.pdgMCTruth() == kLambda0Bar) { - const auto& posChild = parts.iteratorAt(part.globalIndex() - 2); - const auto& negChild = parts.iteratorAt(part.globalIndex() - 1); - /// Daughters that do not pass this condition are not selected - if (isParticleTPC(posChild, 1) && isParticleTPC(negChild, 0)) { - registryMCreco.fill(HIST("minus/MCrecoLambda"), mcpart.pt(), mcpart.eta()); // anti-lambda - if (auto mcpartIdChild = posChild.fdMCParticleId(); mcpartIdChild != -1) { - const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); - registryMCreco.fill(HIST("minus/MCrecoLambdaChildPi"), mcpartChild.pt(), mcpartChild.eta()); // anti-lambda pion child - } - if (auto mcpartIdChild = negChild.fdMCParticleId(); mcpartIdChild != -1) { - const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); - registryMCreco.fill(HIST("minus/MCrecoLambdaChildPr"), mcpartChild.pt(), mcpartChild.eta()); // anti-lambda proton child + if (!invMLambda(part.mLambda(), part.mAntiLambda(), 1)) + continue; + const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + if constexpr (std::experimental::is_detected::value) { + /// Daughters that do not pass this condition are not selected + if (!isParticleTPC(posChild, 1) || !isParticleTPC(negChild, 0)) + continue; + + if (!isParticleTOF(posChild, 1) || !isParticleTOF(negChild, 0)) + continue; + + } else { + if ((posChild.pidCut() & (1u << 1)) == 0 || (negChild.pidCut() & (1u << 0)) == 0) + continue; + + if (ConfV0Selection.confUseStrangenessTOF) { + if ((part.pidCut() & 12) != 12) + continue; + } else { + if ((posChild.pidCut() & (8u << 1)) == 0 || (negChild.pidCut() & (8u << 0)) == 0) + continue; } } + registryMCreco.fill(HIST("minus/MCrecoLambda"), mcpart.pt(), mcpart.eta()); // anti-lambda } } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { - if (part.sign() > 0) { + if (part.mAntiLambda() > 0) { // mAntiLambda is the sign here registryMCreco.fill(HIST("plus/MCrecoAllPt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == kPiPlus && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()))) { + if (mcpart.pdgMCTruth() == kPiPlus) { + if constexpr (std::experimental::is_detected::value) { + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), (part.pidCut() & 512u) != 0)) + continue; + } else { + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & 128u) == 0) // 128 for pion combined + continue; + } else if ((part.pidCut() & 2u) == 0) { + continue; + } + } registryMCreco.fill(HIST("plus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("plus/MCrecoPiPt"), mcpart.pt()); - } else if (mcpart.pdgMCTruth() == kProton && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) { + } else if (mcpart.pdgMCTruth() == kProton) { + if constexpr (std::experimental::is_detected::value) { + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) + continue; + } else { + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & 64u) == 0) // 64 for proton combined + continue; + } else if ((part.pidCut() & 1u) == 0) { + continue; + } + } registryMCreco.fill(HIST("plus/MCrecoPr"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("plus/MCrecoPrPt"), mcpart.pt()); } - } - - if (part.sign() < 0) { + } else if (part.mAntiLambda() < 0) { registryMCreco.fill(HIST("minus/MCrecoAllPt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == kPiMinus && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()))) { + if (mcpart.pdgMCTruth() == kPiMinus) { + if constexpr (std::experimental::is_detected::value) { + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), (part.pidCut() & 512u) != 0)) + continue; + } else { + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & 128u) == 0) // 128 for pion combined + continue; + } else if ((part.pidCut() & 2u) == 0) { + continue; + } + } registryMCreco.fill(HIST("minus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("minus/MCrecoPiPt"), mcpart.pt()); - } else if (mcpart.pdgMCTruth() == kProtonBar && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) { + } else if (mcpart.pdgMCTruth() == kProtonBar) { + if constexpr (std::experimental::is_detected::value) { + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) + continue; + } else { + if ((part.pidCut() & 512u) != 0) { + if ((part.pidCut() & 64u) == 0) // 64 for proton combined + continue; + } else if ((part.pidCut() & 1u) == 0) { + continue; + } + } registryMCreco.fill(HIST("minus/MCrecoPr"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("minus/MCrecoPrPt"), mcpart.pt()); } @@ -1599,7 +1727,17 @@ struct FemtoUniversePairTaskTrackV0Extended { } } + void processMCReco(FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + doMCReco(parts, mcparts); + } PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCReco, "Process MC reco data", false); + + void processMCRecoBitmask(FemtoBasicParticles const& parts, aod::FdMCParticles const& mcparts) + { + doMCReco(parts, mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCRecoBitmask, "Process MC reco data using bitmask for PID", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/FemtoWorld/Tasks/CMakeLists.txt b/PWGCF/FemtoWorld/Tasks/CMakeLists.txt index 4b4e045220a..90503ad0acd 100644 --- a/PWGCF/FemtoWorld/Tasks/CMakeLists.txt +++ b/PWGCF/FemtoWorld/Tasks/CMakeLists.txt @@ -53,3 +53,8 @@ o2physics_add_dpl_workflow(femto-world-efficiency-task-de SOURCES femtoWorldEfficiencyTaskDe.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-lambda-antilambda + SOURCES femtoPairLambdaAntilambda.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx new file mode 100644 index 00000000000..11c590b7002 --- /dev/null +++ b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx @@ -0,0 +1,279 @@ +// Copyright 2019-2025 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 FemtoPairLambdaAntilambda.cxx +/// \brief Tasks that computes correlation between two v0s +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// \author Barbara Gawlik, WUT Warsaw, barbara.maria.gawlik@cern.ch + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/particleCleaner.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGCF/Femto/Core/v0HistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoPairLambdaAntilambda { + + // setup tables + using FemtoCollisions = o2::soa::Join; + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoCollisionsWithLabel = o2::soa::Join; + using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; + using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + + using FemtoTracks = o2::soa::Join; + using FemtoLambdas = o2::soa::Join; + using FemtoK0shorts = o2::soa::Join; + + using FemtoTracksWithLabel = o2::soa::Join; + using FemtoLambdasWithLabel = o2::soa::Join; + using FemtoK0shortsWithLabel = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup for daughters + trackhistmanager::ConfV0PosDauBinning confPosDauBinning; + trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + + // setup lambdas + v0builder::ConfLambdaSelection1 confLambdaSelection; + v0builder::ConfLambdaSelection2 confLambdaSelection2; + particlecleaner::ConfLambdaCleaner1 confLambdaCleaner; + v0histmanager::ConfLambdaBinning1 confLambdaBinning; + + o2::framework::Partition lambdaPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); + o2::framework::Partition lambdaPartition2 = MAKE_LAMBDA_PARTITION(confLambdaSelection2); + o2::framework::Preslice perColLambdas = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition lambdaWithLabelPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); + o2::framework::Partition lambdaWithLabelPartition2 = MAKE_LAMBDA_PARTITION(confLambdaSelection2); + o2::framework::Preslice perCollambdasWithLabel = o2::aod::femtobase::stored::fColId; + + // setup k0shorts + v0builder::ConfK0shortSelection1 confK0shortSelection; + particlecleaner::ConfK0shortCleaner1 confK0shortCleaner; + v0histmanager::ConfK0shortBinning1 confK0shortBinning; + + o2::framework::Partition k0shortPartition = MAKE_K0SHORT_PARTITION(confK0shortSelection); + o2::framework::Preslice perColk0shorts = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition k0shortWithLabelPartition = MAKE_K0SHORT_PARTITION(confK0shortSelection); + o2::framework::Preslice perColk0shortsWithLabel = o2::aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairV0V0Builder< + v0histmanager::PrefixLambda1, + trackhistmanager::PrefixV01PosDaughter, + trackhistmanager::PrefixV01NegDaughter, + v0histmanager::PrefixLambda2, + trackhistmanager::PrefixV02PosDaughter, + trackhistmanager::PrefixV02NegDaughter, + pairhistmanager::PrefixV0V0Se, + pairhistmanager::PrefixV0V0Me, + closepairrejection::PrefixV0V0PosSe, + closepairrejection::PrefixV0V0NegSe, + closepairrejection::PrefixV0V0PosMe, + closepairrejection::PrefixV0V0NegMe, + modes::V0::kLambda, + modes::V0::kLambda> + pairLambdaLambdaBuilder; + + pairbuilder::PairV0V0Builder< + v0histmanager::PrefixK0short1, + trackhistmanager::PrefixV01PosDaughter, + trackhistmanager::PrefixV01NegDaughter, + v0histmanager::PrefixK0short2, + trackhistmanager::PrefixV02PosDaughter, + trackhistmanager::PrefixV02NegDaughter, + pairhistmanager::PrefixV0V0Se, + pairhistmanager::PrefixV0V0Me, + closepairrejection::PrefixV0V0PosSe, + closepairrejection::PrefixV0V0NegSe, + closepairrejection::PrefixV0V0PosMe, + closepairrejection::PrefixV0V0NegMe, + modes::V0::kK0short, + modes::V0::kK0short> + pairK0shortK0shortBuilder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + o2::framework::ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + o2::framework::HistogramRegistry hRegistry{"FemtoV0V0", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprV0DaugherV0DaughterPos confCprPos; + closepairrejection::ConfCprV0DaugherV0DaughterNeg confCprNeg; + + void init(o2::framework::InitContext&) + { + + // TODO: implement lambda-k0short + bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaSameEvent || doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortSameEvent; + bool processMc = doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaSameEventMc || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortSameEventMc; + + if (processData && processMc) { + LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; + } + + bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; + bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; + + if (processLambdaLambda && processK0shortK0short) { + LOG(fatal) << "Both lambda-lambda and k0short-k0short processing is enabled. Breaking..."; + } + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histograms + std::map> colHistSpec; + std::map> trackHistSpec; + std::map> posDauSpec; + std::map> negDauSpec; + std::map> lambdaHistSpec; + std::map> k0shortHistSpec; + std::map> pairV0V0HistSpec; + std::map> cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); + std::map> cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); + + if (processData) { + colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + if (processLambdaLambda) { + lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); + pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + } + + // setup for k0short + if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { + k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); + pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + } + } else { + colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); + posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + if (processLambdaLambda) { + lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); + pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + } + + // setup for k0short + if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { + k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); + pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + } + } + }; + + void processLambdaLambdaSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas) + { + pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, lambdaPartition2, cache); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEvent, "Enable processing same event processing for lambda-lambda", true); + + void processLambdaLambdaSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& lambdas, o2::aod::FMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairLambdaLambdaBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEventMc, "Enable processing same event processing for lambda-lambda with mc information", false); + + void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& lambdas) + { + pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdas, lambdaPartition, lambdaPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambda-lambda", true); + + void processLambdaLambdaMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, o2::aod::FMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairLambdaLambdaBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEventMc, "Enable processing mixed event processing for lambda-lambda with mc information", false); + + void processK0shortK0shortSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) + { + pairK0shortK0shortBuilder.processSameEvent(col, tracks, k0shorts, k0shortPartition, k0shortPartition, cache); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortSameEvent, "Enable processing same event processing for k0short-k0short", false); + + void processK0shortK0shortSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& k0shorts, o2::aod::FMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairK0shortK0shortBuilder.processSameEvent(col, mcCols, tracks, k0shorts, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortSameEventMc, "Enable processing same event processing for k0short-k0short with mc information", false); + + void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) + { + pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shorts, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortMixedEvent, "Enable processing mixed event processing for k0short-k0short", false); + + void processK0shortK0shortMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& /*k0shorts*/, o2::aod::FMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortMixedEventMc, "Enable processing mixed event processing for k0short-k0short with mc information", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Flow/Tasks/CMakeLists.txt b/PWGCF/Flow/Tasks/CMakeLists.txt index b1300623c73..cb080629efb 100644 --- a/PWGCF/Flow/Tasks/CMakeLists.txt +++ b/PWGCF/Flow/Tasks/CMakeLists.txt @@ -64,6 +64,11 @@ o2physics_add_dpl_workflow(flow-pid-cme PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(flow-zdc-energy + SOURCES flowZdcEnergy.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(flow-sp SOURCES flowSP.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore diff --git a/PWGCF/Flow/Tasks/flowEventPlane.cxx b/PWGCF/Flow/Tasks/flowEventPlane.cxx index ea895bc8232..510ba5c5b89 100644 --- a/PWGCF/Flow/Tasks/flowEventPlane.cxx +++ b/PWGCF/Flow/Tasks/flowEventPlane.cxx @@ -106,8 +106,14 @@ enum ParticleType { kNPart }; +enum ResoType { + kPhi0 = 0, + kKStar +}; + enum V0Type { - kLambda = 0, + kK0S = 0, + kLambda, kAntiLambda }; @@ -717,11 +723,17 @@ struct SpectatorPlaneTableProducer { struct FlowEventPlane { // Tracks - Configurable cNEtaBins{"cNEtaBins", 7, "# of eta bins"}; + Configurable cNEtaBins{"cNEtaBins", 5, "# of eta bins"}; + + // Pi,Ka,Pr + Configurable cMinPtPi{"cMinPtPi", 0.2, "Pion min pT"}; + Configurable cMinPtKa{"cMinPtKa", 0.3, "Kaon min pT"}; + Configurable cMinPtPr{"cMinPtPr", 0.5, "Proton min pT"}; // Resonance Configurable cNRapBins{"cNRapBins", 5, "# of y bins"}; - Configurable cNInvMassBins{"cNInvMassBins", 500, "# of m bins"}; + Configurable cPhiInvMassBins{"cPhiInvMassBins", 500, "# of Phi mass bins"}; + Configurable cKStarInvMassBins{"cKStarInvMassBins", 200, "# of Phi mass bins"}; Configurable cResRapCut{"cResRapCut", 0.5, "Resonance rapidity cut"}; // V0 @@ -732,19 +744,22 @@ struct FlowEventPlane { // V0s Configurable cV0TypeSelection{"cV0TypeSelection", 1, "V0 Type Selection"}; - Configurable cMinDcaProtonToPV{"cMinDcaProtonToPV", 0.02, "Minimum Proton DCAr to PV"}; - Configurable cMinDcaPionToPV{"cMinDcaPionToPV", 0.06, "Minimum Pion DCAr to PV"}; + Configurable cMinDcaProtonToPV{"cMinDcaProtonToPV", 0.01, "Minimum Proton DCAr to PV"}; + Configurable cMinDcaPionToPV{"cMinDcaPionToPV", 0.1, "Minimum Pion DCAr to PV"}; Configurable cDcaV0Dau{"cDcaV0Dau", 1., "DCA between V0 daughters"}; Configurable cDcaV0ToPv{"cDcaV0ToPv", 0.1, "DCA V0 to PV"}; Configurable cMinV0Radius{"cMinV0Radius", 0.5, "Minimum V0 radius from PV"}; - Configurable cMaxV0Radius{"cMaxV0Radius", 999.0, "Maximum V0 radius from PV"}; - Configurable cV0CTau{"cV0CTau", 30.0, "Decay length cut"}; - Configurable cV0CosPA{"cV0CosPA", 0.995, "V0 CosPA to PV"}; + Configurable cK0ShortCTau{"cK0ShortCTau", 20.0, "Decay length cut K0Short"}; + Configurable cLambdaCTau{"cLambdaCTau", 30.0, "Decay length cut Lambda"}; + Configurable cK0ShortCosPA{"cK0ShortCosPA", 0.998, "K0Short CosPA"}; + Configurable cLambdaCosPA{"cLambdaCosPA", 0.998, "Lambda CosPA"}; Configurable cK0SMassRej{"cK0SMassRej", 0.01, "Reject K0Short Candidates"}; - Configurable cLambdaMassWin{"cLambdaMassWin", 0.007, "Lambda Mass Window"}; - Configurable cMinV0Pt{"cMinV0Pt", 0.5, "Min v0 pT"}; - Configurable cMaxV0Pt{"cMaxV0Pt", 4.5, "Max v0 pT"}; - Configurable cV0RapCut{"cV0RapCut", 0.5, "V0 rap cut"}; + Configurable cArmPodSel{"cArmPodSel", 0.2, "Armentros-Podolanski Selection for K0S"}; + Configurable cV0RapCut{"cV0RapCut", 0.8, "V0 rap cut"}; + Configurable cK0SMinPt{"cK0SMinPt", 0.4, "K0S Min pT"}; + Configurable cK0SMaxPt{"cK0SMaxPt", 6.0, "K0S Max pT"}; + Configurable cLambdaMinPt{"cLambdaMinPt", 0.6, "Lambda Min pT"}; + Configurable cLambdaMaxPt{"cLambdaMaxPt", 6.0, "Lambda Max pT"}; // Histogram registry: an object to hold your histograms HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -752,6 +767,10 @@ struct FlowEventPlane { // Global objects float cent = 0.; std::array vSP = {0., 0., 0., 0.}; + std::map> mResoDauMass = {{kPhi0, {MassKaonCharged, MassKaonCharged}}, {kKStar, {MassPionCharged, MassKaonCharged}}}; + std::map mResoMass = {{kPhi0, MassPhi}, {kKStar, MassKaonCharged}}; + std::map mV0Ctau = {{kK0S, cK0ShortCTau}, {kLambda, cLambdaCTau}, {kAntiLambda, cLambdaCTau}}; + std::map mV0CosPA = {{kK0S, cK0ShortCosPA}, {kLambda, cLambdaCosPA}, {kAntiLambda, cLambdaCosPA}}; void init(InitContext const&) { @@ -769,7 +788,8 @@ struct FlowEventPlane { const AxisSpec axisTrackNSigma{161, -4.025, 4.025, {"n#sigma"}}; const AxisSpec axisTrackRap{cNRapBins, -0.5, 0.5, "y"}; - const AxisSpec axisInvMass{cNInvMassBins, 0.87, 1.12, "M_{KK} (GeV/#it{c}^{2}"}; + const AxisSpec axisPhiInvMass{cPhiInvMassBins, 0.99, 1.12, "M_{KK} (GeV/#it{c}^{2}"}; + const AxisSpec axisKStarInvMass{cKStarInvMassBins, 0.8, 1.2, "M_{#piK} (GeV/#it{c}^{2}"}; const AxisSpec axisMomPID(80, 0, 4, "p_{T} (GeV/#it{c})"); const AxisSpec axisNsigma(401, -10.025, 10.025, {"n#sigma"}); const AxisSpec axisdEdx(360, 20, 200, "#frac{dE}{dx}"); @@ -782,8 +802,8 @@ struct FlowEventPlane { const AxisSpec axisCTau(2000, 0, 200, "c#tau (cm)"); const AxisSpec axisAlpha(40, -1, 1, "#alpha"); const AxisSpec axisQtarm(40, 0, 0.4, "q_{T}"); - const AxisSpec axisLambdaPt(50, 0, 10, "p_{T} (GeV/#it{c})"); const AxisSpec axisLambdaInvMass(140, 1.08, 1.15, "M_{p#pi} (GeV/#it{c}^{2})"); + const AxisSpec axisK0ShortInvMass(200, 0.4, 0.6, "M_{#pi#pi} (GeV/#it{c}^{2})"); // Create histograms // Charged particles @@ -791,7 +811,6 @@ struct FlowEventPlane { histos.add("TrackQA/hPtDcaXY", "DCA_{XY} vs p_{T}", kTH2F, {axisTrackPt, axisTrackDcaXY}); histos.add("TrackQA/hPtDcaZ", "DCA_{Z} vs p_{T}", kTH2F, {axisTrackPt, axisTrackDcaZ}); histos.add("TrackQA/hTrackTPCdEdX", "hTrackTPCdEdX", kTH2F, {axisMomPID, axisdEdx}); - histos.add("DF/hQaQc", "X^{A}_{1}X^{C}_{1} + Y^{A}_{1}Y^{C}_{1}", kTProfile, {axisCent}); histos.add("DF/hAQu", "u_{x}X^{A}_{1} + u_{y}Y^{A}_{1}", kTProfile2D, {axisCent, axisTrackEta}); histos.add("DF/hCQu", "u_{x}X^{C}_{1} + u_{y}Y^{C}_{1}", kTProfile2D, {axisCent, axisTrackEta}); histos.add("DF/hAQuPos", "u_{x}X^{A}_{1} + u_{y}Y^{A}_{1}", kTProfile2D, {axisCent, axisTrackEta}); @@ -816,34 +835,44 @@ struct FlowEventPlane { // Resonance if (doprocessResoFlow) { - histos.add("Reso/Phi/hSigCentPtInvMass", "hUSCentPtInvMass", kTH3F, {axisCent, axisTrackPt, axisInvMass}); - histos.add("Reso/Phi/hBkgCentPtInvMass", "hLSCentPtInvMass", kTH3F, {axisCent, axisTrackPt, axisInvMass}); - histos.add("Reso/Phi/Sig/hPhiQuA", "hPhiQuA", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); - histos.add("Reso/Phi/Sig/hPhiQuC", "hPhiQuC", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); - histos.add("Reso/Phi/Bkg/hPhiQuA", "hPhiQuA", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); - histos.add("Reso/Phi/Bkg/hPhiQuC", "hPhiQuC", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); + histos.add("Reso/Phi/hSigCentEtaInvMass", "hUSCentEtaInvMass", kTH3F, {axisCent, axisTrackEta, axisPhiInvMass}); + histos.add("Reso/Phi/hBkgCentEtaInvMass", "hLSCentEtaInvMass", kTH3F, {axisCent, axisTrackEta, axisPhiInvMass}); + histos.add("Reso/Phi/Sig/hQuA", "hPhiQuA", kTProfile3D, {axisCent, axisTrackEta, axisPhiInvMass}); + histos.add("Reso/Phi/Sig/hQuC", "hPhiQuC", kTProfile3D, {axisCent, axisTrackEta, axisPhiInvMass}); + histos.add("Reso/Phi/Bkg/hQuA", "hPhiQuA", kTProfile3D, {axisCent, axisTrackEta, axisPhiInvMass}); + histos.add("Reso/Phi/Bkg/hQuC", "hPhiQuC", kTProfile3D, {axisCent, axisTrackEta, axisPhiInvMass}); + histos.add("Reso/KStar/hSigCentEtaInvMass", "hUSCentEtaInvMass", kTH3F, {axisCent, axisTrackEta, axisKStarInvMass}); + histos.add("Reso/KStar/hBkgCentEtaInvMass", "hLSCentEtaInvMass", kTH3F, {axisCent, axisTrackEta, axisKStarInvMass}); + histos.add("Reso/KStar/Sig/hQuA", "hKStarQuA", kTProfile3D, {axisCent, axisTrackEta, axisKStarInvMass}); + histos.add("Reso/KStar/Sig/hQuC", "hKStarQuC", kTProfile3D, {axisCent, axisTrackEta, axisKStarInvMass}); + histos.add("Reso/KStar/Bkg/hQuA", "hKStarQuA", kTProfile3D, {axisCent, axisTrackEta, axisKStarInvMass}); + histos.add("Reso/KStar/Bkg/hQuC", "hKStarQuC", kTProfile3D, {axisCent, axisTrackEta, axisKStarInvMass}); } // Lambda - if (doprocessLambdaFlow) { - histos.add("Lambda/QA/hQtVsAlpha", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); - histos.add("Lambda/QA/hDcaV0Dau", "DCA between V0 daughters", kTH1F, {axisDcaDau}); - histos.add("Lambda/QA/hDcaPosToPv", "DCA positive prong to PV", kTH1F, {axisDcaProngPV}); - histos.add("Lambda/QA/hDcaNegToPv", "DCA negative prong to PV", kTH1F, {axisDcaProngPV}); - histos.add("Lambda/QA/hDcaV0ToPv", "DCA V0 to PV", kTH1F, {axisDcaV0PV}); - histos.add("Lambda/QA/hCosPa", "cos(#theta_{PA})", kTH1F, {axisCosPA}); - histos.add("Lambda/QA/hRxy", "V_{0} Decay Radius in XY plane", kTH1F, {axisRadius}); - histos.add("Lambda/QA/hCTau", "V_{0} c#tau", kTH1F, {axisCTau}); - histos.add("Lambda/QA/hPosdEdXVsP", "TPC Signal Pos-Prong", kTH2F, {axisMomPID, axisdEdx}); - histos.add("Lambda/QA/hNegdEdXVsP", "TPC Signal Neg-Prong", kTH2F, {axisMomPID, axisdEdx}); - histos.add("Lambda/QA/hPosNsigPrVsP", "TPC n#sigma Pos Prong", kTH2F, {axisMomPID, axisNsigma}); - histos.add("Lambda/QA/hNegNsigPrVsP", "TPC n#sigma Neg Prong", kTH2F, {axisMomPID, axisNsigma}); - histos.add("Lambda/QA/hPosNsigPiVsP", "TPC n#sigma Pos Prong", kTH2F, {axisMomPID, axisNsigma}); - histos.add("Lambda/QA/hNegNsigPiVsP", "TPC n#sigma Neg Prong", kTH2F, {axisMomPID, axisNsigma}); - histos.add("Lambda/hInvMassVsPt", "hInvMassVsPt", kTH3F, {axisCent, axisLambdaInvMass, axisLambdaPt}); - histos.add("Lambda/Flow/hQuA", "hPhiQuA", kTProfile3D, {axisCent, axisTrackRap, axisLambdaInvMass}); - histos.add("Lambda/Flow/hQuC", "hPhiQuC", kTProfile3D, {axisCent, axisTrackRap, axisLambdaInvMass}); - histos.addClone("Lambda/", "AntiLambda/"); + if (doprocessV0Flow) { + histos.add("V0/Lambda/QA/hQtVsAlpha", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); + histos.add("V0/Lambda/QA/hDcaV0Dau", "DCA between V0 daughters", kTH1F, {axisDcaDau}); + histos.add("V0/Lambda/QA/hDcaPosToPv", "DCA positive prong to PV", kTH1F, {axisDcaProngPV}); + histos.add("V0/Lambda/QA/hDcaNegToPv", "DCA negative prong to PV", kTH1F, {axisDcaProngPV}); + histos.add("V0/Lambda/QA/hDcaV0ToPv", "DCA V0 to PV", kTH1F, {axisDcaV0PV}); + histos.add("V0/Lambda/QA/hCosPa", "cos(#theta_{PA})", kTH1F, {axisCosPA}); + histos.add("V0/Lambda/QA/hRxy", "V_{0} Decay Radius in XY plane", kTH1F, {axisRadius}); + histos.add("V0/Lambda/QA/hCTau", "V_{0} c#tau", kTH1F, {axisCTau}); + histos.add("V0/Lambda/QA/hPosdEdXVsP", "TPC Signal Pos-Prong", kTH2F, {axisMomPID, axisdEdx}); + histos.add("V0/Lambda/QA/hNegdEdXVsP", "TPC Signal Neg-Prong", kTH2F, {axisMomPID, axisdEdx}); + histos.add("V0/Lambda/QA/hPosNsigPrVsP", "TPC n#sigma Pos Prong", kTH2F, {axisMomPID, axisNsigma}); + histos.add("V0/Lambda/QA/hNegNsigPrVsP", "TPC n#sigma Neg Prong", kTH2F, {axisMomPID, axisNsigma}); + histos.add("V0/Lambda/QA/hPosNsigPiVsP", "TPC n#sigma Pos Prong", kTH2F, {axisMomPID, axisNsigma}); + histos.add("V0/Lambda/QA/hNegNsigPiVsP", "TPC n#sigma Neg Prong", kTH2F, {axisMomPID, axisNsigma}); + histos.addClone("V0/Lambda/", "V0/K0Short/"); + histos.add("V0/Lambda/hMassVsRap", "hMassVsRap", kTH3F, {axisCent, axisLambdaInvMass, axisTrackEta}); + histos.add("V0/Lambda/Flow/hQuA", "hQuA", kTProfile3D, {axisCent, axisTrackRap, axisLambdaInvMass}); + histos.add("V0/Lambda/Flow/hQuC", "hQuC", kTProfile3D, {axisCent, axisTrackRap, axisLambdaInvMass}); + histos.addClone("V0/Lambda/", "V0/AntiLambda/"); + histos.add("V0/K0Short/hMassVsRap", "hMassVsRap", kTH3F, {axisCent, axisK0ShortInvMass, axisTrackEta}); + histos.add("V0/K0Short/Flow/hQuA", "hQuA", kTProfile3D, {axisCent, axisTrackRap, axisK0ShortInvMass}); + histos.add("V0/K0Short/Flow/hQuC", "hQuC", kTProfile3D, {axisCent, axisTrackRap, axisK0ShortInvMass}); } } @@ -874,13 +903,13 @@ struct FlowEventPlane { float tpcNsigma = 0., tofNsigma = 0.; for (auto const& track : tracks) { static constexpr std::string_view SubDir[] = {"Pion/", "Kaon/", "Proton/"}; - if (part == kPi) { + if (part == kPi && track.pt() > cMinPtPi) { tpcNsigma = track.tpcNSigmaPi(); tofNsigma = track.tofNSigmaPi(); - } else if (part == kKa) { + } else if (part == kKa && track.pt() > cMinPtKa) { tpcNsigma = track.tpcNSigmaKa(); tofNsigma = track.tofNSigmaKa(); - } else if (part == kPr) { + } else if (part == kPr && track.pt() > cMinPtPr) { tpcNsigma = track.tpcNSigmaPr(); tofNsigma = track.tofNSigmaPr(); } else { @@ -893,6 +922,7 @@ struct FlowEventPlane { histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hTOFNSigma"), track.pt(), tofNsigma); } + // Directed flow ux = std::cos(track.phi()); uy = std::sin(track.phi()); v1a = ux * vSP[kXa] + uy * vSP[kYa]; @@ -916,40 +946,47 @@ struct FlowEventPlane { return false; } - // Apply DCA Selection on Daughter Tracks Based on Lambda/AntiLambda daughters - float dcaProton = 0., dcaPion = 0.; - if (part == kLambda) { - dcaProton = std::abs(v0.dcapostopv()); - dcaPion = std::abs(v0.dcanegtopv()); + // Apply DCA Selection on Daughter Tracks Based on Lambda/AntiLambda/K0Short daughters + if (part == kK0S) { + if (std::abs(v0.dcapostopv()) <= cMinDcaPionToPV || std::abs(v0.dcanegtopv()) <= cMinDcaPionToPV) { + return false; + } + } else if (part == kLambda) { + if (std::abs(v0.dcapostopv()) <= cMinDcaProtonToPV || std::abs(v0.dcanegtopv()) <= cMinDcaPionToPV) { + return false; + } } else if (part == kAntiLambda) { - dcaPion = std::abs(v0.dcapostopv()); - dcaProton = std::abs(v0.dcanegtopv()); + if (std::abs(v0.dcapostopv()) <= cMinDcaPionToPV || std::abs(v0.dcanegtopv()) <= cMinDcaProtonToPV) { + return false; + } } else { return false; } - if (dcaProton <= cMinDcaProtonToPV || dcaPion <= cMinDcaPionToPV) { - return false; - } - - // Daughter track PID - float tpcNSigmaPr = 0., tpcNSigmaPi = 0.; + // Daughter track PID [Dau1 = PosTrack, Dau2 = NegTrack] + float tpcNSigmaDau1 = 0., tpcNSigmaDau2 = 0.; switch (part) { - // postrack = Proton, negtrack = Pion + // Dau1 = Proton, Dau2 = Pion case kLambda: - tpcNSigmaPr = postrack.tpcNSigmaPr(); - tpcNSigmaPi = negtrack.tpcNSigmaPi(); + tpcNSigmaDau1 = postrack.tpcNSigmaPr(); + tpcNSigmaDau2 = negtrack.tpcNSigmaPi(); break; - // negtrack = Proton, postrack = Pion + // Dau1 = Pion, Dau2 = Proton case kAntiLambda: - tpcNSigmaPr = negtrack.tpcNSigmaPr(); - tpcNSigmaPi = postrack.tpcNSigmaPi(); + tpcNSigmaDau1 = postrack.tpcNSigmaPi(); + tpcNSigmaDau2 = negtrack.tpcNSigmaPr(); + break; + + // Dau1 = Pion, Dau2 = Pion + case kK0S: + tpcNSigmaDau1 = postrack.tpcNSigmaPi(); + tpcNSigmaDau2 = negtrack.tpcNSigmaPi(); break; } - if (std::abs(tpcNSigmaPr) >= cTpcNsigmaCut || std::abs(tpcNSigmaPi) >= cTpcNsigmaCut) { + if (std::abs(tpcNSigmaDau1) >= cTpcNsigmaCut || std::abs(tpcNSigmaDau2) >= cTpcNsigmaCut) { return false; } @@ -959,14 +996,20 @@ struct FlowEventPlane { template void fillV0QAHist(C const& col, V const& v0, T const&) { - static constexpr std::string_view SubDir[] = {"Lambda/QA/", "AntiLambda/QA/"}; + static constexpr std::string_view SubDir[] = {"V0/K0Short/QA/", "V0/Lambda/QA/", "V0/AntiLambda/QA/"}; // daugthers auto postrack = v0.template posTrack_as(); auto negtrack = v0.template negTrack_as(); // ctau - float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; + float mPDG = 0, ctau = 0; + if (part == kK0S) { + mPDG = MassKaonNeutral; + } else { + mPDG = MassLambda0; + } + ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * mPDG; histos.fill(HIST(SubDir[part]) + HIST("hQtVsAlpha"), v0.alpha(), v0.qtarm()); histos.fill(HIST(SubDir[part]) + HIST("hDcaV0Dau"), v0.dcaV0daughters()); @@ -984,10 +1027,11 @@ struct FlowEventPlane { histos.fill(HIST(SubDir[part]) + HIST("hNegNsigPiVsP"), negtrack.tpcInnerParam(), negtrack.tpcNSigmaPi()); } - template + template void getResoFlow(T const& tracks1, T const& tracks2, std::array const& vSP) { float ux = 0., uy = 0., v1a = 0., v1c = 0.; + std::array vMassDau = mResoDauMass.at(rt); for (auto const& [track1, track2] : soa::combinations(soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { // Discard same track if (track1.index() == track2.index()) { @@ -999,15 +1043,15 @@ struct FlowEventPlane { continue; } - // Apply rapidity acceptance + // Apply pseudo-rapidity acceptance std::array v = {track1.px() + track2.px(), track1.py() + track2.py(), track1.pz() + track2.pz()}; - if (RecoDecay::y(v, MassPhi) >= cResRapCut) { + if (std::abs(RecoDecay::eta(v)) >= cResRapCut) { continue; } - // Reconstruct phi meson + // Reconstruct resonance float p = RecoDecay::p((track1.px() + track2.px()), (track1.py() + track2.py()), (track1.pz() + track2.pz())); - float e = RecoDecay::e(track1.px(), track1.py(), track1.pz(), MassKaonCharged) + RecoDecay::e(track2.px(), track2.py(), track2.pz(), MassKaonCharged); + float e = RecoDecay::e(track1.px(), track1.py(), track1.pz(), vMassDau[0]) + RecoDecay::e(track2.px(), track2.py(), track2.pz(), vMassDau[1]); float m = std::sqrt(RecoDecay::m2(p, e)); // Get directed flow @@ -1016,10 +1060,13 @@ struct FlowEventPlane { v1a = ux * vSP[kXa] + uy * vSP[kYa]; v1c = ux * vSP[kXc] + uy * vSP[kYc]; + // Histograms + static constexpr std::string_view SubDir[] = {"Reso/Phi/", "Reso/KStar/"}; + // Fill signal histogram - histos.fill(HIST("Reso/Phi/hSigCentPtInvMass"), cent, RecoDecay::pt(v), m); - histos.fill(HIST("Reso/Phi/Sig/hPhiQuA"), cent, RecoDecay::y(v, MassPhi), m, v1a); - histos.fill(HIST("Reso/Phi/Sig/hPhiQuC"), cent, RecoDecay::y(v, MassPhi), m, v1c); + histos.fill(HIST(SubDir[rt]) + HIST("hSigCentEtaInvMass"), cent, RecoDecay::eta(v), m); + histos.fill(HIST(SubDir[rt]) + HIST("Sig/hQuA"), cent, RecoDecay::eta(v), m, v1a); + histos.fill(HIST(SubDir[rt]) + HIST("Sig/hQuC"), cent, RecoDecay::eta(v), m, v1c); // Get background p = RecoDecay::p((track1.px() - track2.px()), (track1.py() - track2.py()), (track1.pz() - track2.pz())); @@ -1033,9 +1080,9 @@ struct FlowEventPlane { v1c = ux * vSP[kXc] + uy * vSP[kYc]; // Fill bkg histogram - histos.fill(HIST("Reso/Phi/hBkgCentPtInvMass"), cent, RecoDecay::pt(v), m); - histos.fill(HIST("Reso/Phi/Bkg/hPhiQuA"), cent, RecoDecay::y(v, MassPhi), m, v1a); - histos.fill(HIST("Reso/Phi/Bkg/hPhiQuC"), cent, RecoDecay::y(v, MassPhi), m, v1c); + histos.fill(HIST(SubDir[rt]) + HIST("hBkgCentEtaInvMass"), cent, RecoDecay::eta(v), m); + histos.fill(HIST(SubDir[rt]) + HIST("Bkg/hQuA"), cent, RecoDecay::eta(v), m, v1a); + histos.fill(HIST(SubDir[rt]) + HIST("Bkg/hQuC"), cent, RecoDecay::eta(v), m, v1c); } } @@ -1113,14 +1160,16 @@ struct FlowEventPlane { } // Track partitions + auto pionTracks = pionTrackPartition->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto kaonTracks = kaonTrackPartition->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); // Resonance flow - getResoFlow(kaonTracks, kaonTracks, vSP); + getResoFlow(kaonTracks, kaonTracks, vSP); + getResoFlow(pionTracks, kaonTracks, vSP); } PROCESS_SWITCH(FlowEventPlane, processResoFlow, "Resonance flow process", false); - void processLambdaFlow(CollisionsRun3::iterator const& collision, aod::V0Datas const& V0s, TracksV0s const& tracks) + void processV0Flow(CollisionsRun3::iterator const& collision, aod::V0Datas const& V0s, TracksV0s const& tracks) { if (!selCollision(collision, vSP)) { return; @@ -1128,69 +1177,49 @@ struct FlowEventPlane { // Loop over v0s for (auto const& v0 : V0s) { - // V0 kinematic selection - if (v0.pt() <= cMinV0Pt || v0.pt() >= cMaxV0Pt || std::abs(v0.yLambda()) >= cV0RapCut) { - continue; - } - - // Topological selections - float ctau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda0; - if (v0.dcaV0daughters() >= cDcaV0Dau || v0.dcav0topv() >= cDcaV0ToPv || - v0.v0radius() <= cMinV0Radius || v0.v0radius() >= cMaxV0Radius || - v0.v0cosPA() <= cV0CosPA || ctau >= cV0CTau || v0.v0Type() != cV0TypeSelection) { + // Topological and kinematic selections + if (std::abs(v0.eta()) >= cV0RapCut || v0.dcaV0daughters() >= cDcaV0Dau || v0.dcav0topv() >= cDcaV0ToPv || v0.v0radius() <= cMinV0Radius || v0.v0Type() != cV0TypeSelection) { continue; } - // Ks Mass Rejection - if (std::abs(v0.mK0Short() - MassK0Short) <= cK0SMassRej) { - continue; - } - - // Initialize daughter tracks - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - - // Initialize selection flags - bool lambdaFlag = false, antiLambdaFlag = false; - - // Get v0 track as lambda - if ((std::abs(v0.mLambda() - MassLambda0) < cLambdaMassWin) && (selV0DauTracks(v0, postrack, negtrack))) { - lambdaFlag = true; - } - - // Get v0 track as anti-lambda - if ((std::abs(v0.mAntiLambda() - MassLambda0) < cLambdaMassWin) && (selV0DauTracks(v0, postrack, negtrack))) { - antiLambdaFlag = true; - } - - // Lambda/Anti-Lambda selection checks - if (!lambdaFlag && !antiLambdaFlag) { // neither Lambda nor Anti-Lambda - continue; - } else if (lambdaFlag && antiLambdaFlag) { // check if the track is identified as lambda and anti-lambda both (DISCARD THIS TRACK) - continue; - } - - // We have a Lambda/Anti-Lambda // Directed flow float ux = std::cos(v0.phi()); float uy = std::sin(v0.phi()); float v1a = ux * vSP[kXa] + uy * vSP[kYa]; float v1c = ux * vSP[kXc] + uy * vSP[kYc]; - if (lambdaFlag) { + // Initialize selection objects + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + float ctauK0Short = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassKaonNeutral; + float ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda0; + + // K0Short + if (selV0DauTracks(v0, postrack, negtrack) && v0.v0cosPA() > mV0CosPA.at(kK0S) && ctauK0Short < mV0Ctau.at(kK0S) && v0.qtarm() >= cArmPodSel * std::abs(v0.alpha()) && v0.pt() >= cK0SMinPt && v0.pt() < cK0SMaxPt) { + fillV0QAHist(collision, v0, tracks); + histos.fill(HIST("V0/K0Short/hMassVsRap"), cent, v0.mK0Short(), v0.eta()); + histos.fill(HIST("V0/K0Short/Flow/hQuA"), cent, v0.eta(), v0.mK0Short(), v1a); + histos.fill(HIST("V0/K0Short/Flow/hQuC"), cent, v0.eta(), v0.mK0Short(), v1c); + } + + // Lambda + if (selV0DauTracks(v0, postrack, negtrack) && v0.v0cosPA() > mV0CosPA.at(kLambda) && ctauLambda < mV0Ctau.at(kLambda) && std::abs(v0.mK0Short() - MassK0Short) >= cK0SMassRej && v0.pt() >= cLambdaMinPt && v0.pt() < cLambdaMaxPt) { fillV0QAHist(collision, v0, tracks); - histos.fill(HIST("Lambda/hInvMassVsPt"), cent, v0.mLambda(), v0.pt()); - histos.fill(HIST("Lambda/Flow/hQuA"), cent, v0.yLambda(), v0.mLambda(), v1a); - histos.fill(HIST("Lambda/Flow/hQuC"), cent, v0.yLambda(), v0.mLambda(), v1c); - } else if (antiLambdaFlag) { + histos.fill(HIST("V0/Lambda/hMassVsRap"), cent, v0.mLambda(), v0.eta()); + histos.fill(HIST("V0/Lambda/Flow/hQuA"), cent, v0.eta(), v0.mLambda(), v1a); + histos.fill(HIST("V0/Lambda/Flow/hQuC"), cent, v0.eta(), v0.mLambda(), v1c); + } + + // AntiLambda + if (selV0DauTracks(v0, postrack, negtrack) && v0.v0cosPA() > mV0CosPA.at(kAntiLambda) && ctauLambda < mV0Ctau.at(kAntiLambda) && std::abs(v0.mK0Short() - MassK0Short) >= cK0SMassRej && v0.pt() >= cLambdaMinPt && v0.pt() < cLambdaMaxPt) { fillV0QAHist(collision, v0, tracks); - histos.fill(HIST("AntiLambda/hInvMassVsPt"), cent, v0.mAntiLambda(), v0.pt()); - histos.fill(HIST("AntiLambda/Flow/hQuA"), cent, v0.yLambda(), v0.mAntiLambda(), v1a); - histos.fill(HIST("AntiLambda/Flow/hQuC"), cent, v0.yLambda(), v0.mAntiLambda(), v1c); + histos.fill(HIST("V0/AntiLambda/hMassVsRap"), cent, v0.mAntiLambda(), v0.eta()); + histos.fill(HIST("V0/AntiLambda/Flow/hQuA"), cent, v0.eta(), v0.mAntiLambda(), v1a); + histos.fill(HIST("V0/AntiLambda/Flow/hQuC"), cent, v0.eta(), v0.mAntiLambda(), v1c); } } } - PROCESS_SWITCH(FlowEventPlane, processLambdaFlow, "Lambda flow process", false); + PROCESS_SWITCH(FlowEventPlane, processV0Flow, "Lambda flow process", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx b/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx index 4b41fbbb893..7ed06b21a6c 100644 --- a/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx +++ b/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx @@ -119,6 +119,8 @@ struct FlowGfwOmegaXi { O2_DEFINE_CONFIGURABLE(cfgcasc_v0cospa, float, 0.998f, "minimum cosine of pointing angle") O2_DEFINE_CONFIGURABLE(cfgcasc_dcav0topv, float, 0.01f, "minimum daughter DCA to PV") O2_DEFINE_CONFIGURABLE(cfgcasc_dcabachtopv, float, 0.01f, "minimum bachelor DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcaLapitopv, float, 0.1f, "minimum pion from casc->Lambda->Pi DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcaLaprtopv, float, 0.1f, "minimum proton from casc->Lambda->Pr DCA to PV") O2_DEFINE_CONFIGURABLE(cfgcasc_dcacascdau, float, 0.3f, "maximum DCA among cascade daughters") O2_DEFINE_CONFIGURABLE(cfgcasc_dcav0dau, float, 1.0f, "maximum DCA among V0 daughters") O2_DEFINE_CONFIGURABLE(cfgcasc_mlambdawindow, float, 0.04f, "Invariant mass window of lambda") @@ -423,18 +425,35 @@ struct FlowGfwOmegaXi { // QA if (cfgOutputQA) { // V0 QA - registry.add("QAhisto/V0/hqaV0radiusbefore", "", {HistType::kTH1D, {{200, 0, 200}}}); - registry.add("QAhisto/V0/hqaV0radiusafter", "", {HistType::kTH1D, {{200, 0, 200}}}); - registry.add("QAhisto/V0/hqaV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); - registry.add("QAhisto/V0/hqaV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); - registry.add("QAhisto/V0/hqadcaV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); - registry.add("QAhisto/V0/hqadcaV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); - registry.add("QAhisto/V0/hqaarm_podobefore", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); - registry.add("QAhisto/V0/hqaarm_podoafter", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); - registry.add("QAhisto/V0/hqadcapostoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); - registry.add("QAhisto/V0/hqadcapostoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); - registry.add("QAhisto/V0/hqadcanegtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); - registry.add("QAhisto/V0/hqadcanegtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/K0s/hqaV0radiusbefore", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/K0s/hqaV0radiusafter", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/K0s/hqaV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/K0s/hqaV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/K0s/hqadcaV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/K0s/hqadcaV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/K0s/hqaarm_podobefore", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); + registry.add("QAhisto/K0s/hqaarm_podoafter", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); + registry.add("QAhisto/K0s/hqadcapostoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/K0s/hqadcapostoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/K0s/hqadcanegtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/K0s/hqadcanegtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/K0s/hphiposPi", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("QAhisto/K0s/hphinegPi", "", {HistType::kTH1D, {cfgaxisPhi}}); + + registry.add("QAhisto/Lambda/hqaV0radiusbefore", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/Lambda/hqaV0radiusafter", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/Lambda/hqaV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Lambda/hqaV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Lambda/hqadcaV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Lambda/hqadcaV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Lambda/hqadcaPrtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Lambda/hqadcaPrtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Lambda/hqadcaPitoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Lambda/hqadcaPitoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Lambda/hphiposPi", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("QAhisto/Lambda/hphiposPr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("QAhisto/Lambda/hphinegPi", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("QAhisto/Lambda/hphinegPr", "", {HistType::kTH1D, {cfgaxisPhi}}); // Cascade QA registry.add("QAhisto/Xi/hqaCascRadiusbefore", "", {HistType::kTH1D, {{200, -10, 10}}}); registry.add("QAhisto/Xi/hqaCascRadiusafter", "", {HistType::kTH1D, {{200, -10, 10}}}); @@ -446,10 +465,19 @@ struct FlowGfwOmegaXi { registry.add("QAhisto/Xi/hqadcaCascV0toPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); registry.add("QAhisto/Xi/hqadcaCascBachtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); registry.add("QAhisto/Xi/hqadcaCascBachtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascLaprtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascLaprtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascLapitoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascLapitoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); registry.add("QAhisto/Xi/hqadcaCascdaubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); registry.add("QAhisto/Xi/hqadcaCascdauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); registry.add("QAhisto/Xi/hqadcaCascV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); registry.add("QAhisto/Xi/hqadcaCascV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Xi/hTOFnsigmaposPi", "", {HistType::kTH1D, {{1000, -100, 100}}}); + registry.add("QAhisto/Xi/hTOFnsigmaposPr", "", {HistType::kTH1D, {{1000, -100, 100}}}); + registry.add("QAhisto/Xi/hBachTOFnsigmavsPt", "", {HistType::kTH2D, {{1000, -100, 100}, cfgaxisPt}}); + registry.add("QAhisto/Xi/hLaPrTOFnsigmavsPt", "", {HistType::kTH2D, {{1000, -100, 100}, cfgaxisPt}}); + registry.add("QAhisto/Xi/hLaPiTOFnsigmavsPt", "", {HistType::kTH2D, {{1000, -100, 100}, cfgaxisPt}}); registry.add("QAhisto/Omega/hqaCascRadiusbefore", "", {HistType::kTH1D, {{200, -10, 10}}}); registry.add("QAhisto/Omega/hqaCascRadiusafter", "", {HistType::kTH1D, {{200, -10, 10}}}); @@ -461,10 +489,19 @@ struct FlowGfwOmegaXi { registry.add("QAhisto/Omega/hqadcaCascV0toPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); registry.add("QAhisto/Omega/hqadcaCascBachtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); registry.add("QAhisto/Omega/hqadcaCascBachtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascLaprtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascLaprtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascLapitoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascLapitoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); registry.add("QAhisto/Omega/hqadcaCascdaubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); registry.add("QAhisto/Omega/hqadcaCascdauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); registry.add("QAhisto/Omega/hqadcaCascV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); registry.add("QAhisto/Omega/hqadcaCascV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Omega/hTOFnsigmaposPi", "", {HistType::kTH1D, {{1000, -100, 100}}}); + registry.add("QAhisto/Omega/hTOFnsigmaposPr", "", {HistType::kTH1D, {{1000, -100, 100}}}); + registry.add("QAhisto/Omega/hBachTOFnsigmavsPt", "", {HistType::kTH2D, {{1000, -100, 100}, cfgaxisPt}}); + registry.add("QAhisto/Omega/hLaPrTOFnsigmavsPt", "", {HistType::kTH2D, {{1000, -100, 100}, cfgaxisPt}}); + registry.add("QAhisto/Omega/hLaPiTOFnsigmavsPt", "", {HistType::kTH2D, {{1000, -100, 100}, cfgaxisPt}}); } // cumulant of flow @@ -552,8 +589,10 @@ struct FlowGfwOmegaXi { if (cfgOutputV0) { registry.add("InvMassK0s_all", "", {HistType::kTHnSparseF, {cfgaxisPtK0s, axisK0sMass, cfgaxisEta, axisMultiplicity}}); registry.add("InvMassLambda_all", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassALambda_all", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); registry.add("InvMassK0s", "", {HistType::kTHnSparseF, {cfgaxisPtK0s, axisK0sMass, cfgaxisEta, axisMultiplicity}}); registry.add("InvMassLambda", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassALambda", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); } // for local density correction if (cfgOutputLocDenWeights) { @@ -1008,7 +1047,7 @@ struct FlowGfwOmegaXi { return true; } - void processData(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks, soa::Join const& Cascades, aod::V0Datas const& V0s, DaughterTracks const&) + void processData(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks, soa::Join const& Cascades, soa::Join const& V0s, DaughterTracks const&) { o2::aod::ITSResponse itsResponse; int nTot = tracks.size(); @@ -1103,6 +1142,7 @@ struct FlowGfwOmegaXi { // check tpc bool isK0s = false; bool isLambda = false; + bool isALambda = false; if (v0posdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || v0posdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) continue; if (v0negdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || v0negdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) @@ -1110,7 +1150,7 @@ struct FlowGfwOmegaXi { // fill QA if (cfgOutputQA) { - registry.fill(HIST("QAhisto/V0/hqaarm_podobefore"), v0.alpha(), v0.qtarm()); + registry.fill(HIST("QAhisto/K0s/hqaarm_podobefore"), v0.alpha(), v0.qtarm()); } // check daughter ITS, TPC and TOF // K0short @@ -1118,12 +1158,12 @@ struct FlowGfwOmegaXi { if (v0.qtarm() / std::fabs(v0.alpha()) > v0BuilderOpts.cfgv0_ArmPodocut.value && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0BuilderOpts.cfgv0_mk0swindow.value && (std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]) && - ((std::fabs(v0posdau.tofNSigmaPi()) < cfgNSigma[3] || v0posdau.pt() < lowpt) && (std::fabs(v0negdau.tofNSigmaPi()) < cfgNSigma[3] || v0negdau.pt() < lowpt)) && + ((std::fabs(v0.tofNSigmaK0PiPlus()) < cfgNSigma[3] || v0posdau.pt() < lowpt) && (std::fabs(v0.tofNSigmaK0PiMinus()) < cfgNSigma[3] || v0negdau.pt() < lowpt)) && ((std::fabs(itsResponse.nSigmaITS(v0posdau)) < cfgNSigma[6]) || v0posdau.pt() > lowpt) && ((std::fabs(itsResponse.nSigmaITS(v0negdau)) < cfgNSigma[6]) || v0negdau.pt() > lowpt)) { registry.fill(HIST("InvMassK0s_all"), v0.pt(), v0.mK0Short(), v0.eta(), cent); isK0s = true; if (cfgOutputQA) { - registry.fill(HIST("QAhisto/V0/hqaarm_podoafter"), v0.alpha(), v0.qtarm()); + registry.fill(HIST("QAhisto/K0s/hqaarm_podoafter"), v0.alpha(), v0.qtarm()); } } } @@ -1131,27 +1171,44 @@ struct FlowGfwOmegaXi { if (v0.pt() > trkQualityOpts.cfgCutPtLambdaMin.value && v0.pt() < trkQualityOpts.cfgCutPtLambdaMax.value) { if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < v0BuilderOpts.cfgv0_mlambdawindow.value && (std::fabs(v0posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]) && - ((std::fabs(v0posdau.tofNSigmaPr()) < cfgNSigma[4] || v0posdau.pt() < lowpt) && (std::fabs(v0negdau.tofNSigmaPi()) < cfgNSigma[3] || v0negdau.pt() < lowpt)) && + ((std::fabs(v0.tofNSigmaLaPr()) < cfgNSigma[4] || v0posdau.pt() < lowpt) && (std::fabs(v0.tofNSigmaLaPi()) < cfgNSigma[3] || v0negdau.pt() < lowpt)) && ((std::fabs(itsResponse.nSigmaITS(v0posdau)) < cfgNSigma[7]) || v0posdau.pt() > lowpt) && ((std::fabs(itsResponse.nSigmaITS(v0negdau)) < cfgNSigma[6]) || v0negdau.pt() > lowpt)) { registry.fill(HIST("InvMassLambda_all"), v0.pt(), v0.mLambda(), v0.eta(), cent); isLambda = true; - } else if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < v0BuilderOpts.cfgv0_mlambdawindow.value && - (std::fabs(v0negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0]) && - ((std::fabs(v0negdau.tofNSigmaPr()) < cfgNSigma[4] || v0negdau.pt() < lowpt) && (std::fabs(v0posdau.tofNSigmaPi()) < cfgNSigma[3] || v0posdau.pt() < lowpt)) && - ((std::fabs(itsResponse.nSigmaITS(v0posdau)) < cfgNSigma[7]) || v0posdau.pt() > lowpt) && ((std::fabs(itsResponse.nSigmaITS(v0negdau)) < cfgNSigma[6]) || v0negdau.pt() > lowpt)) { - registry.fill(HIST("InvMassLambda_all"), v0.pt(), v0.mLambda(), v0.eta(), cent); - isLambda = true; + } + if (std::fabs(v0.mAntiLambda() - o2::constants::physics::MassLambda) < v0BuilderOpts.cfgv0_mlambdawindow.value && + (std::fabs(v0negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(v0.tofNSigmaALaPr()) < cfgNSigma[4] || v0negdau.pt() < lowpt) && (std::fabs(v0.tofNSigmaALaPi()) < cfgNSigma[3] || v0posdau.pt() < lowpt)) && + ((std::fabs(itsResponse.nSigmaITS(v0negdau)) < cfgNSigma[7]) || v0posdau.pt() > lowpt) && ((std::fabs(itsResponse.nSigmaITS(v0posdau)) < cfgNSigma[6]) || v0negdau.pt() > lowpt)) { + registry.fill(HIST("InvMassALambda_all"), v0.pt(), v0.mAntiLambda(), v0.eta(), cent); + isALambda = true; } } // fill QA before cut if (cfgOutputQA) { - registry.fill(HIST("QAhisto/V0/hqaV0radiusbefore"), v0.v0radius()); - registry.fill(HIST("QAhisto/V0/hqaV0cosPAbefore"), v0.v0cosPA()); - registry.fill(HIST("QAhisto/V0/hqadcaV0daubefore"), v0.dcaV0daughters()); - registry.fill(HIST("QAhisto/V0/hqadcapostoPVbefore"), v0.dcapostopv()); - registry.fill(HIST("QAhisto/V0/hqadcanegtoPVbefore"), v0.dcanegtopv()); + if (isK0s) { + registry.fill(HIST("QAhisto/K0s/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/K0s/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/K0s/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/K0s/hqadcapostoPVbefore"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/K0s/hqadcanegtoPVbefore"), v0.dcanegtopv()); + } + if (isLambda) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVbefore"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVbefore"), v0.dcanegtopv()); + } + if (isALambda) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVbefore"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVbefore"), v0.dcapostopv()); + } } - if (!isK0s && !isLambda) + if (!isK0s && !isLambda && !isALambda) continue; // track quality check if (v0posdau.itsNCls() <= trkQualityOpts.cfgITSNCls.value) @@ -1187,14 +1244,38 @@ struct FlowGfwOmegaXi { isK0s = false; if (isLambda && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0BuilderOpts.cfgv0_compmassrejK0s.value) isLambda = false; + if (isALambda && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0BuilderOpts.cfgv0_compmassrejK0s.value) + isALambda = false; // fill QA after cut if (cfgOutputQA) { - registry.fill(HIST("QAhisto/V0/hqaV0radiusafter"), v0.v0radius()); - registry.fill(HIST("QAhisto/V0/hqaV0cosPAafter"), v0.v0cosPA()); - registry.fill(HIST("QAhisto/V0/hqadcaV0dauafter"), v0.dcaV0daughters()); - registry.fill(HIST("QAhisto/V0/hqadcapostoPVafter"), v0.dcapostopv()); - registry.fill(HIST("QAhisto/V0/hqadcanegtoPVafter"), v0.dcanegtopv()); + if (isK0s) { + registry.fill(HIST("QAhisto/K0s/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/K0s/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/K0s/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/K0s/hqadcapostoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/K0s/hqadcanegtoPVafter"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/K0s/hphiposPi"), v0posdau.phi()); + registry.fill(HIST("QAhisto/K0s/hphinegPi"), v0negdau.phi()); + } + if (isLambda) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVafter"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/Lambda/hphiposPr"), v0posdau.phi()); + registry.fill(HIST("QAhisto/Lambda/hphinegPi"), v0negdau.phi()); + } + if (isALambda) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVafter"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/Lambda/hphiposPi"), v0posdau.phi()); + registry.fill(HIST("QAhisto/Lambda/hphinegPr"), v0negdau.phi()); + } } if (isK0s) { if (cfgDoAccEffCorr) @@ -1225,7 +1306,7 @@ struct FlowGfwOmegaXi { registry.fill(HIST("correction/hRunNumberPhiEtaVertexK0s"), matchedPosition, v0.phi(), v0.eta(), vtxz); } } - if (isLambda) { + if (isLambda || isALambda) { if (cfgDoAccEffCorr) setCurrentParticleWeights(weff, wacc, v0, vtxz, 2); if (cfgDoLocDenCorr) { @@ -1238,10 +1319,16 @@ struct FlowGfwOmegaXi { registry.fill(HIST("MC/densityMCRecLambdaMultTPC"), v0.pt(), nMultTPC, density, v0.mLambda()); } } - registry.fill(HIST("InvMassLambda"), v0.pt(), v0.mLambda(), v0.eta(), cent); + if (isLambda) + registry.fill(HIST("InvMassLambda"), v0.pt(), v0.mLambda(), v0.eta(), cent); + if (isALambda) + registry.fill(HIST("InvMassALambda"), v0.pt(), v0.mAntiLambda(), v0.eta(), cent); registry.fill(HIST("hPhiLambda"), v0.phi()); registry.fill(HIST("hPhiLambdacorr"), v0.phi(), wacc); - fGFW->Fill(v0.eta(), fLambdaPtAxis->FindBin(v0.pt()) - 1 + ((fLambdaMass->FindBin(v0.mLambda()) - 1) * nLambdaPtBins), v0.phi(), wacc * weff * wloc, 16); + if (isLambda) + fGFW->Fill(v0.eta(), fLambdaPtAxis->FindBin(v0.pt()) - 1 + ((fLambdaMass->FindBin(v0.mLambda()) - 1) * nLambdaPtBins), v0.phi(), wacc * weff * wloc, 16); + if (isALambda) + fGFW->Fill(v0.eta(), fLambdaPtAxis->FindBin(v0.pt()) - 1 + ((fLambdaMass->FindBin(v0.mAntiLambda()) - 1) * nLambdaPtBins), v0.phi(), wacc * weff * wloc, 16); if (cfgOutputNUAWeights) fWeightsLambda->fill(v0.phi(), v0.eta(), vtxz, v0.pt(), cent, 0); if (cfgOutputrunbyrun) { @@ -1276,13 +1363,13 @@ struct FlowGfwOmegaXi { if (casc.pt() > trkQualityOpts.cfgCutPtOmegaMin.value && casc.pt() < trkQualityOpts.cfgCutPtOmegaMax.value) { if (casc.sign() < 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]) && - ((std::fabs(casc.tofNSigmaOmKa()) < cfgNSigma[5] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaOmLaPr()) < cfgNSigma[4] || posdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaOmLaPi()) < cfgNSigma[3] || negdau.pt() < dauLaPiPtcut)) && + ((std::fabs(casc.tofNSigmaOmKa()) < cfgNSigma[5] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaOmLaPr()) < cfgNSigma[4] || posdau.pt() < dauLaPrPtcut)) && ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[8]) || bachelor.pt() > bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[7]) || posdau.pt() > dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[6]) || negdau.pt() > dauLaPiPtcut)) { registry.fill(HIST("InvMassOmega_all"), casc.pt(), casc.mOmega(), casc.eta(), cent); isOmega = true; } else if (casc.sign() > 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]) && - ((std::fabs(casc.tofNSigmaOmKa()) < cfgNSigma[5] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaOmLaPr()) < cfgNSigma[4] || negdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaOmLaPi()) < cfgNSigma[3] || posdau.pt() < dauLaPiPtcut)) && + ((std::fabs(casc.tofNSigmaOmKa()) < cfgNSigma[5] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaOmLaPi()) < cfgNSigma[3] || posdau.pt() < dauLaPiPtcut)) && ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[8]) || bachelor.pt() > bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[7]) || negdau.pt() > dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[6]) || posdau.pt() > dauLaPiPtcut)) { registry.fill(HIST("InvMassOmega_all"), casc.pt(), casc.mOmega(), casc.eta(), cent); isOmega = true; @@ -1292,13 +1379,13 @@ struct FlowGfwOmegaXi { if (casc.pt() > trkQualityOpts.cfgCutPtXiMin.value && casc.pt() < trkQualityOpts.cfgCutPtXiMax.value) { if (casc.sign() < 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]) && - ((std::fabs(casc.tofNSigmaXiPi()) < cfgNSigma[3] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaXiLaPr()) < cfgNSigma[4] || posdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaXiLaPi()) < cfgNSigma[3] || negdau.pt() < dauLaPiPtcut)) && + ((std::fabs(casc.tofNSigmaXiPi()) < cfgNSigma[3] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaXiLaPr()) < cfgNSigma[4] || posdau.pt() < dauLaPrPtcut)) && ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[6]) || bachelor.pt() > bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[7]) || posdau.pt() > dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[6]) || negdau.pt() > dauLaPiPtcut)) { registry.fill(HIST("InvMassXi_all"), casc.pt(), casc.mXi(), casc.eta(), cent); isXi = true; } else if (casc.sign() > 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]) && - ((std::fabs(casc.tofNSigmaXiPi()) < cfgNSigma[3] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaXiLaPr()) < cfgNSigma[4] || negdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaXiLaPi()) < cfgNSigma[3] || posdau.pt() < dauLaPiPtcut)) && + ((std::fabs(casc.tofNSigmaXiPi()) < cfgNSigma[3] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaXiLaPi()) < cfgNSigma[3] || posdau.pt() < dauLaPiPtcut)) && ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[6]) || bachelor.pt() > bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[7]) || negdau.pt() > dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[6]) || posdau.pt() > dauLaPiPtcut)) { registry.fill(HIST("InvMassXi_all"), casc.pt(), casc.mXi(), casc.eta(), cent); isXi = true; @@ -1314,6 +1401,19 @@ struct FlowGfwOmegaXi { registry.fill(HIST("QAhisto/Xi/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); registry.fill(HIST("QAhisto/Xi/hqadcaCascdaubefore"), casc.dcacascdaughters()); registry.fill(HIST("QAhisto/Xi/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + if (casc.sign() > 0) { + registry.fill(HIST("QAhisto/Xi/hqadcaCascLaprtoPVbefore"), casc.dcapostopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascLapitoPVbefore"), casc.dcanegtopv()); + registry.fill(HIST("QAhisto/Xi/hTOFnsigmaposPi"), casc.tofNSigmaXiLaPi()); + registry.fill(HIST("QAhisto/Xi/hBachTOFnsigmavsPt"), casc.tofNSigmaXiPi(), bachelor.pt()); + registry.fill(HIST("QAhisto/Xi/hLaPiTOFnsigmavsPt"), casc.tofNSigmaXiLaPi(), posdau.pt()); + } else { + registry.fill(HIST("QAhisto/Xi/hqadcaCascLaprtoPVbefore"), casc.dcanegtopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascLapitoPVbefore"), casc.dcapostopv()); + registry.fill(HIST("QAhisto/Xi/hTOFnsigmaposPr"), casc.tofNSigmaXiLaPr()); + registry.fill(HIST("QAhisto/Xi/hBachTOFnsigmavsPt"), casc.tofNSigmaXiPi(), bachelor.pt()); + registry.fill(HIST("QAhisto/Xi/hLaPrTOFnsigmavsPt"), casc.tofNSigmaXiLaPr(), posdau.pt()); + } } if (isOmega) { registry.fill(HIST("QAhisto/Omega/hqaCascRadiusbefore"), casc.cascradius()); @@ -1323,6 +1423,19 @@ struct FlowGfwOmegaXi { registry.fill(HIST("QAhisto/Omega/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); registry.fill(HIST("QAhisto/Omega/hqadcaCascdaubefore"), casc.dcacascdaughters()); registry.fill(HIST("QAhisto/Omega/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + if (casc.sign() > 0) { + registry.fill(HIST("QAhisto/Omega/hqadcaCascLaprtoPVbefore"), casc.dcapostopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascLapitoPVbefore"), casc.dcanegtopv()); + registry.fill(HIST("QAhisto/Omega/hTOFnsigmaposPi"), casc.tofNSigmaXiLaPi()); + registry.fill(HIST("QAhisto/Omega/hBachTOFnsigmavsPt"), casc.tofNSigmaXiPi(), bachelor.pt()); + registry.fill(HIST("QAhisto/Omega/hLaPiTOFnsigmavsPt"), casc.tofNSigmaXiLaPi(), posdau.pt()); + } else { + registry.fill(HIST("QAhisto/Omega/hqadcaCascLaprtoPVbefore"), casc.dcanegtopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascLapitoPVbefore"), casc.dcapostopv()); + registry.fill(HIST("QAhisto/Omega/hTOFnsigmaposPr"), casc.tofNSigmaXiLaPr()); + registry.fill(HIST("QAhisto/Omega/hBachTOFnsigmavsPt"), casc.tofNSigmaXiPi(), bachelor.pt()); + registry.fill(HIST("QAhisto/Omega/hLaPrTOFnsigmavsPt"), casc.tofNSigmaXiLaPr(), posdau.pt()); + } } } @@ -1339,6 +1452,17 @@ struct FlowGfwOmegaXi { continue; if (std::fabs(casc.dcabachtopv()) < cascBuilderOpts.cfgcasc_dcabachtopv.value) continue; + if (casc.sign() > 0) { + if (std::fabs(casc.dcapostopv()) < cascBuilderOpts.cfgcasc_dcaLaprtopv.value) + continue; + if (std::fabs(casc.dcanegtopv()) < cascBuilderOpts.cfgcasc_dcaLapitopv.value) + continue; + } else { + if (std::fabs(casc.dcanegtopv()) < cascBuilderOpts.cfgcasc_dcaLaprtopv.value) + continue; + if (std::fabs(casc.dcapostopv()) < cascBuilderOpts.cfgcasc_dcaLapitopv.value) + continue; + } if (casc.dcacascdaughters() > cascBuilderOpts.cfgcasc_dcacascdau.value) continue; if (casc.dcaV0daughters() > cascBuilderOpts.cfgcasc_dcav0dau.value) @@ -1388,6 +1512,13 @@ struct FlowGfwOmegaXi { registry.fill(HIST("QAhisto/Xi/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); registry.fill(HIST("QAhisto/Xi/hqadcaCascdauafter"), casc.dcacascdaughters()); registry.fill(HIST("QAhisto/Xi/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + if (casc.sign() > 0) { + registry.fill(HIST("QAhisto/Xi/hqadcaCascLaprtoPVafter"), casc.dcapostopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascLapitoPVafter"), casc.dcanegtopv()); + } else { + registry.fill(HIST("QAhisto/Xi/hqadcaCascLaprtoPVafter"), casc.dcanegtopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascLapitoPVafter"), casc.dcapostopv()); + } } if (isOmega) { registry.fill(HIST("QAhisto/Omega/hqaCascRadiusafter"), casc.cascradius()); @@ -1397,6 +1528,13 @@ struct FlowGfwOmegaXi { registry.fill(HIST("QAhisto/Omega/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); registry.fill(HIST("QAhisto/Omega/hqadcaCascdauafter"), casc.dcacascdaughters()); registry.fill(HIST("QAhisto/Omega/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + if (casc.sign() > 0) { + registry.fill(HIST("QAhisto/Omega/hqadcaCascLaprtoPVafter"), casc.dcapostopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascLapitoPVafter"), casc.dcanegtopv()); + } else { + registry.fill(HIST("QAhisto/Omega/hqadcaCascLaprtoPVafter"), casc.dcanegtopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascLapitoPVafter"), casc.dcapostopv()); + } } } @@ -1926,6 +2064,7 @@ struct FlowGfwOmegaXi { auto v0MC = v0.mcParticle_as(); auto v0negdau = v0.negTrack_as(); auto v0posdau = v0.posTrack_as(); + int pdgCode{v0MC.pdgCode()}; if (v0posdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || v0posdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) continue; @@ -1934,12 +2073,27 @@ struct FlowGfwOmegaXi { // fill QA before cut if (cfgOutputQA) { - registry.fill(HIST("QAhisto/V0/hqaV0radiusbefore"), v0.v0radius()); - registry.fill(HIST("QAhisto/V0/hqaV0cosPAbefore"), v0.v0cosPA()); - registry.fill(HIST("QAhisto/V0/hqadcaV0daubefore"), v0.dcaV0daughters()); - registry.fill(HIST("QAhisto/V0/hqadcapostoPVbefore"), v0.dcapostopv()); - registry.fill(HIST("QAhisto/V0/hqadcanegtoPVbefore"), v0.dcanegtopv()); - registry.fill(HIST("QAhisto/V0/hqaarm_podobefore"), v0.alpha(), v0.qtarm()); + if (pdgCode == kK0Short) { + registry.fill(HIST("QAhisto/K0s/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/K0s/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/K0s/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/K0s/hqadcapostoPVbefore"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/K0s/hqadcanegtoPVbefore"), v0.dcanegtopv()); + } + if (pdgCode == kLambda0) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVbefore"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVbefore"), v0.dcanegtopv()); + } + if (pdgCode == kLambda0Bar) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVbefore"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVbefore"), v0.dcapostopv()); + } } // // track quality check if (v0posdau.itsNCls() <= trkQualityOpts.cfgITSNCls.value) @@ -1973,14 +2127,29 @@ struct FlowGfwOmegaXi { continue; // fill QA after cut if (cfgOutputQA) { - registry.fill(HIST("QAhisto/V0/hqaV0radiusafter"), v0.v0radius()); - registry.fill(HIST("QAhisto/V0/hqaV0cosPAafter"), v0.v0cosPA()); - registry.fill(HIST("QAhisto/V0/hqadcaV0dauafter"), v0.dcaV0daughters()); - registry.fill(HIST("QAhisto/V0/hqadcapostoPVafter"), v0.dcapostopv()); - registry.fill(HIST("QAhisto/V0/hqadcanegtoPVafter"), v0.dcanegtopv()); + if (pdgCode == kK0Short) { + registry.fill(HIST("QAhisto/K0s/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/K0s/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/K0s/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/K0s/hqadcapostoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/K0s/hqadcanegtoPVafter"), v0.dcanegtopv()); + } + if (pdgCode == kLambda0) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVafter"), v0.dcanegtopv()); + } + if (pdgCode == kLambda0Bar) { + registry.fill(HIST("QAhisto/Lambda/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/Lambda/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/Lambda/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPrtoPVafter"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/Lambda/hqadcaPitoPVafter"), v0.dcapostopv()); + } } - int pdgCode{v0MC.pdgCode()}; double v0Pt{v0MC.pt()}; double v0Phi{v0MC.phi()}; double v0Eta{v0MC.eta()}; diff --git a/PWGCF/Flow/Tasks/flowGfwTask.cxx b/PWGCF/Flow/Tasks/flowGfwTask.cxx index de1c2989a2c..e0c6616828d 100644 --- a/PWGCF/Flow/Tasks/flowGfwTask.cxx +++ b/PWGCF/Flow/Tasks/flowGfwTask.cxx @@ -82,7 +82,7 @@ struct FlowGfwTask { O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "Custom DCA Z cut") O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 1.0f, "Custom DCA XY cut") O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") - O2_DEFINE_CONFIGURABLE(cfgCentEstFt0c, bool, false, "Centrality estimator based on FT0C signal") + O2_DEFINE_CONFIGURABLE(cfgCentEstFt0c, bool, true, "Centrality estimator based on FT0C signal") O2_DEFINE_CONFIGURABLE(cfgCentEstFt0a, bool, false, "Centrality estimator based on FT0A signal") O2_DEFINE_CONFIGURABLE(cfgCentEstFt0m, bool, false, " A centrality estimator based on FT0A+FT0C signals.") O2_DEFINE_CONFIGURABLE(cfgCentEstFv0a, bool, false, "Centrality estimator based on FV0A signal") @@ -93,20 +93,20 @@ struct FlowGfwTask { O2_DEFINE_CONFIGURABLE(cfgMagnetField, std::string, "GLO/Config/GRPMagField", "CCDB path to Magnet field object") O2_DEFINE_CONFIGURABLE(cfgDCAzPt, bool, false, "switch for DCAz pt dependent") O2_DEFINE_CONFIGURABLE(cfgTrackSelRun3ITSMatch, bool, false, "Track selection for ITS matches") - O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") - O2_DEFINE_CONFIGURABLE(cfgUseAdditionalTrackCut, bool, false, "Use additional track cut on phi") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, true, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalTrackCut, bool, true, "Use additional track cut on phi") O2_DEFINE_CONFIGURABLE(cfgOccupancy, bool, false, "Bool for event selection on detector occupancy"); O2_DEFINE_CONFIGURABLE(cfgNoTimeFrameBorder, bool, false, "kNoTimeFrameBorder"); O2_DEFINE_CONFIGURABLE(cfgNoITSROFrameBorder, bool, false, "kNoITSROFrameBorder"); O2_DEFINE_CONFIGURABLE(cfgNoSameBunchPileup, bool, false, "kNoSameBunchPileup"); O2_DEFINE_CONFIGURABLE(cfgIsGoodZvtxFT0vsPV, bool, false, "kIsGoodZvtxFT0vsPV"); - O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, false, "kIsVertexITSTPC"); + O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, true, "kIsVertexITSTPC"); O2_DEFINE_CONFIGURABLE(cfgNoCollInTimeRangeStandard, bool, false, "kNoCollInTimeRangeStandard"); O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayersAll, bool, false, "kIsGoodITSLayersAll") O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, false, "Use additional event cut on mult correlations"); O2_DEFINE_CONFIGURABLE(cfgV0AT0ANSigma, bool, false, "V0A T0A n sigma cut") O2_DEFINE_CONFIGURABLE(cfgNSigma, float, 5.0f, "N sigma cut") - O2_DEFINE_CONFIGURABLE(cfgGlobalTracks, bool, false, "Global tracks") + O2_DEFINE_CONFIGURABLE(cfgGlobalTracks, bool, true, "Global tracks") O2_DEFINE_CONFIGURABLE(cfgGlobalplusITS, bool, false, "Global and ITS tracks") O2_DEFINE_CONFIGURABLE(cfgGlobalonly, bool, false, "Global only tracks") O2_DEFINE_CONFIGURABLE(cfgITSonly, bool, false, "ITS only tracks") @@ -894,9 +894,15 @@ struct FlowGfwTask { } } - // Apply process filters GlobalTracks + // Apply process filters Global+ITS_only sample Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex && (aod::cent::centFT0C > cfgMinCentFT0C) && (aod::cent::centFT0C < cfgMaxCentFT0C); - Filter trackFilter = ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::dcaXY) < cfgCutDCAxy); + Filter trackFilter = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionITS) && + ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), + ncheckbit(aod::track::trackCutFlag, TrackSelectionTPC), true) && + ifnode(dcaZ > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDCAXYonly), + ncheckbit(aod::track::trackCutFlag, TrackSelectionDCA)) && + (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::dcaXY) < cfgCutDCAxy); void processData(Colls::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks, aod::FT0s const&, BCsRun3 const&) { @@ -1239,7 +1245,7 @@ struct FlowGfwTask { } } // End of process - PROCESS_SWITCH(FlowGfwTask, processData, "Process analysis for Run 3 data", false); + PROCESS_SWITCH(FlowGfwTask, processData, "Process analysis for Run 3 data", true); using TheFilteredMyTracks = soa::Filtered; using TheFilteredMyCollisions = soa::Filtered; diff --git a/PWGCF/Flow/Tasks/flowTask.cxx b/PWGCF/Flow/Tasks/flowTask.cxx index 3e3fbb181dc..53b84b5f849 100644 --- a/PWGCF/Flow/Tasks/flowTask.cxx +++ b/PWGCF/Flow/Tasks/flowTask.cxx @@ -192,6 +192,7 @@ struct FlowTask { // for deltaPt/ vs centrality O2_DEFINE_CONFIGURABLE(cfgDptDisEnable, bool, false, "Produce deltaPt/meanPt vs centrality") O2_DEFINE_CONFIGURABLE(cfgDptDisSelectionSwitch, int, 0, "0: disable, 1: use low cut, 2:use high cut") + O2_DEFINE_CONFIGURABLE(cfgDptDisEtaGapQA, float, 0.5, "QA plot for pT dis in eta gap") TH1D* hEvAvgMeanPt = nullptr; TH1D* fDptDisCutLow = nullptr; TH1D* fDptDisCutHigh = nullptr; @@ -361,6 +362,7 @@ struct FlowTask { registry.add("centFT0CVar_centFT0C", "after cut;Centrality T0C;Centrality T0C Var", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); registry.add("centFT0M_centFT0C", "after cut;Centrality T0C;Centrality T0M", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); registry.add("centFV0A_centFT0C", "after cut;Centrality T0C;Centrality V0A", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + registry.add("hEtaPtCent", "after cut;#eta;p_{T};Centrality;", {HistType::kTH3D, {{16, -0.8, 0.8}, axisPt, {10, 0, 100}}}); } // Track QA registry.add("hPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); @@ -396,6 +398,8 @@ struct FlowTask { registry.add("hNormDeltaPt_X", "; #delta p_{T}/[p_{T}]; X", {HistType::kTH2D, {cfgAdditionObs.cfgDptDisAxisNormal, axisIndependent}}); registry.add("hNormDeltaPt_X_afterCut", "; #delta p_{T}/[p_{T}]; X", {HistType::kTH2D, {cfgAdditionObs.cfgDptDisAxisNormal, axisIndependent}}); registry.add("hPt_afterDptCut", "p_{T} distribution", {HistType::kTH1D, {axisPt}}); + registry.add("hPtA_afterDptCut", "p_{T} distribution", {HistType::kTH1D, {axisPt}}); + registry.add("hPtB_afterDptCut", "p_{T} distribution", {HistType::kTH1D, {axisPt}}); } if (doprocessMCGen) { registry.add("MCGen/MChPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); @@ -1224,7 +1228,7 @@ struct FlowTask { std::vector consistentEventVector = cfgUserIO.cfgConsistentEventVector; if (cfgUserIO.cfgConsistentEventFlag) LOGF(info, "consistentEventVector.size = %u", consistentEventVector.size()); - std::vector ptVec; + std::vector> ptEtaVec; double psi2Est = 0, psi3Est = 0, psi4Est = 0; float wEPeff = 1; @@ -1294,7 +1298,10 @@ struct FlowTask { } registry.fill(HIST("hPt"), track.pt()); if (cfgAdditionObs.cfgDptDisEnable) - ptVec.push_back(track.pt()); + ptEtaVec.push_back({track.pt(), track.eta()}); + if (!cfgUserIO.cfgUseSmallMemory) { + registry.fill(HIST("hEtaPtCent"), track.eta(), track.pt(), cent); + } if (cfgAdditionObs.cfgV02Enabled && track.eta() >= cfgAdditionObs.cfgV02FracEtaMin && track.eta() <= cfgAdditionObs.cfgV02FracEtaMax) { cfgAdditionObs.listPtX[0]->Fill(independent, track.pt(), weff); cfgAdditionObs.listPtX[sampleIndex + 1]->Fill(independent, track.pt(), weff); @@ -1379,9 +1386,14 @@ struct FlowTask { return; } registry.fill(HIST("hNormDeltaPt_X_afterCut"), normDeltaPt, independent, weffEvent); - if (ptVec.size() > 0) { - for (auto trpt : ptVec) - registry.fill(HIST("hPt_afterDptCut"), trpt); + if (ptEtaVec.size() > 0) { + for (auto trptEta : ptEtaVec) { + registry.fill(HIST("hPt_afterDptCut"), trptEta.first); + if (trptEta.second < -1. * cfgAdditionObs.cfgDptDisEtaGapQA) + registry.fill(HIST("hPtA_afterDptCut"), trptEta.first); + if (trptEta.second > cfgAdditionObs.cfgDptDisEtaGapQA) + registry.fill(HIST("hPtB_afterDptCut"), trptEta.first); + } } } diff --git a/PWGCF/Flow/Tasks/flowZdcEnergy.cxx b/PWGCF/Flow/Tasks/flowZdcEnergy.cxx new file mode 100644 index 00000000000..f812b999c33 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowZdcEnergy.cxx @@ -0,0 +1,232 @@ +// 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 flowZdcEnergy.cxx +/// \author Kegang Xiong +/// \since 03/2026 +/// \brief Study ZDC energy observables versus centrality for Run 2 / Run 3. + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct flowZdcEnergy { + + struct : ConfigurableGroup{ + O2_DEFINE_CONFIGURABLE(cfgCentMin, float, 0.f, "Minimum centrality for selected events") + O2_DEFINE_CONFIGURABLE(cfgCentMax, float, 90.f, "Maximum centrality for selected events") + O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10.f, "Accepted z-vertex range")} evsel; + + ConfigurableAxis axisCent{"axisCent", {90, 0, 90}, "Centrality (%)"}; + ConfigurableAxis axisMult{"axisMult", {100, 0, 100000}, "Multiplicity"}; + ConfigurableAxis axisEnergy{"axisEnergy", {300, 0, 300}, "Energy"}; + ConfigurableAxis axisRescaledDiff{"axisRescaledDiff", {400, -1, 1}, "(EA-EC)/(EA+EC)"}; + + // Event counter bins + enum SelectionCriteria : uint8_t { + kAllEvents = 0, + kSeln, + kZvtx, + kCentrality, + kBCHasZDC, + kSelectedZDC, + kNSelections + }; + + Service ccdb; + HistogramRegistry registry{"registry"}; + + // Run 3 + using CollisionsRun3 = soa::Join; + using BCsRun3 = soa::Join; + // Run 2 + using CollisionsRun2 = soa::Join; + using BCsRun2 = soa::Join; + + void init(InitContext const&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + auto now = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + ccdb->setCreatedNotAfter(now); + + registry.add("hEventCount", "Event counter;Selection;Events", {HistType::kTH1D, {{kNSelections, 0, kNSelections}}}); + auto hCount = registry.get(HIST("hEventCount")); + hCount->GetXaxis()->SetBinLabel(kAllEvents + 1, "All events"); + hCount->GetXaxis()->SetBinLabel(kSeln + 1, "Sel7/8"); + hCount->GetXaxis()->SetBinLabel(kZvtx + 1, "Zvtx"); + hCount->GetXaxis()->SetBinLabel(kCentrality + 1, "Centrality"); + hCount->GetXaxis()->SetBinLabel(kBCHasZDC + 1, "BC has ZDC"); + hCount->GetXaxis()->SetBinLabel(kSelectedZDC + 1, "Selected ZDC"); + + registry.add("hCentrality", "", {HistType::kTH1D, {axisCent}}); + registry.add("hMultiplicity", "", {HistType::kTH1D, {axisMult}}); + + registry.add("hEnergyWithCent_ZNA_Common", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNC_Common", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_RescaledDiff", "", {HistType::kTH2D, {axisRescaledDiff, axisCent}}); + registry.add("hEnergyWithCent_ZNA_1", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNA_2", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNA_3", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNA_4", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNC_1", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNC_2", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNC_3", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNC_4", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNA_SumSectors", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_ZNC_SumSectors", "", {HistType::kTH2D, {axisEnergy, axisCent}}); + registry.add("hEnergyWithCent_RescaledSumDiff", "", {HistType::kTH2D, {axisRescaledDiff, axisCent}}); + } + + // Helper: event selection + template + bool acceptEvent(TCollision const& collision, float centrality, const int runmode) + { + registry.fill(HIST("hEventCount"), kAllEvents); + + if (runmode == 2 && !collision.sel7()) { + return false; + } + if (runmode == 3 && !collision.sel8()) { + return false; + } + registry.fill(HIST("hEventCount"), kSeln); + + if (std::abs(collision.posZ()) > evsel.cfgVtxZ) { + return false; + } + registry.fill(HIST("hEventCount"), kZvtx); + + if (centrality < evsel.cfgCentMin || centrality > evsel.cfgCentMax) { + return false; + } + registry.fill(HIST("hEventCount"), kCentrality); + + return true; + } + + // Helper: fill ZDC observables + template + void fillZDCObservables(TCollision const& collision, float centrality) + { + const auto& foundBC = collision.template foundBC_as(); + if (!foundBC.has_zdc()) { + return; + } + registry.fill(HIST("hEventCount"), kBCHasZDC); + + const auto& zdc = foundBC.zdc(); + if (zdc.energyCommonZNA() <= 1.f || zdc.energyCommonZNC() <= 1.f) { + return; + } + registry.fill(HIST("hEventCount"), kSelectedZDC); + + const float energyCommonZNA = zdc.energyCommonZNA(); + const float energyCommonZNC = zdc.energyCommonZNC(); + const float energySectorZNA1 = zdc.energySectorZNA()[0]; + const float energySectorZNA2 = zdc.energySectorZNA()[1]; + const float energySectorZNA3 = zdc.energySectorZNA()[2]; + const float energySectorZNA4 = zdc.energySectorZNA()[3]; + const float energySectorZNC1 = zdc.energySectorZNC()[0]; + const float energySectorZNC2 = zdc.energySectorZNC()[1]; + const float energySectorZNC3 = zdc.energySectorZNC()[2]; + const float energySectorZNC4 = zdc.energySectorZNC()[3]; + + const float sumEnergyZNA = energySectorZNA1 + energySectorZNA2 + energySectorZNA3 + energySectorZNA4; + const float sumEnergyZNC = energySectorZNC1 + energySectorZNC2 + energySectorZNC3 + energySectorZNC4; + + const float commonDen = energyCommonZNA + energyCommonZNC; + const float sumDen = sumEnergyZNA + sumEnergyZNC; + + registry.fill(HIST("hEnergyWithCent_ZNA_Common"), energyCommonZNA, centrality); + registry.fill(HIST("hEnergyWithCent_ZNC_Common"), energyCommonZNC, centrality); + registry.fill(HIST("hEnergyWithCent_ZNA_1"), energySectorZNA1, centrality); + registry.fill(HIST("hEnergyWithCent_ZNA_2"), energySectorZNA2, centrality); + registry.fill(HIST("hEnergyWithCent_ZNA_3"), energySectorZNA3, centrality); + registry.fill(HIST("hEnergyWithCent_ZNA_4"), energySectorZNA4, centrality); + registry.fill(HIST("hEnergyWithCent_ZNC_1"), energySectorZNC1, centrality); + registry.fill(HIST("hEnergyWithCent_ZNC_2"), energySectorZNC2, centrality); + registry.fill(HIST("hEnergyWithCent_ZNC_3"), energySectorZNC3, centrality); + registry.fill(HIST("hEnergyWithCent_ZNC_4"), energySectorZNC4, centrality); + registry.fill(HIST("hEnergyWithCent_ZNA_SumSectors"), sumEnergyZNA, centrality); + registry.fill(HIST("hEnergyWithCent_ZNC_SumSectors"), sumEnergyZNC, centrality); + + if (commonDen > 1.e-6f) { + registry.fill(HIST("hEnergyWithCent_RescaledDiff"), (energyCommonZNA - energyCommonZNC) / commonDen, centrality); + } + if (sumDen > 1.e-6f) { + registry.fill(HIST("hEnergyWithCent_RescaledSumDiff"), (sumEnergyZNA - sumEnergyZNC) / sumDen, centrality); + } + } + + // Run 3 process + void processRun3(CollisionsRun3::iterator const& collision, + BCsRun3 const&, + aod::Zdcs const&) + { + const float centrality = collision.centFT0C(); + const float multi = collision.multFT0C(); + + if (!acceptEvent(collision, centrality, 3)) { + return; + } + registry.fill(HIST("hCentrality"), centrality); + registry.fill(HIST("hMultiplicity"), multi); + + fillZDCObservables(collision, centrality); + } + + // Run 2 process + void processRun2(CollisionsRun2::iterator const& collision, + BCsRun2 const&, + aod::Zdcs const&) + { + const float centrality = collision.centRun2V0M(); + const float multi = collision.multFV0M(); + + if (!acceptEvent(collision, centrality, 2)) { + return; + } + registry.fill(HIST("hCentrality"), centrality); + registry.fill(HIST("hMultiplicity"), multi); + + fillZDCObservables(collision, centrality); + } + + // Process switches + PROCESS_SWITCH(flowZdcEnergy, processRun3, "Process Run 3 data", true); + PROCESS_SWITCH(flowZdcEnergy, processRun2, "Process Run 2 data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowZdcTask.cxx b/PWGCF/Flow/Tasks/flowZdcTask.cxx index 5bfa4c09495..a0a424172dd 100644 --- a/PWGCF/Flow/Tasks/flowZdcTask.cxx +++ b/PWGCF/Flow/Tasks/flowZdcTask.cxx @@ -66,6 +66,7 @@ struct FlowZdcTask { Configurable minNch{"minNch", 0, "Min Nch (|eta|<0.8)"}; Configurable maxNch{"maxNch", 2500, "Max Nch (|eta|<0.8)"}; Configurable nBinsTDC{"nBinsTDC", 150, "nbinsTDC"}; + Configurable nBinsCent{"nBinsCent", 10, "nBinsCent"}; Configurable minTdcZn{"minTdcZn", 4.0, "minimum TDC for ZN"}; Configurable maxTdcZn{"maxTdcZn", 4.0, "maximum TDC for ZN"}; Configurable minTdcZp{"minTdcZp", -4.0, "minimum TDC for ZP"}; @@ -80,6 +81,7 @@ struct FlowZdcTask { Configurable maxEta{"maxEta", +0.8, "maximum eta"}; Configurable minT0CcentCut{"minT0CcentCut", 0.0, "Min T0C Cent. cut"}; Configurable maxT0CcentCut{"maxT0CcentCut", 90.0, "Max T0C Cent. cut"}; + Configurable maxCent{"maxCent", 90.0, "Max T0C cent"}; // event selection Configurable isNoCollInTimeRangeStrict{"isNoCollInTimeRangeStrict", true, "isNoCollInTimeRangeStrict?"}; Configurable isNoCollInTimeRangeStandard{"isNoCollInTimeRangeStandard", false, "isNoCollInTimeRangeStandard?"}; @@ -198,24 +200,28 @@ struct FlowZdcTask { histos.add("ZNVsFT0C", ";T0C (#times 1/100);ZNA+ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZNVsFT0M", ";T0A+T0C (#times 1/100);ZNA+ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); histos.add("CommonZNVsFT0M", ";T0A+T0C (#times 1/100);ZNA+ZNC Common Energy;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); - histos.add("SectorZNVsFT0M", ";T0A+T0C (#times 1/100);ZNA+ZNC Sector Energy;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNVsCent", ";T0C cent;ZNA + ZNC Amplitude;", kTH2F, {{{nBinsCent, 0., maxCent}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZPVsFT0A", ";T0A (#times 1/100);ZPA+ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZPVsFT0C", ";T0C (#times 1/100);ZPA+ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZPVsFT0M", ";T0A+T0C (#times 1/100);ZPA+ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPVsCent", ";T0C cent;ZPA + ZPC Amplitude;", kTH2F, {{{nBinsCent, 0., maxCent}, {nBinsZDC, -0.5, maxZp}}}); histos.add("CommonZPVsFT0M", ";T0A+T0C (#times 1/100);ZPA+ZPC Common Energy;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); - histos.add("SectorZPVsFT0M", ";T0A+T0C (#times 1/100);ZPA+ZPC Sector Energy;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZNAVsFT0A", ";T0A (#times 1/100);ZNA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZNAVsFT0C", ";T0C (#times 1/100);ZNA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNAVsCent", ";T0C cent;ZNA Amplitude;", kTH2F, {{{nBinsCent, 0., maxCent}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZNAVsFT0M", ";T0A+T0C (#times 1/100);ZNA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZNCVsFT0A", ";T0A (#times 1/100);ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZNCVsFT0C", ";T0C (#times 1/100);ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZNCVsFT0M", ";T0A+T0C (#times 1/100);ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNCVsCent", ";T0C cent;ZNC Amplitude;", kTH2F, {{{nBinsCent, 0., maxCent}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZPAVsFT0A", ";T0A (#times 1/100);ZPA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZPAVsFT0C", ";T0C (#times 1/100);ZPA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZPAVsFT0M", ";T0A+T0C (#times 1/100);ZPA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPAVsCent", ";T0C cent;ZPA Amplitude;", kTH2F, {{{nBinsCent, 0., maxCent}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZPCVsFT0A", ";T0A (#times 1/100);ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZPCVsFT0C", ";T0C (#times 1/100);ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZPCVsFT0M", ";T0A+T0C (#times 1/100);ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPCVsCent", ";T0C cent;ZPC Amplitude;", kTH2F, {{{nBinsCent, 0., maxCent}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZN", ";ZNA+ZNC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); histos.add("ZNA", ";ZNA Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); histos.add("ZPA", ";ZPA Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); @@ -233,10 +239,6 @@ struct FlowZdcTask { histos.add("CommonZPAVsZPC", ";Common ZPC;Common ZPA;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZp}}}); histos.add("CommonZNAVsZPA", ";Common ZPA;Common ZNA;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZn}}}); histos.add("CommonZNCVsZPC", ";Common ZPC;Common ZNC;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZn}}}); - histos.add("ZNASector", ";ZNA;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); - histos.add("ZPASector", ";ZPA;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); - histos.add("ZNCSector", ";ZNC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); - histos.add("ZPCSector", ";ZPC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); histos.add("ZNCcvsZNCsum", ";ZNC common;ZNC sum towers;", kTH2F, {{{30, -0.5, maxZn}, {30, -0.5, maxZn}}}); histos.add("ZNAcvsZNAsum", ";ZNA common;ZNA sum towers;", kTH2F, {{{30, -0.5, maxZn}, {30, -0.5, maxZn}}}); histos.add("ZPCcvsZPCsum", ";ZPC common;ZPC sum towers;", kTH2F, {{{30, -0.5, maxZp}, {30, -0.5, maxZp}}}); @@ -266,8 +268,10 @@ struct FlowZdcTask { histos.add("NchVsITStracks", ";ITS tracks nCls >= 5;TITS+TPC tracks (|#eta|<0.8);", kTH2F, {{{300, -0.5, 5999.5}, {nBinsNch, minNch, maxNch}}}); histos.add("ZNCVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); histos.add("ZNAVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); + histos.add("ZPAVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZPA;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZp}}}); + histos.add("ZPCVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZPA;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZp}}}); histos.add("ZNVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA+ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); - histos.add("ZNDifVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA-ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {100, -50., 50.}}}); + histos.add("ZPVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZPA+ZPC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZp}}}); } if (doprocessZdc) { histos.add("ampZna", ";ZNA Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); @@ -278,10 +282,6 @@ struct FlowZdcTask { histos.add("commonZpa", ";ZPA Common;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); histos.add("commonZnc", ";ZNC Common;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); histos.add("commonZpc", ";ZPC Common;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); - histos.add("sectorSumZna", ";ZNA Sector Sum;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); - histos.add("sectorSumZnc", ";ZNC Sector Sum;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); - histos.add("sectorSumZpa", ";ZPA Sector Sum;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); - histos.add("sectorSumZpc", ";ZPC Sector Sum;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); histos.add("ampZEM1", ";ZEM1 Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZem}}); histos.add("ampZEM2", ";ZEM2 Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZem}}); histos.add("ZnVsZem", "ZnVsZEM; ZEM; ZNA + ZNC", kTH2F, {{{nBinsZDC, -0.5, maxZem}, {nBinsZDC, -0.5, maxZn}}}); @@ -289,10 +289,6 @@ struct FlowZdcTask { histos.add("ZpaVsZpc", "ZPAvsZPC; ZPC; ZPA;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZnaVsZpa", "ZNAvsZPA; ZNA; ZPA;", kTH2F, {{{nBinsZDC, -0.5, maxZn}, {nBinsZDC, -0.5, maxZp}}}); histos.add("ZncVsZpc", "ZNCvsZPC; ZNC; ZPC;", kTH2F, {{{nBinsZDC, -0.5, maxZn}, {nBinsZDC, -0.5, maxZp}}}); - histos.add("ZnccVsZncSum", "ZNCcVsZNCsum; ZNCC ADC; ZNCsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZn}, {nBinsADC, -0.5, 3. * maxZn}}}); - histos.add("ZnacVsZnaSum", "ZNAcVsZNAsum; ZNAC ADC; ZNAsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZn}, {nBinsADC, -0.5, 3. * maxZn}}}); - histos.add("ZpacVsZpaSum", "ZPAcVsZPAsum; ZPAC ADC; ZPAsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZp}, {nBinsADC, -0.5, 3. * maxZp}}}); - histos.add("ZpccVsZpcSum", "ZPCcVsZPCsum; ZPCC ADC; ZPCsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZp}, {nBinsADC, -0.5, 3. * maxZp}}}); histos.add("ZncVsTdc", "ZNCvsTDC; ZNC Amp; ZNC TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZnaVsTdc", "ZNAvsTDC; ZNA Amp; ZNA TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZn}}}); histos.add("ZpcVsTdc", "ZPCvsTDC; ZPC Amp; ZPC TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZp}}}); @@ -409,6 +405,7 @@ struct FlowZdcTask { } histos.fill(HIST("hEventCounter"), EvCutLabel::Zdc); auto zdc = foundBC.zdc(); + auto cent = collision.centFT0C(); float aT0A = 0., aT0C = 0., aV0A = 0.; if (foundBC.has_ft0()) { @@ -425,11 +422,95 @@ struct FlowZdcTask { aV0A += amplitude; } } + const double normT0M{(aT0A + aT0C) / 100.}; + float et = 0., meanpt = 0.; + int itsTracks = 0, glbTracks = 0; + for (const auto& track : tracks) { + if (track.hasITS() && ((track.eta() > minEta) && (track.eta() < maxEta))) { + itsTracks++; + } + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + glbTracks++; + } + bool skipEvent{false}; + if (useMidRapNchSel) { + auto hMeanNch = ccdb->getForTimeStamp(paTHmeanNch.value, foundBC.timestamp()); + auto hSigmaNch = ccdb->getForTimeStamp(paTHsigmaNch.value, foundBC.timestamp()); + if (!hMeanNch) { + LOGF(info, "hMeanNch NOT LOADED!"); + return; + } + if (!hSigmaNch) { + LOGF(info, "hSigmaNch NOT LOADED!"); + return; + } + + const int binT0M{hMeanNch->FindBin(normT0M)}; + const double meanNch{hMeanNch->GetBinContent(binT0M)}; + const double sigmaNch{hSigmaNch->GetBinContent(binT0M)}; + const double nSigmaSelection{nSigmaNchCut * sigmaNch}; + const double diffMeanNch{meanNch - glbTracks}; + + if (!(std::abs(diffMeanNch) < nSigmaSelection)) { + histos.fill(HIST("ExcludedEvtVsNch"), glbTracks); + } else { + skipEvent = true; + } + } else { + skipEvent = true; + } + if (!skipEvent) { + return; + } + + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + histos.fill(HIST("ZposVsEta"), collision.posZ(), track.eta()); + histos.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + histos.fill(HIST("dcaXYvspT"), track.dcaXY(), track.pt()); + et += std::sqrt(std::pow(track.pt(), 2.) + std::pow(o2::constants::physics::MassPionCharged, 2.)); + meanpt += track.pt(); + } + histos.fill(HIST("zPos"), collision.posZ()); + histos.fill(HIST("T0Ccent"), collision.centFT0C()); + histos.fill(HIST("GlbTracks"), glbTracks); + histos.fill(HIST("ampFT0C"), aT0C / 100.); + histos.fill(HIST("ampFT0A"), aT0A / 100.); + histos.fill(HIST("ampFT0M"), (aT0A + aT0C) / 100.); + histos.fill(HIST("ampFV0A"), aV0A / 100.); + // charged particle correlations + histos.fill(HIST("NchVsFV0A"), aV0A / 100., glbTracks); + histos.fill(HIST("NchVsFT0A"), aT0A / 100., glbTracks); + histos.fill(HIST("NchVsFT0C"), aT0C / 100., glbTracks); + histos.fill(HIST("NchVsFT0M"), (aT0A + aT0C) / 100., glbTracks); + histos.fill(HIST("hNchvsNPV"), collision.multNTracksPVeta1(), tracks.size()); + histos.fill(HIST("NchVsEt"), et, glbTracks); + histos.fill(HIST("NchVsITStracks"), itsTracks, glbTracks); + if (glbTracks >= minNchSel) { + histos.fill(HIST("NchVsMeanPt"), glbTracks, meanpt / glbTracks); + } float tZNA{zdc.timeZNA()}; float tZNC{zdc.timeZNC()}; float tZPA{zdc.timeZPA()}; float tZPC{zdc.timeZPC()}; - const double normT0M{(aT0A + aT0C) / 100.}; float znA = zdc.amplitudeZNA(); float znC = zdc.amplitudeZNC(); float zpA = zdc.amplitudeZPA(); @@ -438,19 +519,13 @@ struct FlowZdcTask { float commonSumZna = zdc.energyCommonZNA(); float commonSumZpc = zdc.energyCommonZPC(); float commonSumZpa = zdc.energyCommonZPA(); - float sumZNC = ((zdc.energySectorZNC())[0] + (zdc.energySectorZNC())[1] + (zdc.energySectorZNC())[2] + (zdc.energySectorZNC())[3]); - float sumZNA = ((zdc.energySectorZNA())[0] + (zdc.energySectorZNA())[1] + (zdc.energySectorZNA())[2] + (zdc.energySectorZNA())[3]); - float sumZPC = ((zdc.energySectorZPC())[0] + (zdc.energySectorZPC())[1] + (zdc.energySectorZPC())[2] + (zdc.energySectorZPC())[3]); - float sumZPA = ((zdc.energySectorZPA())[0] + (zdc.energySectorZPA())[1] + (zdc.energySectorZPA())[2] + (zdc.energySectorZPA())[3]); if (applyZdcCorrection) { const float a = zpaCoeff; const float b = zpcCoeff; zpA = zpA - a * znA; commonSumZpa = commonSumZpa - a * commonSumZna; - sumZPA = sumZPA - a * sumZNA; zpC = zpC - b * znC; commonSumZpc = commonSumZpc - b * commonSumZnc; - sumZPC = sumZPC - b * sumZNC; } float aZEM1{zdc.amplitudeZEM1()}; float aZEM2{zdc.amplitudeZEM2()}; @@ -464,34 +539,38 @@ struct FlowZdcTask { if ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) { histos.fill(HIST("ZNA"), znA); histos.fill(HIST("ZNACommon"), commonSumZna); - histos.fill(HIST("ZNASector"), sumZNA); histos.fill(HIST("ZNAVsFT0A"), aT0A / 100., znA); histos.fill(HIST("ZNAVsFT0C"), aT0C / 100., znA); histos.fill(HIST("ZNAVsFT0M"), (aT0A + aT0C) / 100., znA); + histos.fill(HIST("ZNAVsCent"), cent, znA); + histos.fill(HIST("ZNAVsNch"), glbTracks, znA); } if ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) { histos.fill(HIST("ZNC"), znC); histos.fill(HIST("ZNCCommon"), commonSumZnc); - histos.fill(HIST("ZNCSector"), sumZNC); histos.fill(HIST("ZNCVsFT0A"), aT0A / 100., znC); histos.fill(HIST("ZNCVsFT0C"), aT0C / 100., znC); histos.fill(HIST("ZNCVsFT0M"), (aT0A + aT0C) / 100., znC); + histos.fill(HIST("ZNCVsCent"), cent, znC); + histos.fill(HIST("ZNCVsNch"), glbTracks, znC); } if ((tZPA >= minTdcZp) && (tZPA <= maxTdcZp)) { histos.fill(HIST("ZPA"), zpA); histos.fill(HIST("ZPACommon"), commonSumZpa); - histos.fill(HIST("ZPASector"), sumZPA); histos.fill(HIST("ZPAVsFT0A"), aT0A / 100., zpA); histos.fill(HIST("ZPAVsFT0C"), aT0C / 100., zpA); histos.fill(HIST("ZPAVsFT0M"), (aT0A + aT0C) / 100., zpA); + histos.fill(HIST("ZPAVsCent"), cent, zpA); + histos.fill(HIST("ZPAVsNch"), glbTracks, zpA); } if ((tZPC >= minTdcZp) && (tZPC <= maxTdcZp)) { histos.fill(HIST("ZPC"), zpC); histos.fill(HIST("ZPCCommon"), commonSumZpc); - histos.fill(HIST("ZPCSector"), sumZPC); histos.fill(HIST("ZPCVsFT0A"), aT0A / 100., zpC); histos.fill(HIST("ZPCVsFT0C"), aT0C / 100., zpC); histos.fill(HIST("ZPCVsFT0M"), (aT0A + aT0C) / 100., zpC); + histos.fill(HIST("ZPCVsCent"), cent, zpC); + histos.fill(HIST("ZPCVsNch"), glbTracks, zpC); } if (((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) && ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn))) histos.fill(HIST("ZNVsZEM"), sumZEMs, sumZNs); @@ -502,7 +581,8 @@ struct FlowZdcTask { histos.fill(HIST("ZNVsFT0C"), aT0C / 100., znA + znC); histos.fill(HIST("ZNVsFT0M"), (aT0A + aT0C) / 100., znA + znC); histos.fill(HIST("CommonZNVsFT0M"), (aT0A + aT0C) / 100., commonSumZna + commonSumZnc); - histos.fill(HIST("SectorZNVsFT0M"), (aT0A + aT0C) / 100., sumZNA + sumZNC); + histos.fill(HIST("ZNVsCent"), cent, znA + znC); + histos.fill(HIST("ZNVsNch"), glbTracks, znA + znC); } if (((tZPA >= minTdcZp) && (tZPA <= maxTdcZp)) && ((tZPC >= minTdcZp) && (tZPC <= maxTdcZp))) { histos.fill(HIST("ZPAVsZPC"), zpC, zpA); @@ -511,7 +591,8 @@ struct FlowZdcTask { histos.fill(HIST("ZPVsFT0C"), aT0C / 100., zpA + zpC); histos.fill(HIST("ZPVsFT0M"), (aT0A + aT0C) / 100., zpA + zpC); histos.fill(HIST("CommonZPVsFT0M"), (aT0A + aT0C) / 100., commonSumZpa + commonSumZpc); - histos.fill(HIST("SectorZPVsFT0M"), (aT0A + aT0C) / 100., sumZPA + sumZPC); + histos.fill(HIST("ZPVsCent"), cent, zpA + zpC); + histos.fill(HIST("ZPVsNch"), glbTracks, zpA + zpC); } if (((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) && ((tZPA >= minTdcZp) && (tZPA <= maxTdcZp))) { histos.fill(HIST("ZNAVsZPA"), zpA, znA); @@ -536,26 +617,20 @@ struct FlowZdcTask { histos.fill(HIST("CommonZNAVsZPA"), commonSumZpa, commonSumZna); histos.fill(HIST("CommonZNCVsZPC"), commonSumZpc, commonSumZnc); histos.fill(HIST("ZNACommon"), commonSumZna); - histos.fill(HIST("ZNASector"), sumZNA); histos.fill(HIST("ZNCCommon"), commonSumZnc); - histos.fill(HIST("ZNCSector"), sumZNC); histos.fill(HIST("ZPACommon"), commonSumZpa); - histos.fill(HIST("ZPASector"), sumZPA); histos.fill(HIST("ZPCCommon"), commonSumZpc); - histos.fill(HIST("ZPCSector"), sumZPC); histos.fill(HIST("ZN"), znA + znC); histos.fill(HIST("ZPVsFT0A"), aT0A / 100., zpA + zpC); histos.fill(HIST("ZPVsFT0C"), aT0C / 100., zpA + zpC); histos.fill(HIST("ZPVsFT0M"), (aT0A + aT0C) / 100., zpA + zpC); histos.fill(HIST("CommonZPVsFT0M"), (aT0A + aT0C) / 100., commonSumZpa + commonSumZpc); - histos.fill(HIST("SectorZPVsFT0M"), (aT0A + aT0C) / 100., sumZPA + sumZPC); histos.fill(HIST("ZPAVsFT0A"), aT0A / 100., zpA); histos.fill(HIST("ZPAVsFT0C"), aT0C / 100., zpA); histos.fill(HIST("ZPAVsFT0M"), (aT0A + aT0C) / 100., zpA); histos.fill(HIST("ZNVsFT0C"), aT0C / 100., znA + znC); histos.fill(HIST("ZNVsFT0M"), (aT0A + aT0C) / 100., znA + znC); histos.fill(HIST("CommonZNVsFT0M"), (aT0A + aT0C) / 100., commonSumZna + commonSumZnc); - histos.fill(HIST("SectorZNVsFT0M"), (aT0A + aT0C) / 100., sumZNA + sumZNC); histos.fill(HIST("ZPCVsFT0A"), aT0A / 100., zpC); histos.fill(HIST("ZPCVsFT0C"), aT0C / 100., zpC); histos.fill(HIST("ZPCVsFT0M"), (aT0A + aT0C) / 100., zpC); @@ -565,6 +640,16 @@ struct FlowZdcTask { histos.fill(HIST("ZNAVsFT0A"), aT0A / 100., znA); histos.fill(HIST("ZNAVsFT0C"), aT0C / 100., znA); histos.fill(HIST("ZNAVsFT0M"), (aT0A + aT0C) / 100., znA); + histos.fill(HIST("ZNAVsCent"), cent, znA); + histos.fill(HIST("ZNCVsCent"), cent, znC); + histos.fill(HIST("ZPVsCent"), cent, zpA + zpC); + histos.fill(HIST("ZPAVsCent"), cent, zpA); + histos.fill(HIST("ZPCVsCent"), cent, zpC); + histos.fill(HIST("ZPAVsNch"), glbTracks, zpA); + histos.fill(HIST("ZPCVsNch"), glbTracks, zpC); + histos.fill(HIST("ZNVsNch"), glbTracks, znA + znC); + histos.fill(HIST("ZNCVsNch"), glbTracks, znC); + histos.fill(HIST("ZNAVsNch"), glbTracks, znA); } histos.fill(HIST("ZEM1"), aZEM1); histos.fill(HIST("ZEM2"), aZEM2); @@ -576,103 +661,6 @@ struct FlowZdcTask { histos.fill(HIST("ZEM2Vstdc"), tZEM2, aZEM2); histos.fill(HIST("debunch"), tZNA - tZNC, tZNA + tZNC); } - float et = 0., meanpt = 0.; - int itsTracks = 0, glbTracks = 0; - for (const auto& track : tracks) { - if (track.hasITS() && ((track.eta() > minEta) && (track.eta() < maxEta))) { - itsTracks++; - } - // Track Selection - if (!track.isGlobalTrack()) { - continue; - } - if ((track.pt() < minPt) || (track.pt() > maxPt)) { - continue; - } - if ((track.eta() < minEta) || (track.eta() > maxEta)) { - continue; - } - glbTracks++; - } - bool skipEvent{false}; - if (useMidRapNchSel) { - auto hMeanNch = ccdb->getForTimeStamp(paTHmeanNch.value, foundBC.timestamp()); - auto hSigmaNch = ccdb->getForTimeStamp(paTHsigmaNch.value, foundBC.timestamp()); - if (!hMeanNch) { - LOGF(info, "hMeanNch NOT LOADED!"); - return; - } - if (!hSigmaNch) { - LOGF(info, "hSigmaNch NOT LOADED!"); - return; - } - - const int binT0M{hMeanNch->FindBin(normT0M)}; - const double meanNch{hMeanNch->GetBinContent(binT0M)}; - const double sigmaNch{hSigmaNch->GetBinContent(binT0M)}; - const double nSigmaSelection{nSigmaNchCut * sigmaNch}; - const double diffMeanNch{meanNch - glbTracks}; - - if (!(std::abs(diffMeanNch) < nSigmaSelection)) { - histos.fill(HIST("ExcludedEvtVsNch"), glbTracks); - } else { - skipEvent = true; - } - } else { - skipEvent = true; - } - if (!skipEvent) { - return; - } - - for (const auto& track : tracks) { - // Track Selection - if (!track.isGlobalTrack()) { - continue; - } - if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { - continue; - } - if ((track.eta() < minEta) || (track.eta() > maxEta)) { - continue; - } - histos.fill(HIST("ZposVsEta"), collision.posZ(), track.eta()); - histos.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); - histos.fill(HIST("dcaXYvspT"), track.dcaXY(), track.pt()); - et += std::sqrt(std::pow(track.pt(), 2.) + std::pow(o2::constants::physics::MassPionCharged, 2.)); - meanpt += track.pt(); - } - histos.fill(HIST("zPos"), collision.posZ()); - histos.fill(HIST("T0Ccent"), collision.centFT0C()); - histos.fill(HIST("GlbTracks"), glbTracks); - - if (sumZEMs > zemCut) { - // ZDC Correlations - histos.fill(HIST("ZNAVsNch"), glbTracks, znA); - histos.fill(HIST("ZNCVsNch"), glbTracks, znC); - histos.fill(HIST("ZNVsNch"), glbTracks, sumZNs); - histos.fill(HIST("ZNDifVsNch"), glbTracks, znA - znC); - histos.fill(HIST("ZNCcvsZNCsum"), sumZNC, zdc.energyCommonZNC()); - histos.fill(HIST("ZNAcvsZNAsum"), sumZNA, zdc.energyCommonZNA()); - histos.fill(HIST("ZPCcvsZPCsum"), sumZPC, zdc.energyCommonZPC()); - histos.fill(HIST("ZPAcvsZPAsum"), sumZPA, zdc.energyCommonZPA()); - } - - histos.fill(HIST("ampFT0C"), aT0C / 100.); - histos.fill(HIST("ampFT0A"), aT0A / 100.); - histos.fill(HIST("ampFT0M"), (aT0A + aT0C) / 100.); - histos.fill(HIST("ampFV0A"), aV0A / 100.); - // charged particle correlations - histos.fill(HIST("NchVsFV0A"), aV0A / 100., glbTracks); - histos.fill(HIST("NchVsFT0A"), aT0A / 100., glbTracks); - histos.fill(HIST("NchVsFT0C"), aT0C / 100., glbTracks); - histos.fill(HIST("NchVsFT0M"), (aT0A + aT0C) / 100., glbTracks); - histos.fill(HIST("hNchvsNPV"), collision.multNTracksPVeta1(), tracks.size()); - histos.fill(HIST("NchVsEt"), et, glbTracks); - histos.fill(HIST("NchVsITStracks"), itsTracks, glbTracks); - if (glbTracks >= minNchSel) { - histos.fill(HIST("NchVsMeanPt"), glbTracks, meanpt / glbTracks); - } } void processZdc( @@ -688,10 +676,6 @@ struct FlowZdcTask { auto znC = zdc.amplitudeZNC(); auto zpA = zdc.amplitudeZPA(); auto zpC = zdc.amplitudeZPC(); - float sectorSumZNC = ((zdc.energySectorZNC())[0] + (zdc.energySectorZNC())[1] + (zdc.energySectorZNC())[2] + (zdc.energySectorZNC())[3]); - float sectorSumZNA = ((zdc.energySectorZNA())[0] + (zdc.energySectorZNA())[1] + (zdc.energySectorZNA())[2] + (zdc.energySectorZNA())[3]); - float sectorSumZPC = ((zdc.energySectorZPC())[0] + (zdc.energySectorZPC())[1] + (zdc.energySectorZPC())[2] + (zdc.energySectorZPC())[3]); - float sectorSumZPA = ((zdc.energySectorZPA())[0] + (zdc.energySectorZPA())[1] + (zdc.energySectorZPA())[2] + (zdc.energySectorZPA())[3]); float commonSumZnc = zdc.energyCommonZNC(); float commonSumZna = zdc.energyCommonZNA(); float commonSumZpc = zdc.energyCommonZPC(); @@ -707,22 +691,18 @@ struct FlowZdcTask { if ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) { histos.fill(HIST("ampZna"), znA); histos.fill(HIST("commonZna"), commonSumZna); - histos.fill(HIST("sectorSumZna"), sectorSumZNA); } if ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) { histos.fill(HIST("ampZnc"), znC); histos.fill(HIST("commonZnc"), commonSumZnc); - histos.fill(HIST("sectorSumZnc"), sectorSumZNC); } if ((tZPA >= minTdcZp) && (tZPA <= maxTdcZp)) { histos.fill(HIST("ampZpa"), zpA); histos.fill(HIST("commonZpa"), commonSumZpa); - histos.fill(HIST("sectorSumZpa"), sectorSumZPA); } if ((tZPC >= minTdcZp) && (tZPC <= maxTdcZp)) { histos.fill(HIST("ampZpc"), zpC); histos.fill(HIST("commonZpc"), commonSumZpc); - histos.fill(HIST("sectorSumZpc"), sectorSumZPC); } if (((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) && ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn))) histos.fill(HIST("ZnVsZem"), sumZEMs, znC + znA); @@ -743,10 +723,6 @@ struct FlowZdcTask { histos.fill(HIST("commonZnc"), commonSumZnc); histos.fill(HIST("commonZpa"), commonSumZpa); histos.fill(HIST("commonZpc"), commonSumZpc); - histos.fill(HIST("sectorSumZna"), sectorSumZNA); - histos.fill(HIST("sectorSumZnc"), sectorSumZNC); - histos.fill(HIST("sectorSumZpa"), sectorSumZPA); - histos.fill(HIST("sectorSumZpc"), sectorSumZPC); histos.fill(HIST("ZnVsZem"), sumZEMs, znC + znA); histos.fill(HIST("ZnaVsZnc"), znA, znC); histos.fill(HIST("ZpaVsZpc"), zpA, zpC); @@ -755,10 +731,6 @@ struct FlowZdcTask { } histos.fill(HIST("ampZEM1"), aZEM1); histos.fill(HIST("ampZEM2"), aZEM2); - histos.fill(HIST("ZnccVsZncSum"), sectorSumZNC, commonSumZnc); - histos.fill(HIST("ZnacVsZnaSum"), sectorSumZNA, commonSumZna); - histos.fill(HIST("ZpccVsZpcSum"), sectorSumZPC, commonSumZpc); - histos.fill(HIST("ZpacVsZpaSum"), sectorSumZPA, commonSumZpa); histos.fill(HIST("ZncVsTdc"), zdc.timeZNC(), znC); histos.fill(HIST("ZnaVsTdc"), zdc.timeZNA(), znA); histos.fill(HIST("ZpcVsTdc"), zdc.timeZPC(), zpC); diff --git a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx index 6680d402942..0266e81304d 100644 --- a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx +++ b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx @@ -66,6 +66,7 @@ using namespace o2::framework::expressions; #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; struct PidFlowPtCorr { + // configurable O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") @@ -112,13 +113,20 @@ struct PidFlowPtCorr { } dcaCutOpts; O2_DEFINE_CONFIGURABLE(cfgNSigmapid, std::vector, (std::vector{3, 3, 3, 9, 9, 9, 9, 9, 9}), "tpc, tof and its NSigma for Pion Proton Kaon") - O2_DEFINE_CONFIGURABLE(cfgMeanPtcent, std::vector, (std::vector{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), "mean Pt in different cent bin") struct : ConfigurableGroup { std::string prefix = "correctionPathOpts"; O2_DEFINE_CONFIGURABLE(cfgAcceptancePath, std::vector, (std::vector{"Users/f/fcui/NUA/NUAREFPartical", "Users/f/fcui/NUA/NUAK0s", "Users/f/fcui/NUA/NUALambda", "Users/f/fcui/NUA/NUAXi", "Users/f/fcui/NUA/NUAOmega"}), "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgEfficiencyPath, std::vector, (std::vector{"PathtoRef"}), "CCDB path to efficiency object") O2_DEFINE_CONFIGURABLE(cfgEfficiency2DPath, std::vector, (std::vector{"PathtoRef"}), "CCDB path to efficiency(pt, cent) object") + O2_DEFINE_CONFIGURABLE(cfgPidEfficiencyPath, std::vector, (std::vector{"PathtoRef"}), "Pi, Ka, Pr, CCDB path to PID efficiency(pt, cent) object") + + O2_DEFINE_CONFIGURABLE(cfgEfficiencyPath4ITSOnly, std::vector, (std::vector{"PathtoRef"}), "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgEfficiency2DPath4ITSOnly, std::vector, (std::vector{"PathtoRef"}), "CCDB path to efficiency(pt, cent) object") + O2_DEFINE_CONFIGURABLE(cfgPidEfficiencyPath4ITSOnly, std::vector, (std::vector{"PathtoRef"}), "Pi, Ka, Pr, CCDB path to PID efficiency(pt, cent) object") + + O2_DEFINE_CONFIGURABLE(cfgNUEOption, int, 1, "do NUE, 1: use 1D eff, 2: Using Eff(pt, cent), 3: use pid 1D eff, 4: use pid 2D eff, other: dont do NUE") } correctionPathOpts; O2_DEFINE_CONFIGURABLE(cfgRunNumbers, std::vector, (std::vector{544095, 544098, 544116, 544121, 544122, 544123, 544124}), "Preconfigured run numbers") @@ -126,16 +134,18 @@ struct PidFlowPtCorr { O2_DEFINE_CONFIGURABLE(cfgFlowNbootstrap, int, 30, "Number of subsamples for bootstrap") // switch - O2_DEFINE_CONFIGURABLE(cfgDoAccEffCorr, bool, false, "do acc and eff corr") - O2_DEFINE_CONFIGURABLE(cfgDoLocDenCorr, bool, false, "do local density corr") - O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") - O2_DEFINE_CONFIGURABLE(cfgOutputrunbyrun, bool, false, "Fill and output NUA weights run by run") - O2_DEFINE_CONFIGURABLE(cfgOutPutMC, bool, false, "Fill MC graphs, note that if the processMCgen is open,this MUST be open") - O2_DEFINE_CONFIGURABLE(cfgOutputLocDenWeights, bool, false, "Fill and output local density weights") - O2_DEFINE_CONFIGURABLE(cfgOutputQA, bool, false, "do QA") - - O2_DEFINE_CONFIGURABLE(cfgUsePtCentNUECorr, bool, true, "do NUA NUE, Using Eff(pt, cent) to do NUE") - O2_DEFINE_CONFIGURABLE(cfgDebugMyCode, bool, false, "output some graph for code debug") + struct : ConfigurableGroup { + std::string prefix = "switchsOpts"; + O2_DEFINE_CONFIGURABLE(cfgDoLocDenCorr, bool, false, "do local density corr"); + O2_DEFINE_CONFIGURABLE(cfgOutputrunbyrun, bool, false, "OPEN IF USE FUNCTION(fillcorrectiongraph) Fill and output NUA weights run by run"); + O2_DEFINE_CONFIGURABLE(cfgOutPutMC, bool, false, "Fill MC graphs, note that if the processMCgen is open,this MUST be open"); + O2_DEFINE_CONFIGURABLE(cfgOutputQA, bool, false, "OPEN IF USE FUNCTION(detectorPidQa) do QA"); + O2_DEFINE_CONFIGURABLE(cfgDebugMyCode, bool, false, "output some graph for code debug"); + O2_DEFINE_CONFIGURABLE(cfgOutPutPtSpectra, bool, false, "output pt spectra for data, MC and RECO"); + O2_DEFINE_CONFIGURABLE(cfgCheck2MethodDiff, bool, false, "check difference between v2' && v2''"); + O2_DEFINE_CONFIGURABLE(cfgUseITSOnly4MeanPt, bool, false, "use ITS only to calculate mean pt"); + O2_DEFINE_CONFIGURABLE(cfgClosureTest, int, 0, "choose (val) percent particle from charged to pass Pion PID selection"); + } switchsOpts; /** * @brief cfg for PID pt range @@ -163,6 +173,15 @@ struct PidFlowPtCorr { // end separate k-p // end cfg for PID pt range + struct : ConfigurableGroup { + std::string prefix = "particleAbundanceOpts"; + ConfigurableAxis cfgaxisAbundancePi{"cfgaxisAbundancePi", {100, 0, 1100}, "axis for Abundance Pi"}; + ConfigurableAxis cfgaxisAbundanceKa{"cfgaxisAbundanceKa", {100, 0, 200}, "axis for Abundance ka"}; + ConfigurableAxis cfgaxisAbundancePr{"cfgaxisAbundancePr", {100, 0, 50}, "axis for Abundance Pr"}; + + O2_DEFINE_CONFIGURABLE(cfgOutPutAbundanceDis, bool, false, "out put hists for pid particle Abundance QA"); + } particleAbundanceOpts; + ConfigurableAxis cfgaxisVertex{"cfgaxisVertex", {20, -10, 10}, "vertex axis for histograms"}; ConfigurableAxis cfgaxisPhi{"cfgaxisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; ConfigurableAxis cfgaxisEta{"cfgaxisEta", {40, -1., 1.}, "eta axis for histograms"}; @@ -177,12 +196,20 @@ struct PidFlowPtCorr { Configurable> cfgTrackDensityV3P{"cfgTrackDensityV3P", std::vector{0.0174056, 0.000703329, -1.45044e-05, 1.91991e-07, -1.62137e-09}, "parameter of v2(cent) for track density efficiency correction"}; Configurable> cfgTrackDensityV4P{"cfgTrackDensityV4P", std::vector{0.008845, 0.000259668, -3.24435e-06, 4.54837e-08, -6.01825e-10}, "parameter of v2(cent) for track density efficiency correction"}; + struct : ConfigurableGroup { + std::string prefix = "meanptC22GraphOpts"; + ConfigurableAxis cfgaxisBootstrap{"cfgaxisBootstrap", {30, 0, 30}, "cfgaxisBootstrap"}; + } meanptC22GraphOpts; + AxisSpec axisMultiplicity{{0, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90}, "Centrality (%)"}; + // configurable + + // filter // filter and using // data Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter trackFilter = (nabs(aod::track::eta) < trkQualityOpts.cfgCutEta.value) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + Filter trackFilter = (nabs(aod::track::eta) < trkQualityOpts.cfgCutEta.value); using TracksPID = soa::Join; // data tracks filter @@ -197,10 +224,14 @@ struct PidFlowPtCorr { Filter particleFilter = (nabs(aod::mcparticle::eta) < trkQualityOpts.cfgCutEta.value); using FilteredMcParticles = soa::Filtered; - using FilteredTracksWithMCLabel = soa::Filtered>; + using FilteredTracksWithMCLabel = soa::Filtered>; using FilteredCollisionsWithMCLabel = soa::Filtered>; // end using and filter + // filter + + // others + Preslice perCollision = aod::track::collisionId; // Connect to ccdb @@ -211,7 +242,6 @@ struct PidFlowPtCorr { // Define output HistogramRegistry registry{"registry"}; - OutputObj fWeightsREF{GFWWeights("weightsREF")}; // val used for bootstrap TRandom3* fRndm = new TRandom3(0); @@ -224,12 +254,11 @@ struct PidFlowPtCorr { // define global variables GFW* fGFW = new GFW(); // GFW class used from main src std::vector corrconfigs; + std::vector cfgAcceptance; - std::vector cfgEfficiency; - std::vector cfgEfficiency2D; + std::vector cfgMultPVCutPara; std::vector cfgNSigma; - std::vector cfgMeanPt; std::vector runNumbers; std::map>> th1sList; std::map>> th3sList; @@ -240,6 +269,7 @@ struct PidFlowPtCorr { kProton, kNumberOfParticles }; + enum OutputTH1Names { // here are TProfiles for vn-pt correlations that are not implemented in GFW hPhi = 0, @@ -261,9 +291,11 @@ struct PidFlowPtCorr { funcNumber }; + // graphs for NUE / NUA std::vector mAcceptance; - std::vector mEfficiency; - std::vector mEfficiency2D; + std::vector mEfficiency; + std::vector mEfficiency4ITSOnly; + bool correctionsLoaded = false; TF1* fMultPVCutLow = nullptr; @@ -307,17 +339,18 @@ struct PidFlowPtCorr { std::vector qaHistVector; // end hists for QA runbyrun + // others + void init(InitContext const&) // Initialization { + // init and add lots of graphs according to switch ccdb->setURL(cfgurl.value); ccdb->setCaching(true); ccdb->setCreatedNotAfter(cfgnolaterthan.value); cfgAcceptance = correctionPathOpts.cfgAcceptancePath.value; - cfgEfficiency = correctionPathOpts.cfgEfficiencyPath.value; - cfgEfficiency2D = correctionPathOpts.cfgEfficiency2DPath.value; + cfgNSigma = cfgNSigmapid; - cfgMeanPt = cfgMeanPtcent; cfgMultPVCutPara = evtSeleOpts.cfgMultPVCut; // Set the pt, mult and phi Axis; @@ -351,9 +384,10 @@ struct PidFlowPtCorr { registry.add("hEtaPhiVtxzREF", "", {HistType::kTH3D, {cfgaxisPhi, cfgaxisEta, {20, -10, 10}}}); registry.add("hNTracksPVvsCentrality", "", {HistType::kTH2D, {{5000, 0, 5000}, axisMultiplicity}}); + registry.add("hNchUnCorrectedVSNchCorrected", "", {HistType::kTH2D, {cfgaxisNch, cfgaxisNch}}); runNumbers = cfgRunNumbers; // TPC vs TOF vs its, comparation graphs, check the PID performance in difference pt - if (cfgOutputQA) { + if (switchsOpts.cfgOutputQA.value) { registry.add("DetectorPidPerformace/TPCvsTOF/Pi", "", {HistType::kTH3D, {{600, -30, 30}, {600, -30, 30}, cfgaxisPt}}); registry.add("DetectorPidPerformace/TPCvsTOF/Pr", "", {HistType::kTH3D, {{600, -30, 30}, {600, -30, 30}, cfgaxisPt}}); registry.add("DetectorPidPerformace/TPCvsTOF/Ka", "", {HistType::kTH3D, {{600, -30, 30}, {600, -30, 30}, cfgaxisPt}}); @@ -382,7 +416,7 @@ struct PidFlowPtCorr { TH1* hPhiRunByRunBefore = registry.add(Form("RunByRunQA%d/hPhiBefore", oneRun), "", {HistType::kTH1D, {cfgaxisPhi}}).get(); TH1* hPhiRunByRunAfter = registry.add(Form("RunByRunQA%d/hPhiAfter", oneRun), "", {HistType::kTH1D, {cfgaxisPhi}}).get(); - TH2* hITSnclsVsPhi = registry.add(Form("RunByRunQA%d/hITSnclsVsPhi", oneRun), "", {HistType::kTH2D, {cfgaxisPhi, {7, 0, 7}}}).get(); + TH2* hITSnclsVsPhi = registry.add(Form("RunByRunQA%d/hITSnclsVsPhi", oneRun), "", {HistType::kTH2D, {cfgaxisPhi, {8, 0, 8}}}).get(); TH2* hITSChi2VsPhi = registry.add(Form("RunByRunQA%d/hITSChi2VsPhi", oneRun), "", {HistType::kTH2D, {cfgaxisPhi, {100, 0, 10}}}).get(); qaHistVector.emplace_back(qaHist(hPhiRunByRunBefore, hPhiRunByRunAfter, hITSnclsVsPhi, hITSChi2VsPhi)); @@ -390,14 +424,26 @@ struct PidFlowPtCorr { // end run by run QA hists } // cfgoutputqa - if (cfgOutPutMC) { + if (switchsOpts.cfgOutPutMC.value) { // hist for NUE correction registry.add("correction/hPtCentMcRec", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); registry.add("correction/hPtCentMcGen", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + // ITS only + registry.add("correction/hPtCentMcRec4ITSOnly", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + + // hist for Pi eff + registry.add("correction/hPtCentMcRecPi", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + registry.add("correction/hPtCentMcGenPi", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + // hist for Ka eff + registry.add("correction/hPtCentMcRecKa", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + registry.add("correction/hPtCentMcGenKa", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + // hist for Pr eff + registry.add("correction/hPtCentMcRecPr", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + registry.add("correction/hPtCentMcGenPr", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); } // cfgoutputMC // debug hists - if (cfgDebugMyCode) { + if (switchsOpts.cfgDebugMyCode.value) { debugHist.hPtEffWeight = registry.add("debug/hPtEffWeight", "", {HistType::kTH1D, {cfgaxisPt}}); debugHist.hPtCentEffWeight = registry.add("debug/hPtCentEffWeight", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); debugHist.hRunNumberPhiEtaVertexWeight = registry.add("debug/hRunNumberPhiEtaVertexWeight", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); @@ -406,7 +452,20 @@ struct PidFlowPtCorr { } } // cfgdebugmycode - if (cfgOutputrunbyrun) { + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.add("ptSpectra/hPtCentData", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + registry.add("ptSpectra/hCentEventCountData", "", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("ptSpectra/hCentEventCountMcGen", "", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("ptSpectra/hCentEventCountMcRec", "", {HistType::kTH1D, {axisMultiplicity}}); + + registry.add("ptSpectra/hPtCentData4ITSOnly", "", {HistType::kTH2D, {cfgaxisPt, axisMultiplicity}}); + + registry.add("c22PrimeVsc22/Pi", "", {HistType::kTH2D, {{100, 0., 0.01}, {100, 0., 0.01}}}); + registry.add("c22PrimeVsc22/Ka", "", {HistType::kTH2D, {{100, 0., 0.01}, {100, 0., 0.01}}}); + registry.add("c22PrimeVsc22/Pr", "", {HistType::kTH2D, {{100, 0., 0.01}, {100, 0., 0.01}}}); + } // cfgoutputptspectra + + if (switchsOpts.cfgOutputrunbyrun.value) { // hist for NUA registry.add("correction/hRunNumberPhiEtaVertex", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); // set "correction/hRunNumberPhiEtaVertex" axis0 label @@ -416,6 +475,12 @@ struct PidFlowPtCorr { // end set "correction/hRunNumberPhiEtaVertex" axis0 label } // cfgooutputrunbyrun + if (particleAbundanceOpts.cfgOutPutAbundanceDis) { + registry.add("abundance/hNumOfPiEventCount", "", {HistType::kTH1D, {particleAbundanceOpts.cfgaxisAbundancePi}}); + registry.add("abundance/hNumOfKaEventCount", "", {HistType::kTH1D, {particleAbundanceOpts.cfgaxisAbundanceKa}}); + registry.add("abundance/hNumOfPrEventCount", "", {HistType::kTH1D, {particleAbundanceOpts.cfgaxisAbundancePr}}); + } + // set bin label for hEventCount // processdata registry.add("hEventCount/processData", "", {HistType::kTH1D, {{14, 0, 14}}}); @@ -445,6 +510,7 @@ struct PidFlowPtCorr { registry.add("hInteractionRate", "", {HistType::kTH1D, {{1000, 0, 1000}}}); // end set bin label for eventcount + // flow container setup // cumulant of flow // fill TObjArray for charged TObjArray* oba4Ch = new TObjArray(); @@ -491,6 +557,37 @@ struct PidFlowPtCorr { registry.add("ka/c22dmeanpt", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile2D, {axisMultiplicity, cfgaxisMeanPt}}); registry.add("pr/c22dmeanpt", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile2D, {axisMultiplicity, cfgaxisMeanPt}}); + // init tprofile3d for <2'> - meanpt + // charged + registry.add("meanptCentNbs/hCharged", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hChargedMeanpt", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + // end charged + + // pid + registry.add("meanptCentNbs/hChargedPionWithNpair", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hChargedPionFull", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hPion", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hPionMeanptWeightPidflow", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + + if (switchsOpts.cfgClosureTest.value != 0) { + registry.add("meanptCentNbs/hPionMeanptWeightC22pure", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hPionMeanptWeightMeanpt", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hPionMeanptWeightC22prime", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + } + + registry.add("meanptCentNbs/hChargedKaonWithNpair", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hChargedKaonFull", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hKaon", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hKaonMeanptWeightPidflow", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + + registry.add("meanptCentNbs/hChargedProtonWithNpair", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hChargedProtonFull", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hProton", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + registry.add("meanptCentNbs/hProtonMeanptWeightPidflow", "", {HistType::kTProfile3D, {cfgaxisMeanPt, axisMultiplicity, meanptC22GraphOpts.cfgaxisBootstrap}}); + // end pid + // end init tprofile3d for <2'> - meanpt + + // fgfw set up and correlation config setup // Data stored in fGFW double etaMax = trkQualityOpts.cfgCutEta.value; double etaGap = cfgEtaGap; @@ -551,7 +648,7 @@ struct PidFlowPtCorr { corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN refN | olKaN {2 2} refP {-2 -2}", "Kaon0gap24a", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP refP | olKaP {2 2} refN {-2 -2}", "Kaon0gap24b", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN refN | olPrN {2 2} refP {-2 -2}", "Prot0gap24a", kFALSE)); // 15 - corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP refP | olPaP {2 2} refN {-2 -2}", "Prot0gap24b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP refP | olPrP {2 2} refN {-2 -2}", "Prot0gap24b", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN08 {3} refP08 {-3}", "Pion08gap32a", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiP08 {3} refN08 {-3}", "Pion08gap32b", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN08 {3} refP08 {-3}", "Kaon08gap32a", kFALSE)); @@ -563,7 +660,7 @@ struct PidFlowPtCorr { corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN refN | olKaN {3 3} refP {-3 -3}", "Kaon0gap34a", kFALSE)); // 25 corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP refP | olKaP {3 3} refN {-3 -3}", "Kaon0gap34b", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN refN | olPrN {3 3} refP {-3 -3}", "Prot0gap34a", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP refP | olPaP {3 3} refN {-3 -3}", "Prot0gap34b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP refP | olPrP {3 3} refN {-3 -3}", "Prot0gap34b", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN08 {2} poiPiP08 {-2}", "PiPi08gap22", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN08 {2} poiKaP08 {-2}", "KaKa08gap22", kFALSE)); // 30 @@ -572,8 +669,16 @@ struct PidFlowPtCorr { corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN08 {3} poiKaP08 {-3}", "KaKa08gap22", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN08 {3} poiPrP08 {-3}", "PrPr08gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN {2} refP {-2}", "Pion0gap22a", kFALSE)); // 35 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiP {2} refN {-2}", "Pion0gap22b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN {2} refP {-2}", "Kaon0gap22a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP {2} refN {-2}", "Kaon0gap22b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN {2} refP {-2}", "Prot0gap22a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP {2} refN {-2}", "Prot0gap22b", kFALSE)); // 40 + fGFW->CreateRegions(); // finalize the initialization + // params // used for event selection fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); fMultPVCutLow->SetParameters(cfgMultPVCutPara[0], cfgMultPVCutPara[1], cfgMultPVCutPara[2], cfgMultPVCutPara[3], cfgMultPVCutPara[4], cfgMultPVCutPara[5], cfgMultPVCutPara[6], cfgMultPVCutPara[7], cfgMultPVCutPara[8], cfgMultPVCutPara[9]); @@ -585,16 +690,10 @@ struct PidFlowPtCorr { fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); - // fWeight output - if (cfgOutputNUAWeights) { - fWeightsREF->setPtBins(nPtBins, &(axisPt.binEdges)[0]); - fWeightsREF->init(true, false); - } - std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; hFindPtBin = new TH1D("hFindPtBin", "hFindPtBin", pTEffBins.size() - 1, &pTEffBins[0]); funcEff.resize(pTEffBins.size() - 1); - // LHC24g3 Eff + std::vector f1p0 = cfgTrackDensityP0; std::vector f1p1 = cfgTrackDensityP1; for (uint ifunc = 0; ifunc < pTEffBins.size() - 1; ifunc++) { @@ -612,6 +711,8 @@ struct PidFlowPtCorr { funcV4->SetParameters(v4para[0], v4para[1], v4para[2], v4para[3], v4para[4]); } + // pid utils function + /** * @brief Identify whether the input track is a Pion * @@ -624,6 +725,13 @@ struct PidFlowPtCorr { template bool isPion(TrackObject const& track) { + if (switchsOpts.cfgClosureTest.value != 0) { + float rnd4test = fRndm->Rndm() * 100; + if (rnd4test < switchsOpts.cfgClosureTest.value) { + return true; + } + } // closure test + bool resultPion = true; // Declare ITSResponse object internally to get ITS Sigma @@ -742,6 +850,26 @@ struct PidFlowPtCorr { return resultKaon; } + // pid util function + + // other utils + + double getPidC22InOneEvent(const GFW::CorrConfig& corrconfA, const GFW::CorrConfig& corrconfB) + { + double NpairA = fGFW->Calculate(corrconfA, 0, true).real(); + double NpairB = fGFW->Calculate(corrconfB, 0, true).real(); + + if (NpairA == 0 && NpairB == 0) + return 0; + + double ChC22A = NpairA ? fGFW->Calculate(corrconfA, 0, false).real() / NpairA : 0.; + double ChC22B = NpairB ? fGFW->Calculate(corrconfB, 0, false).real() / NpairB : 0.; + + double ChC22 = (ChC22A * NpairA + ChC22B * NpairB) / (NpairA + NpairB); + + return ChC22; + } + /** * @brief get stable particle * @note stable particle include @@ -773,14 +901,146 @@ struct PidFlowPtCorr { return false; } - void fillFC(MyParticleType type, const GFW::CorrConfig& corrconf, const double& cent, const double& rndm, const char* tarName) + // other utils + + // fgfw filling helpers + + /** + * @brief this function is used to fill fFCCh4PtC22 + * @details weight is nch * npair + * + * @param cent + * @param ptSum + * @param nch + * @param rndm + */ + void fillFC4PtC22(const double& cent, const double& ptSum, const double& nch, const double& rndm) + { + double dnx, val; + + dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); + if (dnx == 0) + return; + + // <2> + val = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnx; + if (std::fabs(val) >= 1) + return; + + registry.fill(HIST("meanptCentNbs/hCharged"), ptSum / nch, cent, rndm * cfgFlowNbootstrap, val, nch * dnx); + registry.fill(HIST("meanptCentNbs/hChargedMeanpt"), ptSum / nch, cent, rndm * cfgFlowNbootstrap, ptSum / nch, nch * dnx * val); + } + + /** + * @brief note that the graph's x axis is pid meanpt, for <2'> weight is nPid * npairPID, for <2> weight is nPid * npair + * + * @param cent + * @param rndm + * @param type + * @param pidPtSum + * @param nPid + */ + void fillFC4PtC22(const double& cent, const double& rndm, MyParticleType type, const double& pidPtSum, const double& nPid) + { + // <2> + double dnx, val; + + dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); + if (dnx == 0) + return; + + // <2> + val = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnx; + if (std::fabs(val) >= 1) + return; + + double pidc22 = 0; + double npairPid = 0; + switch (type) { + case MyParticleType::kPion: + pidc22 = getPidC22InOneEvent(corrconfigs.at(5), corrconfigs.at(6)); + if (pidc22 == 0) + return; + + npairPid = fGFW->Calculate(corrconfigs.at(5), 0, kTRUE).real() + fGFW->Calculate(corrconfigs.at(6), 0, kTRUE).real(); + if (npairPid == 0) + return; + + registry.fill(HIST("meanptCentNbs/hPion"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, pidc22, nPid * npairPid); + registry.fill(HIST("meanptCentNbs/hChargedPionFull"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, val, dnx * nPid); + registry.fill(HIST("meanptCentNbs/hChargedPionWithNpair"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, val, dnx); + registry.fill(HIST("meanptCentNbs/hPionMeanptWeightPidflow"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, pidPtSum / nPid, nPid * npairPid * pidc22 * pidc22 / val); + + if (switchsOpts.cfgClosureTest.value != 0) { + double npair4c22pure = fGFW->Calculate(corrconfigs.at(29), 0, kTRUE).real(); + if (npair4c22pure > 1e-3) + registry.fill(HIST("meanptCentNbs/hPionMeanptWeightC22pure"), + pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, + pidPtSum / nPid, + nPid * npairPid * fGFW->Calculate(corrconfigs.at(29), 0, kFALSE).real() / npair4c22pure); + + registry.fill(HIST("meanptCentNbs/hPionMeanptWeightMeanpt"), + pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, + pidPtSum / nPid, + nPid * npairPid * pidPtSum / nPid); + registry.fill(HIST("meanptCentNbs/hPionMeanptWeightC22prime"), + pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, + pidPtSum / nPid, + nPid * npairPid * pidc22); + } + + break; + // end pion + + case MyParticleType::kKaon: + pidc22 = getPidC22InOneEvent(corrconfigs.at(7), corrconfigs.at(8)); + if (pidc22 == 0) + return; + + npairPid = fGFW->Calculate(corrconfigs.at(7), 0, kTRUE).real() + fGFW->Calculate(corrconfigs.at(8), 0, kTRUE).real(); + if (npairPid == 0) + return; + + registry.fill(HIST("meanptCentNbs/hKaon"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, pidc22, nPid * npairPid); + registry.fill(HIST("meanptCentNbs/hChargedKaonFull"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, val, dnx * nPid); + registry.fill(HIST("meanptCentNbs/hChargedKaonWithNpair"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, val, dnx); + registry.fill(HIST("meanptCentNbs/hKaonMeanptWeightPidflow"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, pidPtSum / nPid, nPid * npairPid * pidc22 * pidc22 / val); + + break; + // end kaon + + case MyParticleType::kProton: + pidc22 = getPidC22InOneEvent(corrconfigs.at(9), corrconfigs.at(10)); + if (pidc22 == 0) + return; + + npairPid = fGFW->Calculate(corrconfigs.at(9), 0, kTRUE).real() + fGFW->Calculate(corrconfigs.at(10), 0, kTRUE).real(); + if (npairPid == 0) + return; + + registry.fill(HIST("meanptCentNbs/hProton"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, pidc22, nPid * npairPid); + registry.fill(HIST("meanptCentNbs/hChargedProtonFull"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, val, dnx * nPid); + registry.fill(HIST("meanptCentNbs/hChargedProtonWithNpair"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, val, dnx); + registry.fill(HIST("meanptCentNbs/hProtonMeanptWeightPidflow"), pidPtSum / nPid, cent, rndm * cfgFlowNbootstrap, pidPtSum / nPid, nPid * npairPid * pidc22 * pidc22 / val); + + break; + // end proton + + default: + return; + break; + } + // end switch particle type + } + + bool fillFC(MyParticleType type, const GFW::CorrConfig& corrconf, const double& cent, const double& rndm, const char* tarName) { double dnx, val; // calculate #sum exp{i * 0 (#phi_{i} - #phi_{j})} == N_{pairs} // note that weight is ignored in the formula but not in the calculation, for c24 is similar dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); if (dnx == 0) - return; + return false; if (!corrconf.pTDif) { // #sum exp{i * 2 * (#phi_{i} - #phi_{j})} / N_{pairs} == < 2 > val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; @@ -805,10 +1065,10 @@ struct PidFlowPtCorr { LOGF(warning, "particle not found"); break; } - return; + return true; } } - return; + return true; } /** @@ -912,6 +1172,10 @@ struct PidFlowPtCorr { return; } + // fill fgfw helper + + // correction apply functions + /** * @brief load NUE(1D) NUE(2D) NUA graphs * @note if u write more than one path in cfg, the graph would not load, that's the strange way to close NUE/NUA corr separatly @@ -935,87 +1199,229 @@ struct PidFlowPtCorr { } // end load NUA - // load NUE 1d - if (cfgEfficiency.size() == static_cast(nspecies)) { - for (int i = 0; i <= nspecies - 1; i++) { - mEfficiency.push_back(ccdb->getForTimeStamp(cfgEfficiency[i], timestamp)); - } - if (mEfficiency.size() == static_cast(nspecies)) - LOGF(info, "Loaded efficiency histogram"); - else - LOGF(fatal, "Could not load efficiency histogram"); - } - // end load NUE1d + /// @note dont modify load NUA!, just modify NUE + // here needs to load 2 NUE graph selected from 6 ccdb path + /// @note when using eff 2D, convert TH1* to (TH2D *) + // pid eff is not available now... + std::vector effPath1D = correctionPathOpts.cfgEfficiencyPath.value; + std::vector effPath2D = correctionPathOpts.cfgEfficiency2DPath.value; + std::vector effPathPid = correctionPathOpts.cfgPidEfficiencyPath.value; + + std::vector effPath1D4ITSOnly = correctionPathOpts.cfgEfficiencyPath4ITSOnly.value; + std::vector effPath2D4ITSOnly = correctionPathOpts.cfgEfficiency2DPath4ITSOnly.value; + std::vector effPathPid4ITSOnly = correctionPathOpts.cfgPidEfficiencyPath4ITSOnly.value; + + switch (correctionPathOpts.cfgNUEOption.value) { + case 1: // use 1D eff + // load 1d eff for global track + if (effPath1D.size() != static_cast(1)) { + LOGF(warning, "eff path 1d size != 1, skip eff 1d load"); + break; + } + mEfficiency.push_back(ccdb->getForTimeStamp(effPath1D[0], timestamp)); + if (mEfficiency.size() == static_cast(1)) { + LOGF(info, "Loaded efficiency histogram"); + } else { + LOGF(fatal, "Could not load efficiency histogram"); + } + // end load 1d eff for global track - // load NUE 2D - if (cfgEfficiency2D.size() == static_cast(nspecies)) { - for (int i = 0; i <= nspecies - 1; i++) { - mEfficiency2D.push_back(ccdb->getForTimeStamp(cfgEfficiency2D[i], timestamp)); - } - if (mEfficiency2D.size() == static_cast(nspecies)) - LOGF(info, "Loaded efficiency2D histogram"); - else - LOGF(fatal, "Could not load efficiency2D histogram"); - } - // end load NUE 2D + // load 1d eff for ITS only + if (effPath1D4ITSOnly.size() != static_cast(1)) { + LOGF(warning, "eff path for its 1d size != 1, skip its eff 1d load"); + break; + } + mEfficiency4ITSOnly.push_back(ccdb->getForTimeStamp(effPath1D4ITSOnly[0], timestamp)); + if (mEfficiency4ITSOnly.size() == static_cast(1)) { + LOGF(info, "Loaded ITS only efficiency histogram"); + } else { + LOGF(fatal, "Could not load ITS only efficiency histogram"); + } + // end load 1d eff for its only + + break; + // end use 1d eff + + case 2: // Use 2D eff + // load 2d eff for global track + if (effPath2D.size() != static_cast(1)) { + LOGF(warning, "eff path 2d size != 1, skip eff 2d load"); + break; + } + mEfficiency.push_back(ccdb->getForTimeStamp(effPath2D[0], timestamp)); + if (mEfficiency.size() == static_cast(1)) { + LOGF(info, "Loaded 2D efficiency histogram"); + } else { + LOGF(fatal, "Could not load 2D efficiency histogram"); + } + // end load 2d eff for global track + + // load 2d eff for ITS only + if (effPath2D4ITSOnly.size() != static_cast(1)) { + LOGF(warning, "eff path for its 2d size != 1, skip its eff 2d load"); + break; + } + mEfficiency4ITSOnly.push_back(ccdb->getForTimeStamp(effPath2D4ITSOnly[0], timestamp)); + if (mEfficiency4ITSOnly.size() == static_cast(1)) { + LOGF(info, "Loaded ITS only 2D efficiency histogram"); + } else { + LOGF(fatal, "Could not load ITS only 2D efficiency histogram"); + } + // end load 2d eff for its only + + break; + // end use 2d eff + + case 3: // use pid 1D eff + // load pid 1d eff for ITS + global track + if (effPathPid.size() != static_cast(3)) { + LOGF(warning, "eff path pid 1d size != 3, skip pid eff 1d load"); + break; + } + for (int i = 0; i < 3; i++) { + mEfficiency.push_back(ccdb->getForTimeStamp(effPathPid[i], timestamp)); + } + if (mEfficiency.size() == static_cast(3)) { + LOGF(info, "Loaded PID efficiency histogram"); + } else { + LOGF(fatal, "Could not load PID efficiency histogram"); + } + // end load pid 1d eff for ITS + global track + + // load pid 1d eff for ITS only + if (effPathPid4ITSOnly.size() != static_cast(3)) { + LOGF(warning, "eff path for its pid 1d size != 3, skip its pid eff 1d load"); + break; + } + for (int i = 0; i < 3; i++) { + mEfficiency4ITSOnly.push_back(ccdb->getForTimeStamp(effPathPid4ITSOnly[i], timestamp)); + } + if (mEfficiency4ITSOnly.size() == static_cast(3)) { + LOGF(info, "Loaded ITS only PID efficiency histogram"); + } else { + LOGF(fatal, "Could not load ITS only PID efficiency histogram"); + } + // end load pid 1d eff for its only + + break; + // end use pid 1d eff + + default: // not do NUE + break; + } // end switch load eff correctionsLoaded = true; } template - bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, TrackObject& track, float vtxz, int ispecies) + bool setParticleNUAWeight(float& weight_nua, TrackObject& track, float vtxz) { - float eff = 1.; - int nspecies = 1; - if (mEfficiency.size() == static_cast(nspecies)) - eff = mEfficiency[ispecies]->GetBinContent(mEfficiency[ispecies]->FindBin(track.pt())); - else - eff = 1.0; - if (eff == 0) { - return false; - } - weight_nue = 1. / eff; - if (mAcceptance.size() == static_cast(nspecies)) - weight_nua = mAcceptance[ispecies]->getNUA(track.phi(), track.eta(), vtxz); + if (mAcceptance.size() == static_cast(1)) + weight_nua = mAcceptance[0]->getNUA(track.phi(), track.eta(), vtxz); else weight_nua = 1; return true; } + /** + * @brief Set the Particle Nue Weight, for global track and ITS track, use different eff path + * + * @tparam TrackObject + * @param weight_nue + * @param track + * @param cent + * @param isGlobalTrack + * @return true weight setted succesfully, note that weight == 1 also return true; + * @return false eff got from graph == 0 + */ template - bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, TrackObject& track, float vtxz, int ispecies, double cent) + bool setParticleNUEWeight(float& weight_nue, TrackObject& track, double cent, bool isGlobalTrack) { float eff = 1.; - int nspecies = 1; - // eff 2d - if (mEfficiency2D.size() == static_cast(nspecies)) { - int ptBin = mEfficiency2D[ispecies]->GetXaxis()->FindBin(track.pt()); - int centBin = mEfficiency2D[ispecies]->GetYaxis()->FindBin(cent); - eff = mEfficiency2D[ispecies]->GetBinContent(ptBin, centBin); - } - if (eff == 0) { - return false; + uint64_t sizeOfEffVec = mEfficiency.size(); + uint64_t sizeOfEffVec4ITS = mEfficiency4ITSOnly.size(); + + TH2* eff2D = 0; + TH2* eff2D4ITS = 0; + + /// @note 1. size check 2. load eff 3. dividezero check + switch (correctionPathOpts.cfgNUEOption.value) { + case 1: // 1d + if (sizeOfEffVec != 1) + break; + if (sizeOfEffVec4ITS != 1) + break; + + if (isGlobalTrack) + eff = mEfficiency[0]->GetBinContent(mEfficiency[0]->FindBin(track.pt())); + else + eff = mEfficiency4ITSOnly[0]->GetBinContent(mEfficiency4ITSOnly[0]->FindBin(track.pt())); + + if (eff == 0.) + return false; + + break; + // end 1d + + case 2: // 2d + if (sizeOfEffVec != 1) + break; + if (sizeOfEffVec4ITS != 1) + break; + + eff2D = dynamic_cast(mEfficiency[0]); + eff2D4ITS = dynamic_cast(mEfficiency4ITSOnly[0]); + + if (!eff2D || !eff2D4ITS) { + LOGF(warning, "failed while converting TH1 to TH2! skip eff apply"); + break; + } + + if (isGlobalTrack) { + int ptBin = eff2D->GetXaxis()->FindBin(track.pt()); + int centBin = eff2D->GetYaxis()->FindBin(cent); + eff = eff2D->GetBinContent(ptBin, centBin); + } else { + int ptBin = eff2D4ITS->GetXaxis()->FindBin(track.pt()); + int centBin = eff2D4ITS->GetYaxis()->FindBin(cent); + eff = eff2D4ITS->GetBinContent(ptBin, centBin); + } + + if (eff == 0.) + return false; + + break; + // end 2d + + /// @todo add pid NUE eff + case 3: // pid + if (sizeOfEffVec != 3) + break; + if (sizeOfEffVec4ITS != 3) + break; + + break; + // end pid + + default: + break; } - weight_nue = 1. / eff; - // end eff 2d - // acc - if (mAcceptance.size() == static_cast(nspecies)) - weight_nua = mAcceptance[ispecies]->getNUA(track.phi(), track.eta(), vtxz); - else - weight_nua = 1; + weight_nue = 1. / eff; return true; - // end acc } + // correction apply function + + // track cut functions + /** * @brief cut MC particles * @note include * 1. eta cut * 2. pt cut - * 3. primaryparticle check - * 4. stable partccle + * 3. stable partccle * * @tparam mcParticle * @param particle @@ -1033,9 +1439,6 @@ struct PidFlowPtCorr { return false; if (particle.pt() > trkQualityOpts.cfgCutPtMax.value) return false; - // primary particle - if (!particle.isPhysicalPrimary()) - return false; // stable particle if (!isStable(particle.pdgCode())) return false; @@ -1044,16 +1447,12 @@ struct PidFlowPtCorr { } /** - * @brief track selection + * @brief global track selection, cut for specified detector is not include * @note include: 1. dcaxy - * 2. its ncls - * 3. tpc cross row - * 4. tpc ncls - * 5. pt cut - * 6. eta - * 7. tpc chi2 - * 8. dcaz - * 9. its CHI2 + * 2. pt cut + * 3. eta + * 4. dcaz + * * * @tparam TTrack * @param track @@ -1061,33 +1460,45 @@ struct PidFlowPtCorr { * @return false reject track */ template - bool trackSelected(TTrack& track) + bool trackSelectedGlobal(TTrack& track) { // dca xy cut // note that z cut is in filter if (dcaCutOpts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > dcaCutOpts.fPtDepDCAxy->Eval(track.pt()))) return false; - // its ncls cut - if (track.itsNCls() <= trkQualityOpts.cfgITSNCls.value) - return false; - // tpc crossedrows cut - if (track.tpcNClsCrossedRows() <= trkQualityOpts.cfgTPCCrossedRows.value) - return false; - // tpc ncls cut - if (track.tpcNClsFound() <= trkQualityOpts.cfgTPCNCls.value) - return false; + // pt if (!((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value))) return false; + // eta if (std::fabs(track.eta()) > trkQualityOpts.cfgCutEta.value) return false; - // tpc chi2 - if (track.tpcChi2NCl() > cfgCutChi2prTPCcls) - return false; + // dca z if (std::fabs(track.dcaZ()) > dcaCutOpts.cfgCutDCAz.value) return false; + + return true; + } + + /** + * @brief cut for ITS, include: + * 1. its n cluster + * 2. its chi2 + * + * @tparam TTrack + * @param track + * @return true + * @return false + */ + template + bool trackSelected4ITS(TTrack& track) + { + // its ncls cut + if (track.itsNCls() <= trkQualityOpts.cfgITSNCls.value) + return false; + // its chi2 if (track.itsChi2NCl() > trkQualityOpts.cfgITSChi2NDF.value) return false; @@ -1095,6 +1506,37 @@ struct PidFlowPtCorr { return true; } + /** + * @brief cut for TPC, include + * 1. TPC cross rows + * 2. tpc n cluster + * 3. tpc chi2 + * + * @tparam TTrack + * @param track + * @return true + * @return false + */ + template + bool trackSelected4TPC(TTrack& track) + { + // tpc crossedrows cut + if (track.tpcNClsCrossedRows() <= trkQualityOpts.cfgTPCCrossedRows.value) + return false; + // tpc ncls cut + if (track.tpcNClsFound() <= trkQualityOpts.cfgTPCNCls.value) + return false; + // tpc chi2 + if (track.tpcChi2NCl() > cfgCutChi2prTPCcls) + return false; + + return true; + } + + // track cut + + // event selection functions + /** * @brief fill eventCount for different function * @@ -1237,8 +1679,13 @@ struct PidFlowPtCorr { return true; } + // event selection + + // main functions + void processData(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks) { + // sub region, init // init float rndm = fRndm->Rndm(); int nTot = tracks.size(); @@ -1262,6 +1709,11 @@ struct PidFlowPtCorr { return; // end collision cut + // pt spectra + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hCentEventCountData"), cent); + } // switchsOpts.cfgOutPutPtSpectra.value + // correction loadCorrections(bc.timestamp()); float vtxz = collision.posZ(); @@ -1274,7 +1726,7 @@ struct PidFlowPtCorr { double psi2Est = 0, psi3Est = 0, psi4Est = 0; float wEPeff = 1; double v2 = 0, v3 = 0, v4 = 0; - if (cfgDoLocDenCorr) { + if (switchsOpts.cfgDoLocDenCorr.value) { double q2x = 0, q2y = 0; double q3x = 0, q3y = 0; double q4x = 0, q4y = 0; @@ -1298,28 +1750,138 @@ struct PidFlowPtCorr { v4 = funcV4->Eval(cent); } // cfgDoLocDenCorr - float weff = 1; - float wacc = 1; double ptSum = 0; double ptSumw2 = 0; double nch = 0; double nchSquare = 0; double ptSquareSum = 0; - // fill GFW ref flow + double nchCorrectedPassed = 0; + double nchPassedSelection = 0; + + if (switchsOpts.cfgDebugMyCode.value) { + LOGF(info, "===================================="); + } + + // val for pid particles + double pionPtSum = 0; + double kaonPtSum = 0; + double protonPtSum = 0; + + double nPionWeighted = 0; + double nKaonWeighted = 0; + double nProtonWeighted = 0; + + double pionPtSumw2 = 0; + double kaonPtSumw2 = 0; + double protonPtSumw2 = 0; + + double nPionSquare = 0; + double nKaonSquare = 0; + double nProtonSquare = 0; + + double pionPtSquareSum = 0; + double kaonPtSquareSum = 0; + double protonPtSquareSum = 0; + // end val for pid particles + + /// @note calculate pt + /// use ITS only for (const auto& track : tracks) { - if (cfgDoAccEffCorr) { - if (cfgUsePtCentNUECorr) { - // true - if (!setCurrentParticleWeights(weff, wacc, track, vtxz, 0, cent)) - continue; - } else { - // false - if (!setCurrentParticleWeights(weff, wacc, track, vtxz, 0)) - continue; - } // cfgUsePtCentNUECorr - } // cfgDoAccEffCorr + float weff = 1; + + // do nue + if (switchsOpts.cfgUseITSOnly4MeanPt.value) + setParticleNUEWeight(weff, track, cent, false); + else + setParticleNUEWeight(weff, track, cent, true); + // end do nue - if (cfgDoLocDenCorr) { + // track cut ITS only + if (!trackSelectedGlobal(track)) + continue; + if (!track.hasITS()) + continue; + if (!trackSelected4ITS(track)) + continue; + + if (switchsOpts.cfgUseITSOnly4MeanPt.value) { + if (track.hasTPC()) + continue; + } else { + if (!track.hasTPC()) + continue; + if (!trackSelected4TPC(track)) + continue; + } + // end track cut its only + + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hPtCentData4ITSOnly"), track.pt(), cent); + } + + // calculate ncharged(nch with weight) and pt + if (std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { + nch += weff; + nchSquare += weff * weff; + ptSum += weff * track.pt(); + ptSumw2 += weff * weff * track.pt(); + ptSquareSum += weff * weff * track.pt() * track.pt(); + + if (isPion(track)) { + nPionWeighted += weff; + nPionSquare += weff * weff; + pionPtSum += weff * track.pt(); + pionPtSumw2 += weff * weff * track.pt(); + pionPtSquareSum += weff * weff * track.pt() * track.pt(); + } + if (isKaon(track)) { + nKaonWeighted += weff; + nKaonSquare += weff * weff; + kaonPtSum += weff * track.pt(); + kaonPtSumw2 += weff * weff * track.pt(); + kaonPtSquareSum += weff * weff * track.pt() * track.pt(); + } + if (isProton(track)) { + nProtonWeighted += weff; + nProtonSquare += weff * weff; + protonPtSum += weff * track.pt(); + protonPtSumw2 += weff * weff * track.pt(); + protonPtSquareSum += weff * weff * track.pt() * track.pt(); + } + } + // end calculate nch and pt + + nchCorrectedPassed += weff; + nchPassedSelection += 1; + + if (weff == 1. && switchsOpts.cfgDebugMyCode.value) { + LOGF(info, "weff is 1, if nue opt is open and this message appears a lot, check!"); + } + } + // end pt calculation using ITS only + + if (switchsOpts.cfgDebugMyCode.value) { + LOGF(info, Form("its only track num %f", nchPassedSelection)); + } + + int totalGlobalTrack = 0; + // calculate number of pid particle + int numOfPi = 0; + int numOfKa = 0; + int numOfPr = 0; + + /// @note fill v2 flow + // use global track + for (const auto& track : tracks) { + float weff = 1; + float wacc = 1; + + // do NUE && NUA + setParticleNUAWeight(wacc, track, vtxz); + setParticleNUEWeight(weff, track, cent, true); + // end do NUE && NUA + + if (switchsOpts.cfgDoLocDenCorr.value) { bool withinPtRef = (trkQualityOpts.cfgCutPtMin.value < track.pt()) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); if (withinPtRef) { double fphi = v2 * std::cos(2 * (track.phi() - psi2Est)) + v3 * std::cos(3 * (track.phi() - psi3Est)) + v4 * std::cos(4 * (track.phi() - psi4Est)); @@ -1335,7 +1897,7 @@ struct PidFlowPtCorr { } } // cfgDoLocDenCorr - if (cfgDebugMyCode) { + if (switchsOpts.cfgDebugMyCode.value) { // pt eff weight graph { int ptBin = debugHist.hPtEffWeight->GetXaxis()->FindBin(track.pt()); @@ -1375,10 +1937,28 @@ struct PidFlowPtCorr { // end thn wacc graph } // cfgDebugMycode - // track cut - if (!trackSelected(track)) + // track cut, global + ITS + TPC + if (!trackSelectedGlobal(track)) + continue; + if (!track.hasITS()) continue; + if (!track.hasTPC()) + continue; + if (!trackSelected4ITS(track)) + continue; + if (!trackSelected4TPC(track)) + continue; + // end track cut + totalGlobalTrack++; + + if (switchsOpts.cfgDebugMyCode.value && weff == 1.) { + LOGF(info, "weff for global track is 1, if NUE is open and this appears a lot, check!"); + } + + if (switchsOpts.cfgDebugMyCode.value && wacc == 1.) { + LOGF(info, "wacc for global track is 1, if NUA is open and this appears alot, check!"); + } // fill QA hist registry.fill(HIST("hPhi"), track.phi()); @@ -1388,10 +1968,10 @@ struct PidFlowPtCorr { registry.fill(HIST("hPt"), track.pt()); // end fill QA hist - // track pt cut - if (!((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value))) - continue; - // end track pt cut + // pt spectra + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hPtCentData"), track.pt(), cent); + } // fill GFW // bit mask 1: fill CHARGED PARTICLES @@ -1401,34 +1981,37 @@ struct PidFlowPtCorr { // bitmask 18: 0010010 fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 18); // fill PIONS and overlap Pions + numOfPi++; } if (isKaon(track)) { // bitmask 36: 0100100 fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 36); // fill KAONS and overlap Kaons + numOfKa++; } if (isProton(track)) { // bitmask 72: 1001000 fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 72); // fill PROTONS and overlap Protons + numOfPr++; } // end fill GFW + } // end track loop for v2 calculation - if (cfgOutputNUAWeights) - fWeightsREF->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + // sub region, fill graphs after 2 loop on all tracks + if (particleAbundanceOpts.cfgOutPutAbundanceDis) { + registry.fill(HIST("abundance/hNumOfPiEventCount"), numOfPi); + registry.fill(HIST("abundance/hNumOfKaEventCount"), numOfKa); + registry.fill(HIST("abundance/hNumOfPrEventCount"), numOfPr); + } // outputabundacedis - // calculate ncharged(nch with weight) and pt - if (std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { - nch += weff; - nchSquare += weff * weff; - ptSum += weff * track.pt(); - ptSumw2 += weff * weff * track.pt(); - ptSquareSum += weff * weff * track.pt() * track.pt(); - } - // end calculate nch and pt - } // end track loop + if (switchsOpts.cfgDebugMyCode.value) { + LOGF(info, Form("global track num %d", totalGlobalTrack)); + } + + registry.fill(HIST("hNchUnCorrectedVSNchCorrected"), nchPassedSelection, nchCorrectedPassed); // fill hist using fGFW if (nch > 0) { @@ -1438,12 +2021,12 @@ struct PidFlowPtCorr { fillFC(MyParticleType::kCharged, corrconfigs.at(3), cent, rndm, "c32"); fillFC(MyParticleType::kCharged, corrconfigs.at(4), cent, rndm, "c34"); - fillFC(MyParticleType::kPion, corrconfigs.at(5), cent, rndm, "c22"); - fillFC(MyParticleType::kPion, corrconfigs.at(6), cent, rndm, "c22"); - fillFC(MyParticleType::kKaon, corrconfigs.at(7), cent, rndm, "c22"); - fillFC(MyParticleType::kKaon, corrconfigs.at(8), cent, rndm, "c22"); - fillFC(MyParticleType::kProton, corrconfigs.at(9), cent, rndm, "c22"); - fillFC(MyParticleType::kProton, corrconfigs.at(10), cent, rndm, "c22"); + fillFC(MyParticleType::kPion, corrconfigs.at(35), cent, rndm, "c22Full"); + fillFC(MyParticleType::kPion, corrconfigs.at(36), cent, rndm, "c22Full"); + fillFC(MyParticleType::kKaon, corrconfigs.at(37), cent, rndm, "c22Full"); + fillFC(MyParticleType::kKaon, corrconfigs.at(38), cent, rndm, "c22Full"); + fillFC(MyParticleType::kProton, corrconfigs.at(39), cent, rndm, "c22Full"); + fillFC(MyParticleType::kProton, corrconfigs.at(40), cent, rndm, "c22Full"); fillFC(MyParticleType::kPion, corrconfigs.at(11), cent, rndm, "c24"); fillFC(MyParticleType::kPion, corrconfigs.at(12), cent, rndm, "c24"); @@ -1466,13 +2049,26 @@ struct PidFlowPtCorr { fillFC(MyParticleType::kProton, corrconfigs.at(27), cent, rndm, "c34"); fillFC(MyParticleType::kProton, corrconfigs.at(28), cent, rndm, "c34"); - fillFC(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, "c22pure"); - fillFC(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, "c22pure"); - fillFC(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, "c22pure"); + bool filledPi = fillFC(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, "c22pure"); + bool filledKa = fillFC(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, "c22pure"); + bool filledPr = fillFC(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, "c22pure"); + fillFC(MyParticleType::kPion, corrconfigs.at(32), cent, rndm, "c32pure"); fillFC(MyParticleType::kKaon, corrconfigs.at(33), cent, rndm, "c32pure"); fillFC(MyParticleType::kProton, corrconfigs.at(34), cent, rndm, "c32pure"); + if (filledPi || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kPion, corrconfigs.at(5), cent, rndm, "c22"); + fillFC(MyParticleType::kPion, corrconfigs.at(6), cent, rndm, "c22"); + } + if (filledKa || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kKaon, corrconfigs.at(7), cent, rndm, "c22"); + fillFC(MyParticleType::kKaon, corrconfigs.at(8), cent, rndm, "c22"); + } + if (filledPr || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kProton, corrconfigs.at(9), cent, rndm, "c22"); + fillFC(MyParticleType::kProton, corrconfigs.at(10), cent, rndm, "c22"); + } fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, nch, nch, "c22TrackWeight"); fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(1), cent, rndm, nch, nch, "c24TrackWeight"); fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(2), cent, rndm, nch, nch, "c22FullTrackWeight"); @@ -1505,10 +2101,54 @@ struct PidFlowPtCorr { fillProfilePOIvnpt(corrconfigs.at(9), HIST("pr/c22dmeanpt"), cent, ptSum, nch); fillProfilePOIvnpt(corrconfigs.at(10), HIST("pr/c22dmeanpt"), cent, ptSum, nch); + fillFC4PtC22(cent, ptSum, nch, rndm); + if (nPionWeighted > 0) + fillFC4PtC22(cent, rndm, MyParticleType::kPion, pionPtSum, nPionWeighted); + + if (nKaonWeighted > 0) + fillFC4PtC22(cent, rndm, MyParticleType::kKaon, kaonPtSum, nKaonWeighted); + + if (nProtonWeighted > 0) + fillFC4PtC22(cent, rndm, MyParticleType::kProton, protonPtSum, nProtonWeighted); + + if (switchsOpts.cfgOutPutPtSpectra.value) { + // charged calculation + double NpairCharged = fGFW->Calculate(corrconfigs.at(0), 0, true).real(); + double chargedC22 = NpairCharged > 0 ? fGFW->Calculate(corrconfigs.at(0), 0, false).real() / NpairCharged : 0; + // end charged calculation + + // pi + double pidChargedC22Pi = getPidC22InOneEvent(corrconfigs.at(5), corrconfigs.at(6)); + if (pidChargedC22Pi > 0 && chargedC22 > 0) + registry.fill(HIST("c22PrimeVsc22/Pi"), pidChargedC22Pi, chargedC22); + // end pi + + // Ka + double pidKaonC22 = getPidC22InOneEvent(corrconfigs.at(7), corrconfigs.at(8)); + if (pidKaonC22 > 0 && chargedC22 > 0) + registry.fill(HIST("c22PrimeVsc22/Ka"), pidKaonC22, chargedC22); + // end Ka + + // Pr + double pidProtonC22 = getPidC22InOneEvent(corrconfigs.at(9), corrconfigs.at(10)); + if (pidProtonC22 > 0 && chargedC22 > 0) + registry.fill(HIST("c22PrimeVsc22/Pr"), pidProtonC22, chargedC22); + // end Pr + } + fFCCh->FillProfile("hMeanPt", cent, (ptSum / nch), nch, rndm); + if (nPionWeighted > 0) + fFCPi->FillProfile("hMeanPt", cent, (pionPtSum / nPionWeighted), nPionWeighted, rndm); + + if (nKaonWeighted > 0) + fFCKa->FillProfile("hMeanPt", cent, (kaonPtSum / nKaonWeighted), nKaonWeighted, rndm); + + if (nProtonWeighted > 0) + fFCPr->FillProfile("hMeanPt", cent, (protonPtSum / nProtonWeighted), nProtonWeighted, rndm); + double nchDiff = nch * nch - nchSquare; - if (nchDiff) { + if (nchDiff > 1e-3) { fFCCh->FillProfile("ptSquareAve", cent, (ptSum * ptSum - ptSquareSum) / nchDiff, nchDiff, rndm); @@ -1517,6 +2157,40 @@ struct PidFlowPtCorr { (nch * ptSum - ptSumw2) / nchDiff, nchDiff, rndm); } + + double pionDiff = nPionWeighted * nPionWeighted - nPionSquare; + if (pionDiff > 1e-3) { + fFCPi->FillProfile("ptSquareAve", cent, + (pionPtSum * pionPtSum - pionPtSquareSum) / pionDiff, + pionDiff, rndm); + + fFCPi->FillProfile("ptAve", cent, + (nPionWeighted * pionPtSum - pionPtSumw2) / pionDiff, + pionDiff, rndm); + } + + double kaonDiff = nKaonWeighted * nKaonWeighted - nKaonSquare; + if (kaonDiff > 1e-3) { + fFCKa->FillProfile("ptSquareAve", cent, + (kaonPtSum * kaonPtSum - kaonPtSquareSum) / kaonDiff, + kaonDiff, rndm); + + fFCKa->FillProfile("ptAve", cent, + (nKaonWeighted * kaonPtSum - kaonPtSumw2) / kaonDiff, + kaonDiff, rndm); + } + + double protonDiff = nProtonWeighted * nProtonWeighted - nProtonSquare; + if (protonDiff > 1e-3) { + fFCPr->FillProfile("ptSquareAve", cent, + (protonPtSum * protonPtSum - protonPtSquareSum) / protonDiff, + protonDiff, rndm); + + fFCPr->FillProfile("ptAve", cent, + (nProtonWeighted * protonPtSum - protonPtSumw2) / protonDiff, + protonDiff, rndm); + } + } // end fill hist using fillProfile } PROCESS_SWITCH(PidFlowPtCorr, processData, "", true); @@ -1568,7 +2242,15 @@ struct PidFlowPtCorr { // loop all the track for (const auto& track : tracks) { // track cut - if (!trackSelected(track)) + if (!trackSelectedGlobal(track)) + continue; + if (!track.hasITS()) + continue; + if (!track.hasTPC()) + continue; + if (!trackSelected4ITS(track)) + continue; + if (!trackSelected4TPC(track)) continue; // end track cut @@ -1641,7 +2323,15 @@ struct PidFlowPtCorr { // start filling graphs for (const auto& track : tracks) { // track cut - if (!trackSelected(track)) + if (!trackSelectedGlobal(track)) + continue; + if (!track.hasITS()) + continue; + if (!track.hasTPC()) + continue; + if (!trackSelected4ITS(track)) + continue; + if (!trackSelected4TPC(track)) continue; // end track cut @@ -1694,10 +2384,14 @@ struct PidFlowPtCorr { return; // end init && cut + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hCentEventCountMcRec"), cent); + } // cfgoutputptspectra + // loop tracks for (const auto& track : tracks) { // track cut - if (!trackSelected(track)) + if (!trackSelectedGlobal(track)) continue; // end track cut @@ -1706,7 +2400,30 @@ struct PidFlowPtCorr { auto mcParticle = track.mcParticle(); // fill graph if (particleSelected(mcParticle)) { - registry.fill(HIST("correction/hPtCentMcRec"), track.pt(), cent); + /// @note global track, fill rec hist + if (track.hasITS() && track.hasTPC() && trackSelected4ITS(track) && trackSelected4TPC(track)) { + // graph for all particles + registry.fill(HIST("correction/hPtCentMcRec"), track.pt(), cent); + + // identify particle and fill graph + if (isPion(track)) { + registry.fill(HIST("correction/hPtCentMcRecPi"), track.pt(), cent); + } + if (isKaon(track)) { + registry.fill(HIST("correction/hPtCentMcRecKa"), track.pt(), cent); + } + if (isProton(track)) { + registry.fill(HIST("correction/hPtCentMcRecPr"), track.pt(), cent); + } + // end identify particle and fill graph + } + // end global track, fill rec hist + + /// @note ITS track. fill rec hist + if (track.hasITS() && !track.hasTPC() && trackSelected4ITS(track)) { + registry.fill(HIST("correction/hPtCentMcRec4ITSOnly"), track.pt(), cent); + } + // end ITS track. fill rec hist } // end fill graph } @@ -1755,11 +2472,28 @@ struct PidFlowPtCorr { continue; // end collision cut + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hCentEventCountMcGen"), cent); + } // cfgoutputptspectra + // loop mc particles for (const auto& mcParticle : mcParticles) { // fill graph - if (particleSelected(mcParticle)) { + if (particleSelected(mcParticle) && mcParticle.isPhysicalPrimary()) { + // graph for all particles registry.fill(HIST("correction/hPtCentMcGen"), mcParticle.pt(), cent); + + // identify particle and fill graph + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus) { + registry.fill(HIST("correction/hPtCentMcGenPi"), mcParticle.pt(), cent); + } + if (std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus) { + registry.fill(HIST("correction/hPtCentMcGenKa"), mcParticle.pt(), cent); + } + if (std::abs(mcParticle.pdgCode()) == PDG_t::kProton) { + registry.fill(HIST("correction/hPtCentMcGenPr"), mcParticle.pt(), cent); + } + // end identify particle and fill graph } // end fill graph } @@ -1769,6 +2503,8 @@ struct PidFlowPtCorr { // end cut && init } PROCESS_SWITCH(PidFlowPtCorr, processSim, "function used to do pt eff, NOTE (OutPutMc, processReco, processSim) should be open", true); + + // main function }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/GenericFramework/Core/FlowPtContainer.cxx b/PWGCF/GenericFramework/Core/FlowPtContainer.cxx index b8189636987..f527b05d6af 100644 --- a/PWGCF/GenericFramework/Core/FlowPtContainer.cxx +++ b/PWGCF/GenericFramework/Core/FlowPtContainer.cxx @@ -699,8 +699,9 @@ void FlowPtContainer::fillSubeventPtProfiles(const double& centmult, const doubl } ++subIndex; } - if (valid) + if (valid) { dynamic_cast(fSubList->At(histCounter))->FillProfile(centmult, val, (fEventWeight == EventWeight::UnityWeight) ? 1.0 : dn, rn); + } ++histCounter; } return; @@ -907,16 +908,18 @@ void FlowPtContainer::fillCMSubeventProfiles(const double& centmult, const doubl for (int im = 1; im <= mpar; im++) { indOffset += im; } + + std::vector validMpar = {0, 0, 0}; // 0th order correlation cmDenSub[0].push_back(1.); cmValSub[0].push_back(1.); cmDenSub[nSubevents - 1].push_back(1.); cmValSub[nSubevents - 1].push_back(1.); - cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)]); - cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - insub[0][getVectorIndex(2, 0)]); - cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 0)] + 2 * insub[0][getVectorIndex(3, 0)]); - cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 6 * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] + 8 * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(3, 0)] + 3 * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(2, 0)] - 6 * insub[0][getVectorIndex(4, 0)]); + cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)]); // cmDensub[0][1] = sum w + cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - insub[0][getVectorIndex(2, 0)]); // cmDensub[0][2] = sum wi wj + cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 0)] + 2 * insub[0][getVectorIndex(3, 0)]); // cmDensub[0][3] = sum wi wj wk + cmDenSub[0].push_back(insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 6 * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] + 8 * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(3, 0)] + 3 * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(2, 0)] - 6 * insub[0][getVectorIndex(4, 0)]); // cmDensub[0][4] = sum wi wj wk wl cmDenSub[nSubevents - 1].push_back(insub[nSubevents - 1][getVectorIndex(1, 0)]); cmDenSub[nSubevents - 1].push_back(insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - insub[nSubevents - 1][getVectorIndex(2, 0)]); @@ -932,65 +935,68 @@ void FlowPtContainer::fillCMSubeventProfiles(const double& centmult, const doubl dynamic_cast(fSubCMList->At(indOffset + 0))->FillProfile(centmult, cmValSub[nSubevents - 1][1], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][1], rn); } - if (mpar < 2) - return; - if (insub[0][getVectorIndex(2, 0)] != 0 && cmDenSub[0][2] != 0) { - cmValSub[0].push_back(1 / cmDenSub[0][2] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] - insub[0][getVectorIndex(2, 2)])); - dynamic_cast(fSubCMList->At(1))->FillProfile(centmult, cmValSub[0][2], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][2], rn); - cmValSub[0].push_back(1 / cmDenSub[0][2] * (insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 1)] - insub[0][getVectorIndex(2, 1)])); - dynamic_cast(fSubCMList->At(2))->FillProfile(centmult, cmValSub[0][3], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][2], rn); - } - if (insub[nSubevents - 1][getVectorIndex(2, 0)] != 0 && cmDenSub[nSubevents - 1][2] != 0) { - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][2] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - insub[nSubevents - 1][getVectorIndex(2, 2)])); - dynamic_cast(fSubCMList->At(indOffset + 1))->FillProfile(centmult, cmValSub[nSubevents - 1][2], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][2], rn); - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][2] * (insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - insub[nSubevents - 1][getVectorIndex(2, 1)])); - dynamic_cast(fSubCMList->At(indOffset + 2))->FillProfile(centmult, cmValSub[nSubevents - 1][3], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][2], rn); - } - - if (mpar < 3) - return; - if (insub[0][getVectorIndex(3, 0)] != 0 && cmDenSub[0][3] != 0) { - cmValSub[0].push_back(1 / cmDenSub[0][3] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] - 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 1)] + 2 * insub[0][getVectorIndex(3, 3)])); - dynamic_cast(fSubCMList->At(3))->FillProfile(centmult, cmValSub[0][4], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][3], rn); - cmValSub[0].push_back(1 / cmDenSub[0][3] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] - 2 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 1)] + 2 * insub[0][getVectorIndex(3, 2)] - insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 0)])); - dynamic_cast(fSubCMList->At(4))->FillProfile(centmult, cmValSub[0][5], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][3], rn); - cmValSub[0].push_back(1 / cmDenSub[0][3] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 2 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 0)] + 2 * insub[0][getVectorIndex(3, 1)] - insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(2, 0)])); - dynamic_cast(fSubCMList->At(5))->FillProfile(centmult, cmValSub[0][6], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][3], rn); - } - if (insub[nSubevents - 1][getVectorIndex(3, 0)] != 0 && cmDenSub[nSubevents - 1][3] != 0) { - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][3] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 2 * insub[nSubevents - 1][getVectorIndex(3, 3)])); - dynamic_cast(fSubCMList->At(indOffset + 3))->FillProfile(centmult, cmValSub[nSubevents - 1][4], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][3], rn); - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][3] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 2 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 2 * insub[nSubevents - 1][getVectorIndex(3, 2)] - insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 0)])); - dynamic_cast(fSubCMList->At(indOffset + 4))->FillProfile(centmult, cmValSub[nSubevents - 1][5], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][3], rn); - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][3] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 2 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 2 * insub[nSubevents - 1][getVectorIndex(3, 1)] - insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(2, 0)])); - dynamic_cast(fSubCMList->At(indOffset + 5))->FillProfile(centmult, cmValSub[nSubevents - 1][6], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][3], rn); + if (mpar >= 2) { + if (insub[0][getVectorIndex(2, 0)] != 0 && cmDenSub[0][2] != 0) { + cmValSub[0].push_back(1 / cmDenSub[0][2] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] - insub[0][getVectorIndex(2, 2)])); + dynamic_cast(fSubCMList->At(1))->FillProfile(centmult, cmValSub[0][2], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][2], rn); + cmValSub[0].push_back(1 / cmDenSub[0][2] * (insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 1)] - insub[0][getVectorIndex(2, 1)])); + dynamic_cast(fSubCMList->At(2))->FillProfile(centmult, cmValSub[0][3], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][2], rn); + } + if (insub[nSubevents - 1][getVectorIndex(2, 0)] != 0 && cmDenSub[nSubevents - 1][2] != 0) { + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][2] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - insub[nSubevents - 1][getVectorIndex(2, 2)])); + dynamic_cast(fSubCMList->At(indOffset + 1))->FillProfile(centmult, cmValSub[nSubevents - 1][2], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][2], rn); + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][2] * (insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - insub[nSubevents - 1][getVectorIndex(2, 1)])); + dynamic_cast(fSubCMList->At(indOffset + 2))->FillProfile(centmult, cmValSub[nSubevents - 1][3], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][2], rn); + } + validMpar[0] = true; } - if (mpar < 4) - return; - if (insub[0][getVectorIndex(4, 0)] != 0 && cmDenSub[0][4] != 0) { - cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] - 6 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] + 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(2, 2)] + 8 * insub[0][getVectorIndex(3, 3)] * insub[0][getVectorIndex(1, 1)] - 6 * insub[0][getVectorIndex(4, 4)])); - dynamic_cast(fSubCMList->At(6))->FillProfile(centmult, cmValSub[0][7], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); - cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(2, 1)] + 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(2, 1)] + 6 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(3, 2)] - 6 * insub[0][getVectorIndex(4, 3)])); - dynamic_cast(fSubCMList->At(7))->FillProfile(centmult, cmValSub[0][8], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); - cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] + insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(2, 2)] - 4 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] + 4 * insub[0][getVectorIndex(3, 2)] * insub[0][getVectorIndex(1, 0)] + 4 * insub[0][getVectorIndex(3, 1)] * insub[0][getVectorIndex(1, 1)] + 2 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(2, 1)] - 6 * insub[0][getVectorIndex(4, 2)])); - dynamic_cast(fSubCMList->At(8))->FillProfile(centmult, cmValSub[0][9], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); - cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 0)] + 3 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(2, 0)] + 2 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(3, 0)] + 6 * insub[0][getVectorIndex(3, 1)] * insub[0][getVectorIndex(1, 0)] - 6 * insub[0][getVectorIndex(4, 1)])); - dynamic_cast(fSubCMList->At(9))->FillProfile(centmult, cmValSub[0][10], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); - } - if (insub[nSubevents - 1][getVectorIndex(4, 0)] != 0 && cmDenSub[nSubevents - 1][4] != 0) { - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - 6 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(2, 2)] + 8 * insub[nSubevents - 1][getVectorIndex(3, 3)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 4)])); - dynamic_cast(fSubCMList->At(indOffset + 6))->FillProfile(centmult, cmValSub[nSubevents - 1][7], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(2, 1)] + 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(2, 1)] + 6 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(3, 2)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 3)])); - dynamic_cast(fSubCMList->At(indOffset + 7))->FillProfile(centmult, cmValSub[nSubevents - 1][8], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - insub[nSubevents - 1][getVectorIndex(2, 0)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + insub[nSubevents - 1][getVectorIndex(2, 0)] * insub[nSubevents - 1][getVectorIndex(2, 2)] - 4 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 4 * insub[nSubevents - 1][getVectorIndex(3, 2)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 4 * insub[nSubevents - 1][getVectorIndex(3, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 2 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(2, 1)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 2)])); - dynamic_cast(fSubCMList->At(indOffset + 8))->FillProfile(centmult, cmValSub[nSubevents - 1][9], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); - cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(2, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 3 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(2, 0)] + 2 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(3, 0)] + 6 * insub[nSubevents - 1][getVectorIndex(3, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 1)])); - dynamic_cast(fSubCMList->At(indOffset + 9))->FillProfile(centmult, cmValSub[nSubevents - 1][10], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); + if (mpar >= 3) { + if (insub[0][getVectorIndex(3, 0)] != 0 && cmDenSub[0][3] != 0) { + cmValSub[0].push_back(1 / cmDenSub[0][3] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] - 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 1)] + 2 * insub[0][getVectorIndex(3, 3)])); + dynamic_cast(fSubCMList->At(3))->FillProfile(centmult, cmValSub[0][4], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][3], rn); + cmValSub[0].push_back(1 / cmDenSub[0][3] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] - 2 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 1)] + 2 * insub[0][getVectorIndex(3, 2)] - insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 0)])); + dynamic_cast(fSubCMList->At(4))->FillProfile(centmult, cmValSub[0][5], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][3], rn); + cmValSub[0].push_back(1 / cmDenSub[0][3] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 2 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 0)] + 2 * insub[0][getVectorIndex(3, 1)] - insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(2, 0)])); + dynamic_cast(fSubCMList->At(5))->FillProfile(centmult, cmValSub[0][6], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][3], rn); + } + if (insub[nSubevents - 1][getVectorIndex(3, 0)] != 0 && cmDenSub[nSubevents - 1][3] != 0) { + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][3] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 2 * insub[nSubevents - 1][getVectorIndex(3, 3)])); + dynamic_cast(fSubCMList->At(indOffset + 3))->FillProfile(centmult, cmValSub[nSubevents - 1][4], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][3], rn); + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][3] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 2 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 2 * insub[nSubevents - 1][getVectorIndex(3, 2)] - insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 0)])); + dynamic_cast(fSubCMList->At(indOffset + 4))->FillProfile(centmult, cmValSub[nSubevents - 1][5], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][3], rn); + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][3] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 2 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 2 * insub[nSubevents - 1][getVectorIndex(3, 1)] - insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(2, 0)])); + dynamic_cast(fSubCMList->At(indOffset + 5))->FillProfile(centmult, cmValSub[nSubevents - 1][6], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][3], rn); + } + validMpar[1] = true; + } + if (mpar >= 4) { + if (insub[0][getVectorIndex(4, 0)] != 0 && cmDenSub[0][4] != 0) { + cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] - 6 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] + 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(2, 2)] + 8 * insub[0][getVectorIndex(3, 3)] * insub[0][getVectorIndex(1, 1)] - 6 * insub[0][getVectorIndex(4, 4)])); + dynamic_cast(fSubCMList->At(6))->FillProfile(centmult, cmValSub[0][7], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); + cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(2, 1)] + 3 * insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(2, 1)] + 6 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(3, 2)] - 6 * insub[0][getVectorIndex(4, 3)])); + dynamic_cast(fSubCMList->At(7))->FillProfile(centmult, cmValSub[0][8], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); + cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - insub[0][getVectorIndex(2, 2)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 1)] + insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(2, 2)] - 4 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] + 4 * insub[0][getVectorIndex(3, 2)] * insub[0][getVectorIndex(1, 0)] + 4 * insub[0][getVectorIndex(3, 1)] * insub[0][getVectorIndex(1, 1)] + 2 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(2, 1)] - 6 * insub[0][getVectorIndex(4, 2)])); + dynamic_cast(fSubCMList->At(8))->FillProfile(centmult, cmValSub[0][9], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); + cmValSub[0].push_back(1 / cmDenSub[0][4] * (insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(1, 0)] * insub[0][getVectorIndex(1, 0)] - 3 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(2, 0)] * insub[0][getVectorIndex(1, 0)] + 3 * insub[0][getVectorIndex(2, 1)] * insub[0][getVectorIndex(2, 0)] + 2 * insub[0][getVectorIndex(1, 1)] * insub[0][getVectorIndex(3, 0)] + 6 * insub[0][getVectorIndex(3, 1)] * insub[0][getVectorIndex(1, 0)] - 6 * insub[0][getVectorIndex(4, 1)])); + dynamic_cast(fSubCMList->At(9))->FillProfile(centmult, cmValSub[0][10], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][4], rn); + } + if (insub[nSubevents - 1][getVectorIndex(4, 0)] != 0 && cmDenSub[nSubevents - 1][4] != 0) { + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - 6 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(2, 2)] + 8 * insub[nSubevents - 1][getVectorIndex(3, 3)] * insub[nSubevents - 1][getVectorIndex(1, 1)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 4)])); + dynamic_cast(fSubCMList->At(indOffset + 6))->FillProfile(centmult, cmValSub[nSubevents - 1][7], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(2, 1)] + 3 * insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(2, 1)] + 6 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(3, 2)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 3)])); + dynamic_cast(fSubCMList->At(indOffset + 7))->FillProfile(centmult, cmValSub[nSubevents - 1][8], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - insub[nSubevents - 1][getVectorIndex(2, 2)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - insub[nSubevents - 1][getVectorIndex(2, 0)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + insub[nSubevents - 1][getVectorIndex(2, 0)] * insub[nSubevents - 1][getVectorIndex(2, 2)] - 4 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 4 * insub[nSubevents - 1][getVectorIndex(3, 2)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 4 * insub[nSubevents - 1][getVectorIndex(3, 1)] * insub[nSubevents - 1][getVectorIndex(1, 1)] + 2 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(2, 1)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 2)])); + dynamic_cast(fSubCMList->At(indOffset + 8))->FillProfile(centmult, cmValSub[nSubevents - 1][9], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); + cmValSub[nSubevents - 1].push_back(1 / cmDenSub[nSubevents - 1][4] * (insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 3 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(2, 0)] * insub[nSubevents - 1][getVectorIndex(1, 0)] + 3 * insub[nSubevents - 1][getVectorIndex(2, 1)] * insub[nSubevents - 1][getVectorIndex(2, 0)] + 2 * insub[nSubevents - 1][getVectorIndex(1, 1)] * insub[nSubevents - 1][getVectorIndex(3, 0)] + 6 * insub[nSubevents - 1][getVectorIndex(3, 1)] * insub[nSubevents - 1][getVectorIndex(1, 0)] - 6 * insub[nSubevents - 1][getVectorIndex(4, 1)])); + dynamic_cast(fSubCMList->At(indOffset + 9))->FillProfile(centmult, cmValSub[nSubevents - 1][10], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[nSubevents - 1][4], rn); + } + validMpar[2] = true; } - // Fill cross terms for (int m = 2; m <= 4; ++m) { + if (!validMpar[m - 2]) + continue; for (int first = 1; first < m; ++first) { for (int second = first; second < m; ++second) { if (first > second) @@ -999,8 +1005,9 @@ void FlowPtContainer::fillCMSubeventProfiles(const double& centmult, const doubl for (int third = 1; third < m; ++third) { if (third > fourth) continue; - if (insub[0][getVectorIndex(m, 0)] != 0 && insub[nSubevents - 1][getVectorIndex(m, 0)] != 0 && cmDenSub[0][m] * cmDenSub[nSubevents - 1][m] != 0) + if (insub[0][getVectorIndex(m, 0)] != 0 && insub[nSubevents - 1][getVectorIndex(m, 0)] != 0 && cmDenSub[0][m] * cmDenSub[nSubevents - 1][m] != 0) { dynamic_cast(fSubCMList->FindObject(Form("cm%i_%i%isub1_%i%isub2", m, first, second, third, fourth)))->FillProfile(centmult, cmValSub[0][second * (second - 1) / 2 + second - first + 1] * cmValSub[nSubevents - 1][fourth * (fourth - 1) / 2 + fourth - third + 1], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDenSub[0][m] * cmDenSub[nSubevents - 1][m], rn); + } } } } diff --git a/PWGCF/GenericFramework/Tasks/CMakeLists.txt b/PWGCF/GenericFramework/Tasks/CMakeLists.txt index 338f173aa73..6238192e1be 100644 --- a/PWGCF/GenericFramework/Tasks/CMakeLists.txt +++ b/PWGCF/GenericFramework/Tasks/CMakeLists.txt @@ -18,3 +18,7 @@ o2physics_add_dpl_workflow(flow-gfw-light-ions SOURCES flowGfwLightIons.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(flow-gfw-v02 + SOURCES flowGfwV02.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx index cf7d2168c53..de8731f61ca 100644 --- a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx @@ -77,6 +77,7 @@ std::vector centbinning(90); int nBootstrap = 10; GFWRegions regions; GFWCorrConfigs configs; +GFWCorrConfigs configsradial; std::vector multGlobalCorrCutPars; std::vector multPVCorrCutPars; std::vector multGlobalPVCorrCutPars; @@ -94,24 +95,27 @@ struct FlowGenericFramework { O2_DEFINE_CONFIGURABLE(cfgFillWeights, bool, false, "Fill NUA weights") O2_DEFINE_CONFIGURABLE(cfgRunByRun, bool, false, "Fill histograms on a run-by-run basis") O2_DEFINE_CONFIGURABLE(cfgFillQA, bool, false, "Fill QA histograms") - O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, true, "Use additional event cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, false, "Use additional event cut on mult correlations"); O2_DEFINE_CONFIGURABLE(cfgUseCentralMoments, bool, true, "Use central moments in vn-pt calculations") O2_DEFINE_CONFIGURABLE(cfgUsePID, bool, true, "Enable PID information") O2_DEFINE_CONFIGURABLE(cfgUseGapMethod, bool, false, "Use gap method in vn-pt calculations") O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") - O2_DEFINE_CONFIGURABLE(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); - O2_DEFINE_CONFIGURABLE(cfgDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); - O2_DEFINE_CONFIGURABLE(cfgNTPCCls, float, 70, "Cut on number of TPC clusters found"); - O2_DEFINE_CONFIGURABLE(cfgNTPCXrows, float, 70, "Cut on number of TPC crossed rows"); - O2_DEFINE_CONFIGURABLE(cfgMinNITSCls, float, 5, "Cut on minimum number of ITS clusters found"); - O2_DEFINE_CONFIGURABLE(cfgChi2PrITSCls, float, 36, "Cut on chi^2 per ITS clusters found"); - O2_DEFINE_CONFIGURABLE(cfgChi2PrTPCCls, float, 2.5, "Cut on chi^2 per TPC clusters found"); O2_DEFINE_CONFIGURABLE(cfgPtmin, float, 0.2, "minimum pt (GeV/c)"); O2_DEFINE_CONFIGURABLE(cfgPtmax, float, 10, "maximum pt (GeV/c)"); O2_DEFINE_CONFIGURABLE(cfgEta, float, 0.8, "eta cut"); O2_DEFINE_CONFIGURABLE(cfgEtaPtPt, float, 0.4, "eta cut for pt-pt correlations"); O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10, "vertex cut (cm)"); + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); + O2_DEFINE_CONFIGURABLE(cfgDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgNTPCCls, float, 50, "Cut on number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgNTPCXrows, float, 70, "Cut on number of TPC crossed rows"); + O2_DEFINE_CONFIGURABLE(cfgMinNITSCls, float, 5, "Cut on minimum number of ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrITSCls, float, 36, "Cut on chi^2 per ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrTPCCls, float, 2.5, "Cut on chi^2 per TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgTPCSectorCut, bool, false, "Cut on pt-phi distribution"); + } cfgTrackCuts; struct : ConfigurableGroup { O2_DEFINE_CONFIGURABLE(cfgNoSameBunchPileupCut, bool, true, "kNoSameBunchPileupCut"); O2_DEFINE_CONFIGURABLE(cfgIsGoodZvtxFT0vsPV, bool, true, "kIsGoodZvtxFT0vsPV"); @@ -127,7 +131,6 @@ struct FlowGenericFramework { O2_DEFINE_CONFIGURABLE(cfgOccupancySelection, int, 2000, "Max occupancy selection, -999 to disable"); O2_DEFINE_CONFIGURABLE(cfgDoOccupancySel, bool, true, "Bool for event selection on detector occupancy"); O2_DEFINE_CONFIGURABLE(cfgMagField, float, 99999, "Configurable magnetic field; default CCDB will be queried"); - O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5, "pt cut on TOF for PID"); O2_DEFINE_CONFIGURABLE(cfgUseDensityDependentCorrection, bool, false, "Use density dependent efficiency correction based on Run 2 measurements"); Configurable> cfgTrackDensityP0{"cfgTrackDensityP0", std::vector{0.7217476707, 0.7384792571, 0.7542625668, 0.7640680200, 0.7701951667, 0.7755299053, 0.7805901710, 0.7849446786, 0.7957356586, 0.8113039262, 0.8211968966, 0.8280558878, 0.8329342135}, "parameter 0 for track density efficiency correction"}; Configurable> cfgTrackDensityP1{"cfgTrackDensityP1", std::vector{-2.169488e-05, -2.191913e-05, -2.295484e-05, -2.556538e-05, -2.754463e-05, -2.816832e-05, -2.846502e-05, -2.843857e-05, -2.705974e-05, -2.477018e-05, -2.321730e-05, -2.203315e-05, -2.109474e-05}, "parameter 1 for track density efficiency correction"}; @@ -148,11 +151,16 @@ struct FlowGenericFramework { O2_DEFINE_CONFIGURABLE(cfgGlobalT0ALowSigma, float, -3., "Number of sigma deviations below expected value in global vs T0A correlation"); O2_DEFINE_CONFIGURABLE(cfgGlobalT0AHighSigma, float, 4, "Number of sigma deviations above expected value in global vs T0A correlation"); } cfgGlobalAsideCorrCuts; + struct ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgUseStrictPID, bool, true, "Use strict PID cuts for TPC") + O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5, "pt cut on TOF for PID"); + } cfgPIDCuts; Configurable cfgGFWBinning{"cfgGFWBinning", {40, 16, 72, 300, 0, 3000, 0.2, 10.0, 0.2, 3.0, {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4, 4.5, 5, 5.5, 6, 7, 8, 9, 10}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90}}, "Configuration for binning"}; Configurable cfgRegions{"cfgRegions", {{"refN", "refP", "refFull"}, {-0.8, 0.4, -0.8}, {-0.4, 0.8, 0.8}, {0, 0, 0}, {1, 1, 1}}, "Configurations for GFW regions"}; Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "refP {3} refN {-3}", "refP {4} refN {-4}", "refFull {2 -2}", "refFull {2 2 -2 -2}"}, {"ChGap22", "ChGap32", "ChGap42", "ChFull22", "ChFull24"}, {0, 0, 0, 0, 0}, {15, 1, 1, 0, 0}}, "Configurations for each correlation to calculate"}; + Configurable cfgCorrConfigRadial{"cfgCorrConfigRadial", {{"refP {2} refN {-2}", "refP {3} refN {-3}", "refP {4} refN {-4}"}, {"ChGap22", "ChGap32", "ChGap42"}, {1, 1, 1}, {0, 0, 0}}, "Configurations for each radial flow correlation to calculate"}; // #include "PWGCF/TwoParticleCorrelations/TableProducer/Productions/skimmingconf_20221115.cxx" // NOLINT // Connect to ccdb @@ -166,10 +174,15 @@ struct FlowGenericFramework { // Define output OutputObj fFC{FlowContainer("FlowContainer")}; - OutputObj fFCpt{FlowPtContainer("FlowPtContainer")}; + OutputObj fFCpt_ch{FlowPtContainer("FlowPtContainer_ch")}; + OutputObj fFCpt_pi{FlowPtContainer("FlowPtContainer_pi")}; + OutputObj fFCpt_ka{FlowPtContainer("FlowPtContainer_ka")}; + OutputObj fFCpt_pr{FlowPtContainer("FlowPtContainer_pr")}; OutputObj fFCgen{FlowContainer("FlowContainer_gen")}; HistogramRegistry registry{"registry"}; + std::vector fFCpts = {&(*fFCpt_ch), &(*fFCpt_pi), &(*fFCpt_ka), &(*fFCpt_pr)}; + // QA outputs std::map>> th1sList; std::map>> th3sList; @@ -189,6 +202,7 @@ struct FlowGenericFramework { hNUApi, hNUAka, hNUApr, + hPtPhiMult, kCount_TH3Names }; enum CentEstimators { @@ -241,11 +255,12 @@ struct FlowGenericFramework { GFW* fGFW = new GFW(); std::vector corrconfigs; + std::vector corrconfigsradial; + TRandom3* fRndm = new TRandom3(0); TAxis* fPtAxis; int lastRun = -1; std::vector runNumbers; - TH1D* event_pt_spectrum; // Density dependent eff correction std::vector funcEff; @@ -275,9 +290,13 @@ struct FlowGenericFramework { TF1* fMultGlobalT0ACutLow = nullptr; TF1* fMultGlobalT0ACutHigh = nullptr; + // Track selection - pt-phi cuts + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + void init(InitContext const&) { - LOGF(info, "flowGenericFramework::init()"); + LOGF(info, "FlowGenericFramework::init()"); o2::analysis::gfw::regions.SetNames(cfgRegions->GetNames()); o2::analysis::gfw::regions.SetEtaMin(cfgRegions->GetEtaMin()); o2::analysis::gfw::regions.SetEtaMax(cfgRegions->GetEtaMax()); @@ -289,6 +308,11 @@ struct FlowGenericFramework { o2::analysis::gfw::configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); o2::analysis::gfw::regions.Print(); o2::analysis::gfw::configs.Print(); + o2::analysis::gfw::configsradial.SetCorrs(cfgCorrConfigRadial->GetCorrs()); + o2::analysis::gfw::configsradial.SetHeads(cfgCorrConfigRadial->GetHeads()); + o2::analysis::gfw::configsradial.SetpTDifs(cfgCorrConfigRadial->GetpTDifs()); + o2::analysis::gfw::configsradial.SetpTCorrMasks(cfgCorrConfigRadial->GetpTCorrMasks()); + o2::analysis::gfw::configsradial.Print(); o2::analysis::gfw::ptbinning = cfgGFWBinning->GetPtBinning(); o2::analysis::gfw::ptpoilow = cfgGFWBinning->GetPtPOImin(); o2::analysis::gfw::ptpoiup = cfgGFWBinning->GetPtPOImax(); @@ -313,6 +337,7 @@ struct FlowGenericFramework { o2::analysis::gfw::multGlobalT0ACutPars = cfgGlobalAsideCorrCuts.cfgMultGlobalT0ACutPars; AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; + AxisSpec phiModAxis = {100, 0, constants::math::PI / 9, "fmod(#varphi,#pi/9)"}; AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgEta, cfgEta, "#eta"}; AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; AxisSpec ptAxis = {o2::analysis::gfw::ptbinning, "#it{p}_{T} GeV/#it{c}"}; @@ -325,10 +350,11 @@ struct FlowGenericFramework { } AxisSpec nchAxis = {nchbinning, "N_{ch}"}; AxisSpec bAxis = {200, 0, 20, "#it{b}"}; - AxisSpec t0cAxis = {1000, 0, 10000, "N_{ch} (T0C)"}; - AxisSpec t0aAxis = {300, 0, 30000, "N_{ch} (T0A)"}; - AxisSpec v0aAxis = {800, 0, 80000, "N_{ch} (V0A)"}; - AxisSpec multpvAxis = {600, 0, 600, "N_{ch} (PV)"}; + AxisSpec t0cAxis = {1000, 0, 50000, "N_{ch} (T0C)"}; + AxisSpec t0aAxis = {1800, 0, 180000, "N_{ch} (T0A)"}; + AxisSpec v0aAxis = {1800, 0, 180000, "N_{ch} (V0A)"}; + AxisSpec multpvAxis = {3500, 0, 3500, "N_{ch} (PV)"}; + AxisSpec occAxis = {500, 0, 5000, "occupancy"}; AxisSpec multAxis = (doprocessOnTheFly && !cfgUseNch) ? bAxis : (cfgUseNch) ? nchAxis : centAxis; AxisSpec dcaZAXis = {200, -2, 2, "DCA_{z} (cm)"}; @@ -353,6 +379,7 @@ struct FlowGenericFramework { if (doprocessMCReco || doprocessData || doprocessRun2) { registry.add("trackQA/before/phi_eta_vtxZ", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); registry.add("trackQA/before/pt_dcaXY_dcaZ", "", {HistType::kTH3D, {ptAxis, dcaXYAXis, dcaZAXis}}); + registry.add("trackQA/before/pt_phi", "", {HistType::kTH2D, {ptAxis, phiModAxis}}); registry.add("trackQA/before/chi2prTPCcls", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); registry.add("trackQA/before/chi2prITScls", "#chi^{2}/cluster for the ITS track", {HistType::kTH1D, {{100, 0., 50.}}}); registry.add("trackQA/before/nTPCClusters", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); @@ -363,15 +390,16 @@ struct FlowGenericFramework { registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptreflow, o2::analysis::gfw::ptrefup}}}); registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoiup}}}); - registry.add("eventQA/before/centrality", "", {HistType::kTH1D, {centAxis}}); - registry.add("eventQA/before/multiplicity", "", {HistType::kTH1D, {nchAxis}}); - registry.add("eventQA/before/globalTracks_centT0C", "", {HistType::kTH2D, {centAxis, nchAxis}}); - registry.add("eventQA/before/PVTracks_centT0C", "", {HistType::kTH2D, {centAxis, multpvAxis}}); - registry.add("eventQA/before/globalTracks_PVTracks", "", {HistType::kTH2D, {multpvAxis, nchAxis}}); - registry.add("eventQA/before/globalTracks_multT0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); - registry.add("eventQA/before/globalTracks_multV0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); - registry.add("eventQA/before/multV0A_multT0A", "", {HistType::kTH2D, {t0aAxis, t0aAxis}}); - registry.add("eventQA/before/multT0C_centT0C", "", {HistType::kTH2D, {centAxis, t0cAxis}}); + registry.add("eventQA/before/centrality", "; centrality (%); Counts", {HistType::kTH1D, {centAxis}}); + registry.add("eventQA/before/multiplicity", "; N_{ch}; Counts", {HistType::kTH1D, {nchAxis}}); + registry.add("eventQA/before/globalTracks_centT0C", "; FT0C centrality (%); N_{global}", {HistType::kTH2D, {centAxis, nchAxis}}); + registry.add("eventQA/before/PVTracks_centT0C", "; FT0C centrality (%); N_{PV}", {HistType::kTH2D, {centAxis, multpvAxis}}); + registry.add("eventQA/before/globalTracks_PVTracks", "; N_{PV}; N_{global}", {HistType::kTH2D, {multpvAxis, nchAxis}}); + registry.add("eventQA/before/globalTracks_multT0A", "; multT0A; N_{global}", {HistType::kTH2D, {t0aAxis, nchAxis}}); + registry.add("eventQA/before/globalTracks_multV0A", "; multV0A; N_{global}", {HistType::kTH2D, {v0aAxis, nchAxis}}); + registry.add("eventQA/before/multV0A_multT0A", "; multV0A; multT0A", {HistType::kTH2D, {t0aAxis, v0aAxis}}); + registry.add("eventQA/before/multT0C_centT0C", "; multT0C; FT0C centrality (%)", {HistType::kTH2D, {centAxis, t0cAxis}}); + registry.add("eventQA/before/occ_mult_cent", "; occupancy; N_{ch}; centrality (%)", {HistType::kTH3D, {occAxis, nchAxis, centAxis}}); registry.addClone("eventQA/before/", "eventQA/after/"); registry.add("eventQA/eventSel", "Number of Events;; Counts", {HistType::kTH1D, {{11, 0, 11}}}); registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(1, "Filtered event"); @@ -386,6 +414,11 @@ struct FlowGenericFramework { registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(10, "after Mult cuts"); registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(11, "has track + within cent"); + registry.add("npt_ch", "; #it{p}_{T} (GeV/#it{c}; ; centrality (%); fraction)", {HistType::kTH2D, {ptAxis, centAxis}}); + registry.add("npt_pi", "; #it{p}_{T} (GeV/#it{c}; ; centrality (%); fraction)", {HistType::kTH2D, {ptAxis, centAxis}}); + registry.add("npt_ka", "; #it{p}_{T} (GeV/#it{c}; ; centrality (%); fraction)", {HistType::kTH2D, {ptAxis, centAxis}}); + registry.add("npt_pr", "; #it{p}_{T} (GeV/#it{c}; ; centrality (%); fraction)", {HistType::kTH2D, {ptAxis, centAxis}}); + if (!cfgRunByRun) { if (cfgUsePID) { registry.add("phi_eta_vtxz_ref", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); @@ -398,14 +431,6 @@ struct FlowGenericFramework { } } - // v0 - const TArrayD* bins = fPtAxis->GetXbins(); - if (bins->fN > 0) { - event_pt_spectrum = new TH1D("event_pt_spectrum", "event_pt_spectrum", bins->fN - 1, bins->fArray); - } - registry.add("meanNpt", "", {HistType::kTProfile2D, {ptAxis, multAxis}}); - registry.add("meanpt", "", {HistType::kTProfile, {multAxis}}); - registry.add("Npt_pt", "", {HistType::kTProfile2D, {ptAxis, multAxis}}); registry.add("trackQA/after/Nch_corrected", "", {HistType::kTH1D, {nchAxis}}); registry.add("trackQA/after/Nch_uncorrected", "", {HistType::kTH1D, {nchAxis}}); } @@ -420,9 +445,19 @@ struct FlowGenericFramework { } if (corrconfigs.empty()) LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); + + // Radial flow configs + for (auto i = 0; i < o2::analysis::gfw::configsradial.GetSize(); ++i) { + corrconfigsradial.push_back(fGFW->GetCorrelatorConfig(o2::analysis::gfw::configsradial.GetCorrs()[i], o2::analysis::gfw::configsradial.GetHeads()[i], o2::analysis::gfw::configsradial.GetpTDifs()[i])); + } + if (corrconfigsradial.empty()) + LOGF(error, "Radial configuration contains vectors of different size - check the GFWCorrConfig configurable"); + fGFW->CreateRegions(); TObjArray* oba = new TObjArray(); addConfigObjectsToObjArray(oba, corrconfigs); + addConfigObjectsToObjArray(oba, corrconfigsradial); + if (doprocessData || doprocessRun2 || doprocessMCReco) { fFC->SetName("FlowContainer"); fFC->SetXAxis(fPtAxis); @@ -434,9 +469,11 @@ struct FlowGenericFramework { fFCgen->Initialize(oba, multAxis, cfgNbootstrap); } delete oba; - fFCpt->setUseCentralMoments(cfgUseCentralMoments); - fFCpt->setUseGapMethod(cfgUseGapMethod); - fFCpt->initialise(multAxis, cfgMpar, o2::analysis::gfw::configs, cfgNbootstrap); + for (auto& container : fFCpts) { + container->setUseCentralMoments(cfgUseCentralMoments); + container->setUseGapMethod(cfgUseGapMethod); + container->initialise(multAxis, cfgMpar, o2::analysis::gfw::configs, cfgNbootstrap); + } // Multiplicity correlation cuts if (cfgMultCut) { @@ -482,6 +519,10 @@ struct FlowGenericFramework { LOGF(info, "fMultGlobalT0ACutHigh par %d = %g", i, fMultGlobalT0ACutHigh->GetParameter(i)); } + if (cfgTrackCuts.cfgTPCSectorCut) { + fPhiCutLow = new TF1("fPhiCutLow", "0.06/x+pi/18.0-0.06", 0, 100); + fPhiCutHigh = new TF1("fPhiCutHigh", "0.1/x+pi/18.0+0.06", 0, 100); + } // Density dependent corrections if (cfgUseDensityDependentCorrection) { std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; @@ -591,33 +632,40 @@ struct FlowGenericFramework { return 1. / eff; } - /* template - int getNsigmaPID(TTrack track) - { - // Computing Nsigma arrays for pion, kaon, and protons - std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; - std::array nSigmaCombined = {std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi()), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())}; - int pid = -1; - float nsigma = 3.0; - - // Choose which nSigma to use - std::array nSigmaToUse = (track.pt() > cfgTofPtCut && track.hasTOF()) ? nSigmaCombined : nSigmaTPC; - if (track.pt() >= cfgTofPtCut && !track.hasTOF()) - return -1; - - // Select particle with the lowest nsigma - const int nspecies = 3; - for (int i = 0; i < nspecies; ++i) { - if (std::abs(nSigmaToUse[i]) < nsigma) { - pid = i; + template + int getNsigmaPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaCombined = {std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi()), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())}; + int pid = -1; + float nsigma = 3.0; + + // Choose which nSigma to use + std::array nSigmaToUse = (track.pt() > cfgPIDCuts.cfgTofPtCut && track.hasTOF()) ? nSigmaCombined : nSigmaTPC; + if (track.pt() > cfgPIDCuts.cfgTofPtCut && !track.hasTOF()) + return 0; + + const int numSpecies = 3; + int pidCount = 0; + // Select particle with the lowest nsigma + for (int i = 0; i < numSpecies; ++i) { + if (std::abs(nSigmaToUse[i]) < nsigma) { + if (pidCount > 0 && cfgPIDCuts.cfgUseStrictPID) + return 0; // more than one particle with low nsigma + + pidCount++; + pid = i; + if (!cfgPIDCuts.cfgUseStrictPID) nsigma = std::abs(nSigmaToUse[i]); - } } - return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton } - */ + + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + template - bool eventSelected(TCollision collision, const int& multTrk, const float& centrality, const int& run) + bool eventSelected(TCollision collision, const int multTrk, const float& centrality, const int run) { // Cut on trigger alias if (cfgEventCutFlags.cfgTVXinTRD) { @@ -670,7 +718,7 @@ struct FlowGenericFramework { } template - bool selectMultiplicityCorrelation(TCollision collision, const int& multTrk, const float& centrality, const int& run) + bool selectMultiplicityCorrelation(TCollision collision, const int multTrk, const float& centrality, const int run) { auto multNTracksPV = collision.multNTracksPV(); if (multNTracksPV < fMultPVCutLow->Eval(centrality)) @@ -699,11 +747,29 @@ struct FlowGenericFramework { } template - bool trackSelected(TTrack track) + bool trackSelected(TTrack track, const int field) { - if (cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > cfgDCAxyNSigma / 7. * (0.0105f + 0.0035f / track.pt()))) + if (cfgTrackCuts.cfgTPCSectorCut) { + double phimodn = track.phi(); + if (field < 0) // for negative polarity field + phimodn = o2::constants::math::TwoPI - phimodn; + if (track.sign() < 0) // for negative charge + phimodn = o2::constants::math::TwoPI - phimodn; + if (phimodn < 0) + LOGF(warning, "phi < 0: %g", phimodn); + + phimodn += o2::constants::math::PI / 18.0; // to center gap in the middle + phimodn = fmod(phimodn, o2::constants::math::PI / 9.0); + if (cfgFillQA) + registry.fill(HIST("trackQA/before/pt_phi"), track.pt(), phimodn); + if (phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt())) + return false; // reject track + if (cfgFillQA) + registry.fill(HIST("trackQA/after/pt_phi"), track.pt(), phimodn); + } + if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > cfgTrackCuts.cfgDCAxyNSigma / 7. * (0.0105f + 0.0035f / track.pt()))) return false; - return ((track.tpcNClsCrossedRows() >= cfgNTPCXrows) && (track.tpcNClsFound() >= cfgNTPCCls) && (track.itsNCls() >= cfgMinNITSCls)); + return ((track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgNTPCXrows) && (track.tpcNClsFound() >= cfgTrackCuts.cfgNTPCCls) && (track.itsNCls() >= cfgTrackCuts.cfgMinNITSCls)); } template @@ -711,7 +777,7 @@ struct FlowGenericFramework { { if (std::fabs(track.dcaXY()) > (0.0105f + 0.0035f / track.pt())) return false; - return ((track.tpcNClsCrossedRows() >= 70) && (track.tpcNClsFound() >= 70) && (track.itsNCls() >= 5)); + return ((track.tpcNClsCrossedRows() >= 70) && (track.tpcNClsFound() >= 50) && (track.itsNCls() >= 5)); } enum DataType { @@ -720,7 +786,7 @@ struct FlowGenericFramework { }; template - void fillWeights(const TTrack track, const double vtxz, const int& pid_index, const int& run) + void fillWeights(const TTrack track, const double vtxz, const int pid_index, const int run) { if (cfgUsePID) { double ptpidmins[] = {o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoilow, 0.3, 0.5}; // min pt for ch, pi, ka, pr @@ -761,13 +827,15 @@ struct FlowGenericFramework { return; } - void createRunByRunHistograms(const int& run) + void createRunByRunHistograms(const int run) { AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; + AxisSpec phiModAxis = {100, 0, constants::math::PI / 9, "fmod(#varphi,#pi/9)"}; AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgEta, cfgEta, "#eta"}; AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; AxisSpec nchAxis = {o2::analysis::gfw::nchbins, o2::analysis::gfw::nchlow, o2::analysis::gfw::nchup, "N_{ch}"}; AxisSpec centAxis = {o2::analysis::gfw::centbinning, "Centrality (%)"}; + AxisSpec ptAxis = {o2::analysis::gfw::ptbinning, "#it{p}_{T} GeV/#it{c}"}; std::vector> histos(kCount_TH1Names); histos[hPhi] = registry.add(Form("%d/phi", run), "", {HistType::kTH1D, {phiAxis}}); histos[hEta] = registry.add(Form("%d/eta", run), "", {HistType::kTH1D, {etaAxis}}); @@ -797,18 +865,40 @@ struct FlowGenericFramework { } else { histos3d[hNUAref] = registry.add(Form("%d/phi_eta_vtxz_ref", run), "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); } + histos3d[hPtPhiMult] = registry.add(Form("%d/pt_phi_mult", run), "", {HistType::kTH3D, {ptAxis, phiModAxis, (cfgUseNch) ? nchAxis : centAxis}}); th3sList.insert(std::make_pair(run, histos3d)); return; } + struct AcceptedTracks { + explicit AcceptedTracks(std::size_t nptbins) + : nch(nptbins, 0.f), + npi(nptbins, 0.f), + nka(nptbins, 0.f), + npr(nptbins, 0.f) + { + } + + float total = 0; + unsigned int total_uncorr = 0; + + std::vector nch; + std::vector npi; + std::vector nka; + std::vector npr; + }; + template - void fillOutputContainers(const float& centmult, const double& rndm) + void fillOutputContainers(const float& centmult, const double& rndm, AcceptedTracks acceptedtracks) { - fFCpt->calculateCorrelations(); - fFCpt->fillPtProfiles(centmult, rndm); - fFCpt->fillCMProfiles(centmult, rndm); - if (!cfgUseGapMethod) - fFCpt->fillVnPtStdProfiles(centmult, rndm); + for (auto container : fFCpts) { + container->calculateCorrelations(); + container->fillPtProfiles(centmult, rndm); + container->fillCMProfiles(centmult, rndm); + if (!cfgUseGapMethod) + container->fillVnPtStdProfiles(centmult, rndm); + } + for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { if (!corrconfigs.at(l_ind).pTDif) { auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), 0, kTRUE).real(); @@ -817,8 +907,11 @@ struct FlowGenericFramework { auto val = fGFW->Calculate(corrconfigs.at(l_ind), 0, kFALSE).real() / dnx; if (std::abs(val) < 1) { (dt == kGen) ? fFCgen->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm) : fFC->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm); - if (cfgUseGapMethod) - fFCpt->fillVnPtProfiles(centmult, val, dnx, rndm, o2::analysis::gfw::configs.GetpTCorrMasks()[l_ind]); + if (cfgUseGapMethod) { + for (auto container : fFCpts) { + container->fillVnPtProfiles(centmult, val, dnx, rndm, o2::analysis::gfw::configs.GetpTCorrMasks()[l_ind]); + } + } } continue; } @@ -832,13 +925,41 @@ struct FlowGenericFramework { } } - // Only consider events where mean pt can be calculated - if (fFCpt->corrDen[1] != 0) { - double mean_pt = fFCpt->corrNum[1] / fFCpt->corrDen[1]; - registry.fill(HIST("meanpt"), centmult, mean_pt); - for (int bin = 1; bin <= event_pt_spectrum->GetNbinsX(); ++bin) { - registry.fill(HIST("meanNpt"), event_pt_spectrum->GetXaxis()->GetBinCenter(bin), centmult, event_pt_spectrum->GetBinContent(bin)); - registry.fill(HIST("Npt_pt"), event_pt_spectrum->GetXaxis()->GetBinCenter(bin), centmult, event_pt_spectrum->GetBinContent(bin) * mean_pt); + int total = (cfgUseNchCorrection) ? acceptedtracks.total : acceptedtracks.total_uncorr; + + if (total == 0) + return; + + for (std::size_t i = 0; i < acceptedtracks.nch.size(); ++i) + registry.fill(HIST("npt_ch"), fPtAxis->GetBinCenter(i + 1), centmult, acceptedtracks.nch[i] / total); + for (std::size_t i = 0; i < acceptedtracks.npi.size(); ++i) + registry.fill(HIST("npt_pi"), fPtAxis->GetBinCenter(i + 1), centmult, acceptedtracks.npi[i] / total); + for (std::size_t i = 0; i < acceptedtracks.nka.size(); ++i) + registry.fill(HIST("npt_ka"), fPtAxis->GetBinCenter(i + 1), centmult, acceptedtracks.nka[i] / total); + for (std::size_t i = 0; i < acceptedtracks.npr.size(); ++i) + registry.fill(HIST("npt_pr"), fPtAxis->GetBinCenter(i + 1), centmult, acceptedtracks.npr[i] / total); + + std::vector> inputs = {acceptedtracks.nch, acceptedtracks.npi, acceptedtracks.nka, acceptedtracks.npr}; + std::vector> fractions; + fractions.reserve(inputs.size()); + + for (const auto& vec : inputs) { + fractions.emplace_back(); + fractions.back().reserve(vec.size()); + + std::transform(vec.begin(), vec.end(), + std::back_inserter(fractions.back()), + [&](double x) { return x / total; }); + } + + for (uint l_ind = 0; l_ind < corrconfigsradial.size(); ++l_ind) { + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + auto dnx = fGFW->Calculate(corrconfigsradial.at(l_ind), i - 1, kTRUE).real(); + if (dnx == 0) + continue; + auto val = fGFW->Calculate(corrconfigsradial.at(l_ind), i - 1, kFALSE).real() / dnx; + if (std::abs(val) < 1) + (dt == kGen) ? fFCgen->FillProfile(Form("%s_pt_%i", corrconfigsradial.at(l_ind).Head.c_str(), i), centmult, val * fractions[l_ind][i - 1], dnx, rndm) : fFC->FillProfile(Form("%s_pt_%i", corrconfigsradial.at(l_ind).Head.c_str(), i), centmult, val * fractions[l_ind][i - 1], dnx, rndm); } } @@ -846,7 +967,7 @@ struct FlowGenericFramework { } template - void processCollision(TCollision collision, TTracks tracks, const float& centrality, const int& run) + void processCollision(TCollision collision, TTracks tracks, const float& centrality, const int field, const int run) { if (tracks.size() < 1) return; @@ -864,8 +985,9 @@ struct FlowGenericFramework { th1sList[run][hCent]->Fill(centrality); } fGFW->Clear(); - fFCpt->clearVector(); - event_pt_spectrum->Reset(); + for (auto& container : fFCpts) + container->clearVector(); + float lRandom = fRndm->Rndm(); // be cautious, this only works for Pb-Pb @@ -903,13 +1025,13 @@ struct FlowGenericFramework { densitycorrections.density = tracks.size(); } - AcceptedTracks acceptedTracks; + AcceptedTracks acceptedTracks(o2::analysis::gfw::ptbinning.size() - 1); for (const auto& track : tracks) { - processTrack(track, vtxz, run, densitycorrections, acceptedTracks); + processTrack(track, vtxz, field, run, densitycorrections, acceptedTracks); } - registry.fill(HIST("trackQA/after/Nch_corrected"), acceptedTracks.corrected); - registry.fill(HIST("trackQA/after/Nch_uncorrected"), acceptedTracks.uncorrected); + registry.fill(HIST("trackQA/after/Nch_corrected"), acceptedTracks.total); + registry.fill(HIST("trackQA/after/Nch_uncorrected"), acceptedTracks.total_uncorr); int multiplicity = 0; switch (cfgUseNchCorrection) { @@ -917,10 +1039,10 @@ struct FlowGenericFramework { multiplicity = tracks.size(); break; case 1: - multiplicity = acceptedTracks.corrected; + multiplicity = acceptedTracks.total; break; case 2: - multiplicity = acceptedTracks.uncorrected; + multiplicity = acceptedTracks.total_uncorr; break; default: multiplicity = tracks.size(); @@ -928,16 +1050,11 @@ struct FlowGenericFramework { } if (!cfgFillWeights) - fillOutputContainers
((cfgUseNch) ? multiplicity : centrality, lRandom); + fillOutputContainers
((cfgUseNch) ? multiplicity : centrality, lRandom, acceptedTracks); } - struct AcceptedTracks { - float corrected = 0; - unsigned int uncorrected = 0; - }; - template - inline void processTrack(TTrack const& track, const float& vtxz, const int& run, DensityCorr densitycorrections, AcceptedTracks& acceptedTracks) + inline void processTrack(TTrack const& track, const float& vtxz, const int field, const int run, DensityCorr densitycorrections, AcceptedTracks& acceptedTracks) { if constexpr (framework::has_type_v) { if (track.mcParticleId() < 0 || !(track.has_mcParticle())) @@ -956,10 +1073,10 @@ struct FlowGenericFramework { if (!nchSelected(track)) return; - acceptedTracks.corrected += getEfficiency(track); - ++acceptedTracks.uncorrected; + acceptedTracks.total += getEfficiency(track); + ++acceptedTracks.total_uncorr; - if (!trackSelected(track)) + if (!trackSelected(track, field)) return; int pidIndex = 0; @@ -975,7 +1092,7 @@ struct FlowGenericFramework { if (cfgFillWeights) { fillWeights(mcParticle, vtxz, 0, run); } else { - fillPtSums(track, vtxz); + fillPtSums(track, vtxz, pidIndex); fillGFW(mcParticle, vtxz, pidIndex, densitycorrections); } @@ -1005,9 +1122,9 @@ struct FlowGenericFramework { if (std::abs(track.pdgCode()) == kProton) pidIndex = 3; } - ++acceptedTracks.corrected; - ++acceptedTracks.uncorrected; - fillPtSums(track, vtxz); + ++acceptedTracks.total; + ++acceptedTracks.total_uncorr; + fillPtSums(track, vtxz, pidIndex); fillGFW(track, vtxz, pidIndex, densitycorrections); if (cfgFillQA) @@ -1015,29 +1132,34 @@ struct FlowGenericFramework { } else { if (cfgFillQA) fillTrackQA(track, vtxz); - // Select tracks with nominal cuts always if (!nchSelected(track)) return; + acceptedTracks.total += getEfficiency(track); + ++acceptedTracks.total_uncorr; - acceptedTracks.corrected += getEfficiency(track); - ++acceptedTracks.uncorrected; - - if (!trackSelected(track)) + if (!trackSelected(track, field)) return; - - int pidIndex = 0; - if (cfgUsePID) { - // pid_index = getBayesPIDIndex(track); - // pidIndex = getNsigmaPID(track); - pidIndex = 0; + // int pidIndex = 0; + // if (cfgUsePID) Need PID for v02 + int pidIndex = getNsigmaPID(track); + + std::size_t ptBinIndex = fPtAxis->FindBin(track.pt()) - 1; + if (!(ptBinIndex > o2::analysis::gfw::ptbinning.size())) { + acceptedTracks.nch[ptBinIndex] += (cfgUseNchCorrection) ? getEfficiency(track) : 1.0; + if (pidIndex == 1) + acceptedTracks.npi[ptBinIndex] += (cfgUseNchCorrection) ? getEfficiency(track) : 1.0; + if (pidIndex == 2) + acceptedTracks.nka[ptBinIndex] += (cfgUseNchCorrection) ? getEfficiency(track) : 1.0; + if (pidIndex == 3) + acceptedTracks.npr[ptBinIndex] += (cfgUseNchCorrection) ? getEfficiency(track) : 1.0; } + if (cfgFillWeights) { fillWeights(track, vtxz, pidIndex, run); } else { - fillPtSums(track, vtxz); + fillPtSums(track, vtxz, pidIndex); fillGFW(track, vtxz, pidIndex, densitycorrections); - event_pt_spectrum->Fill(track.pt(), (cfgUseNchCorrection == 1) ? getEfficiency(track) : 1.); } if (cfgFillQA) { fillTrackQA(track, vtxz); @@ -1050,20 +1172,22 @@ struct FlowGenericFramework { } template - inline void fillPtSums(TTrack track, const double& vtxz) + inline void fillPtSums(TTrack track, const double& vtxz, const int pidIndex) { double wacc = (dt == kGen) ? 1. : getAcceptance(track, vtxz, 0); double weff = (dt == kGen) ? 1. : getEfficiency(track); if (weff < 0) return; if (std::abs(track.eta()) < cfgEtaPtPt) { - fFCpt->fill(weff, track.pt()); + fFCpt_ch->fill(weff, track.pt()); + if (pidIndex) + fFCpts[pidIndex]->fill(weff, track.pt()); } if (!cfgUseGapMethod) { std::complex q2p = {weff * wacc * std::cos(2 * track.phi()), weff * wacc * std::sin(2 * track.phi())}; std::complex q2n = {weff * wacc * std::cos(-2 * track.phi()), weff * wacc * std::sin(-2 * track.phi())}; - fFCpt->fillArray(q2p, q2n, weff * track.pt(), weff); - fFCpt->fillArray(weff * wacc, weff * wacc, weff, weff); + fFCpt_ch->fillArray(q2p, q2n, weff * track.pt(), weff); + fFCpt_ch->fillArray(weff * wacc, weff * wacc, weff, weff); } } @@ -1185,10 +1309,10 @@ struct FlowGenericFramework { } o2::framework::expressions::Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; - o2::framework::expressions::Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::itsChi2NCl < cfgChi2PrITSCls) && (aod::track::tpcChi2NCl < cfgChi2PrTPCCls) && nabs(aod::track::dcaZ) < cfgDCAz; + o2::framework::expressions::Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::itsChi2NCl < cfgTrackCuts.cfgChi2PrITSCls) && (aod::track::tpcChi2NCl < cfgTrackCuts.cfgChi2PrTPCCls) && nabs(aod::track::dcaZ) < cfgTrackCuts.cfgDCAz; // using GFWTracks = soa::Filtered>; - using GFWTracks = soa::Filtered>; + using GFWTracks = soa::Filtered>; void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, GFWTracks const& tracks) { @@ -1211,23 +1335,30 @@ struct FlowGenericFramework { } if (!cfgFillWeights && !cfgRunByRun) loadCorrections(bc); + registry.fill(HIST("eventQA/eventSel"), 0.5); if (cfgRunByRun) th1sList[run][hEventSel]->Fill(0.5); + if (!collision.sel8()) return; + registry.fill(HIST("eventQA/eventSel"), 1.5); if (cfgRunByRun) th1sList[run][hEventSel]->Fill(1.5); + + float centrality = getCentrality(collision); + if (cfgDoOccupancySel) { int occupancy = collision.trackOccupancyInTimeRange(); + registry.fill(HIST("eventQA/before/occ_mult_cent"), occupancy, tracks.size(), centrality); if (occupancy < 0 || occupancy > cfgOccupancySelection) return; + registry.fill(HIST("eventQA/after/occ_mult_cent"), occupancy, tracks.size(), centrality); } registry.fill(HIST("eventQA/eventSel"), 2.5); if (cfgRunByRun) th1sList[run][hEventSel]->Fill(2.5); - float centrality = getCentrality(collision); if (cfgFillQA) fillEventQA(collision, tracks); registry.fill(HIST("eventQA/before/centrality"), centrality); @@ -1238,7 +1369,11 @@ struct FlowGenericFramework { fillEventQA(collision, tracks); registry.fill(HIST("eventQA/after/centrality"), centrality); registry.fill(HIST("eventQA/after/multiplicity"), tracks.size()); - processCollision(collision, tracks, centrality, run); + + // Get magnetic field polarity + auto field = (cfgMagField == 99999) ? getMagneticField(bc.timestamp()) : cfgMagField; + + processCollision(collision, tracks, centrality, field, run); } PROCESS_SWITCH(FlowGenericFramework, processData, "Process analysis for non-derived data", true); @@ -1251,9 +1386,31 @@ struct FlowGenericFramework { if (cfgRunByRun) createRunByRunHistograms(run); } + + registry.fill(HIST("eventQA/eventSel"), 0.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(0.5); + if (!collision.sel8()) return; + + registry.fill(HIST("eventQA/eventSel"), 1.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(1.5); + const auto centrality = getCentrality(collision); + + if (cfgDoOccupancySel) { + int occupancy = collision.trackOccupancyInTimeRange(); + registry.fill(HIST("eventQA/before/occ_mult_cent"), occupancy, tracks.size(), centrality); + if (occupancy < 0 || occupancy > cfgOccupancySelection) + return; + registry.fill(HIST("eventQA/after/occ_mult_cent"), occupancy, tracks.size(), centrality); + } + registry.fill(HIST("eventQA/eventSel"), 2.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(2.5); + if (cfgFillQA) fillEventQA(collision, tracks); if (!eventSelected(collision, tracks.size(), centrality, run)) @@ -1263,7 +1420,9 @@ struct FlowGenericFramework { if (!cfgFillWeights) loadCorrections(bc); - processCollision(collision, tracks, centrality, run); + + auto field = (cfgMagField == 99999) ? getMagneticField(bc.timestamp()) : cfgMagField; + processCollision(collision, tracks, centrality, field, run); } PROCESS_SWITCH(FlowGenericFramework, processMCReco, "Process analysis for MC reconstructed events", false); @@ -1277,7 +1436,7 @@ struct FlowGenericFramework { centrality = getCentrality(collision); } int run = 0; - processCollision(mcCollision, particles, centrality, run); + processCollision(mcCollision, particles, centrality, -999, run); } PROCESS_SWITCH(FlowGenericFramework, processMCGen, "Process analysis for MC generated events", false); @@ -1285,7 +1444,7 @@ struct FlowGenericFramework { { int run = 0; registry.fill(HIST("MCGen/impactParameter"), mcCollision.impactParameter(), mcParticles.size()); - processCollision(mcCollision, mcParticles, mcCollision.impactParameter(), run); + processCollision(mcCollision, mcParticles, mcCollision.impactParameter(), -999, run); } PROCESS_SWITCH(FlowGenericFramework, processOnTheFly, "Process analysis for MC on-the-fly generated events", false); @@ -1303,7 +1462,9 @@ struct FlowGenericFramework { const auto centrality = collision.centRun2V0M(); if (!cfgFillWeights) loadCorrections(bc); - processCollision(collision, tracks, centrality, run); + + auto field = (cfgMagField == 99999) ? getMagneticField(bc.timestamp()) : cfgMagField; + processCollision(collision, tracks, centrality, field, run); } PROCESS_SWITCH(FlowGenericFramework, processRun2, "Process analysis for Run 2 converted data", false); }; diff --git a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx new file mode 100644 index 00000000000..304b412696c --- /dev/null +++ b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx @@ -0,0 +1,745 @@ +// 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 flowGfwV02.cxx +/// \brief Skeleton copy of flowGfwLightIons with empty function bodies +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + +#include "FlowContainer.h" +#include "FlowPtContainer.h" +#include "GFW.h" +#include "GFWConfig.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" +#include "GFWWeightsList.h" + +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/JCorran/DataModel/JCatalyst.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; +static constexpr float LongArrayFloat[3][20] = {{1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {2.1, 2.2, 2.3, -2.1, -2.2, -2.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {3.1, 3.2, 3.3, -3.1, -3.2, -3.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}}; + +namespace o2::analysis::gfw +{ +std::vector ptbinning = {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; +float ptpoilow = 0.2, ptpoiup = 10.0; +float ptreflow = 0.2, ptrefup = 3.0; +float ptlow = 0.2, ptup = 10.0; +int etabins = 16; +float etalow = -0.8, etaup = 0.8; +int vtxZbins = 40; +float vtxZlow = -10.0, vtxZup = 10.0; +int phibins = 72; +float philow = 0.0; +float phiup = o2::constants::math::TwoPI; +int nchbins = 300; +float nchlow = 0; +float nchup = 3000; +std::vector centbinning(90); +int nBootstrap = 10; +std::vector> etagapsPtPt; +GFWRegions regions; +GFWCorrConfigs configs; +} // namespace o2::analysis::gfw + +struct FlowGfwV02 { + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgMpar, int, 4, "Highest order of pt-pt correlations") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgFixedMultMin, int, 1, "Minimum for fixed nch range"); + O2_DEFINE_CONFIGURABLE(cfgFixedMultMax, int, 3000, "Maximum for fixed nch range"); + O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5f, "Minimum pt to use TOF N-sigma") + O2_DEFINE_CONFIGURABLE(cfgUseItsPID, bool, true, "Use ITS PID for particle identification") + O2_DEFINE_CONFIGURABLE(cfgGetNsigmaQA, bool, true, "Get QA histograms for selection of pions, kaons, and protons") + O2_DEFINE_CONFIGURABLE(cfgUseMultiplicityFlowWeights, bool, true, "Enable or disable the use of multiplicity-based event weighting"); + O2_DEFINE_CONFIGURABLE(cfgNormalizeByCharged, bool, true, "Enable or disable the normalization by charged particles"); + O2_DEFINE_CONFIGURABLE(cfgConsistentEventFlag, int, 15, "Flag for consistent event selection"); + + Configurable cfgGFWBinning{"cfgGFWBinning", {40, 16, 72, 300, 0, 3000, 0.2, 10.0, 0.2, 5.0, {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4, 4.5, 5}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90}}, "Configuration for binning"}; + Configurable cfgRegions{"cfgRegions", {{"refN", "refP", "refFull", "refMid", "piP", "kaP", "prP"}, {-0.8, 0.5, -0.8, -0.4, 0.5, 0.5, 0.5}, {-0.5, 0.8, 0.8, 0.4, 0.8, 0.8, 0.8}, {0, 0, 0, 0, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1}}, "Configurations for GFW regions"}; + + Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "piP {2} refN {-2}", "kaP {2} refN {-2}", "prP {2} refN {-2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}"}, {"ChGap22", "PiGap22", "KaGap22", "PrGap22", "ChFull22", "nchCh", "nchPi", "nchKa", "nchPr", "v02ptCh", "v02ptPi", "v02ptKa", "v02ptPr"}, {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {15, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, "Configurations for each correlation to calculate"}; + Configurable> nSigmas{"nSigmas", {LongArrayFloat[0], 6, 3, {"UpCut_pi", "UpCut_ka", "UpCut_pr", "LowCut_pi", "LowCut_ka", "LowCut_pr"}, {"TPC", "TOF", "ITS"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; + + struct : ConfigurableGroup { + Configurable cfgPtMin{"cfgPtMin", 0.2f, "Minimum pT used for track selection."}; + Configurable cfgPtMax{"cfgPtMax", 5.0f, "Maximum pT used for track selection."}; + Configurable cfgEtaMax{"cfgEtaMax", 0.8f, "Maximum eta used for track selection."}; + } cfgTrackCuts; + + struct : ConfigurableGroup { + Configurable cfgZvtxMax{"cfgZvtxMax", 10.0f, "Maximum primary vertex cut applied for the events."}; + Configurable cfgMultMin{"cfgMultMin", 10, "Minimum number of particles required for the event to have."}; + } cfgEventCuts; + + // // Filters to be applied to the received data. + // // The analysis assumes the data has been subjected to a QA of its selection, + // // and thus only the final distributions of the data for analysis are saved. + o2::framework::expressions::Filter collFilter = (nabs(aod::collision::posZ) < cfgEventCuts.cfgZvtxMax); + o2::framework::expressions::Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); + o2::framework::expressions::Filter cftrackFilter = (aod::cftrack::pt > cfgTrackCuts.cfgPtMin) && (aod::cftrack::pt < cfgTrackCuts.cfgPtMax); // eta cuts done by jfluc + + // Connect to ccdb + Service ccdb; + + struct Config { + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance; + bool correctionsLoaded = false; + } cfg; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + HistogramRegistry registry{"registry"}; + + std::unique_ptr fGFW{std::make_unique()}; + std::unique_ptr fRndm{std::make_unique(0)}; + std::unique_ptr fSecondAxis{nullptr}; + std::vector corrconfigs; + int lastRun = -1; + + // region indices for consistency flag + int posRegionIndex = -1; + int negRegionIndex = -1; + int fullRegionIndex = -1; + int midRegionIndex = -1; + // PID + + struct PIDState { + o2::aod::ITSResponse itsResponse; + std::array tofNsigmaCut; + std::array itsNsigmaCut; + std::array tpcNsigmaCut; + TH1D* hPtMid[4] = {nullptr, nullptr, nullptr, nullptr}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt axis for histograms"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {80, -5, 5}, "nsigmaTPC axis"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"}; + ConfigurableAxis axisNsigmaITS{"axisNsigmaITS", {80, -5, 5}, "nsigmaITS axis"}; + ConfigurableAxis axisTpcSignal{"axisTpcSignal", {250, 0, 250}, "dEdx axis for TPC"}; + }; + PIDState pidStates; + + using GFWTracks = soa::Filtered>; + + enum PIDIndex { + PidCharged = 0, + PidPions, + PidKaons, + PidProtons + }; + enum PiKpArrayIndex { + IndPionUp = 0, + IndKaonUp, + IndProtonUp, + IndPionLow, + IndKaonLow, + IndProtonLow + }; + enum DetectorType { + kTPC = 0, + kTOF, + kITS + }; + + void init(InitContext const&) + { + + pidStates.tpcNsigmaCut[IndPionUp] = nSigmas->getData()[IndPionUp][kTPC]; + pidStates.tpcNsigmaCut[IndKaonUp] = nSigmas->getData()[IndKaonUp][kTPC]; + pidStates.tpcNsigmaCut[IndProtonUp] = nSigmas->getData()[IndProtonUp][kTPC]; + pidStates.tpcNsigmaCut[IndPionLow] = nSigmas->getData()[IndPionLow][kTPC]; + pidStates.tpcNsigmaCut[IndKaonLow] = nSigmas->getData()[IndKaonLow][kTPC]; + pidStates.tpcNsigmaCut[IndProtonLow] = nSigmas->getData()[IndProtonLow][kTPC]; + + pidStates.tofNsigmaCut[IndPionUp] = nSigmas->getData()[IndPionUp][kTOF]; + pidStates.tofNsigmaCut[IndKaonUp] = nSigmas->getData()[IndKaonUp][kTOF]; + pidStates.tofNsigmaCut[IndProtonUp] = nSigmas->getData()[IndProtonUp][kTOF]; + pidStates.tofNsigmaCut[IndPionLow] = nSigmas->getData()[IndPionLow][kTOF]; + pidStates.tofNsigmaCut[IndKaonLow] = nSigmas->getData()[IndKaonLow][kTOF]; + pidStates.tofNsigmaCut[IndProtonLow] = nSigmas->getData()[IndProtonLow][kTOF]; + + pidStates.itsNsigmaCut[IndPionUp] = nSigmas->getData()[IndPionUp][kITS]; + pidStates.itsNsigmaCut[IndKaonUp] = nSigmas->getData()[IndKaonUp][kITS]; + pidStates.itsNsigmaCut[IndProtonUp] = nSigmas->getData()[IndProtonUp][kITS]; + pidStates.itsNsigmaCut[IndPionLow] = nSigmas->getData()[IndPionLow][kITS]; + pidStates.itsNsigmaCut[IndKaonLow] = nSigmas->getData()[IndKaonLow][kITS]; + pidStates.itsNsigmaCut[IndProtonLow] = nSigmas->getData()[IndProtonLow][kITS]; + + if (cfgGetNsigmaQA) { + if (!cfgUseItsPID) { + registry.add("TofTpcNsigma_before", "", {HistType::kTHnSparseD, {{pidStates.axisNsigmaTPC, pidStates.axisNsigmaTOF, pidStates.axisPt}}}); + registry.add("TofTpcNsigma_after", "", {HistType::kTHnSparseD, {{pidStates.axisNsigmaTPC, pidStates.axisNsigmaTOF, pidStates.axisPt}}}); + } + if (cfgUseItsPID) { + registry.add("TofItsNsigma_before", "", {HistType::kTHnSparseD, {{pidStates.axisNsigmaITS, pidStates.axisNsigmaTOF, pidStates.axisPt}}}); + registry.add("TofItsNsigma_after", "", {HistType::kTHnSparseD, {{pidStates.axisNsigmaITS, pidStates.axisNsigmaTOF, pidStates.axisPt}}}); + } + + registry.add("TpcdEdx_ptwise", "", {HistType::kTH2D, {{pidStates.axisTpcSignal, pidStates.axisPt}}}); + registry.add("TpcdEdx_ptwise_afterCut", "", {HistType::kTH2D, {{pidStates.axisTpcSignal, pidStates.axisPt}}}); + } + + o2::analysis::gfw::regions.SetNames(cfgRegions->GetNames()); + o2::analysis::gfw::regions.SetEtaMin(cfgRegions->GetEtaMin()); + o2::analysis::gfw::regions.SetEtaMax(cfgRegions->GetEtaMax()); + o2::analysis::gfw::regions.SetpTDifs(cfgRegions->GetpTDifs()); + o2::analysis::gfw::regions.SetBitmasks(cfgRegions->GetBitmasks()); + o2::analysis::gfw::configs.SetCorrs(cfgCorrConfig->GetCorrs()); + o2::analysis::gfw::configs.SetHeads(cfgCorrConfig->GetHeads()); + o2::analysis::gfw::configs.SetpTDifs(cfgCorrConfig->GetpTDifs()); + o2::analysis::gfw::configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); + o2::analysis::gfw::regions.Print(); + o2::analysis::gfw::configs.Print(); + o2::analysis::gfw::ptbinning = cfgGFWBinning->GetPtBinning(); + o2::analysis::gfw::ptpoilow = cfgGFWBinning->GetPtPOImin(); + o2::analysis::gfw::ptpoiup = cfgGFWBinning->GetPtPOImax(); + o2::analysis::gfw::ptreflow = cfgGFWBinning->GetPtRefMin(); + o2::analysis::gfw::ptrefup = cfgGFWBinning->GetPtRefMax(); + o2::analysis::gfw::ptlow = cfgTrackCuts.cfgPtMin; + o2::analysis::gfw::ptup = cfgTrackCuts.cfgPtMax; + o2::analysis::gfw::etabins = cfgGFWBinning->GetEtaBins(); + o2::analysis::gfw::vtxZbins = cfgGFWBinning->GetVtxZbins(); + o2::analysis::gfw::phibins = cfgGFWBinning->GetPhiBins(); + o2::analysis::gfw::philow = 0.0f; + o2::analysis::gfw::phiup = o2::constants::math::TwoPI; + o2::analysis::gfw::nchbins = cfgGFWBinning->GetNchBins(); + o2::analysis::gfw::nchlow = cfgGFWBinning->GetNchMin(); + o2::analysis::gfw::nchup = cfgGFWBinning->GetNchMax(); + o2::analysis::gfw::centbinning = cfgGFWBinning->GetCentBinning(); + cfgGFWBinning->Print(); + + // Initialise pt spectra histograms for different particles + pidStates.hPtMid[PidCharged] = new TH1D("hPtMid_charged", "hPtMid_charged", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtMid[PidPions] = new TH1D("hPtMid_pions", "hPtMid_pions", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtMid[PidKaons] = new TH1D("hPtMid_kaons", "hPtMid_kaons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtMid[PidProtons] = new TH1D("hPtMid_protons", "hPtMid_protons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtMid[PidCharged]->SetDirectory(nullptr); + pidStates.hPtMid[PidPions]->SetDirectory(nullptr); + pidStates.hPtMid[PidKaons]->SetDirectory(nullptr); + pidStates.hPtMid[PidProtons]->SetDirectory(nullptr); + + AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; + AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgTrackCuts.cfgEtaMax, cfgTrackCuts.cfgEtaMax, "#eta"}; + AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgEventCuts.cfgZvtxMax, cfgEventCuts.cfgZvtxMax, "Vtx_{z} (cm)"}; + AxisSpec ptAxis = {o2::analysis::gfw::ptbinning, "#it{p}_{T} GeV/#it{c}"}; + + std::string sCentralityEstimator = "FT0C centrality (%)"; + AxisSpec centAxis = {o2::analysis::gfw::centbinning, sCentralityEstimator.c_str()}; + + std::vector nchbinning; + int nchskip = (o2::analysis::gfw::nchup - o2::analysis::gfw::nchlow) / o2::analysis::gfw::nchbins; + for (int i = 0; i <= o2::analysis::gfw::nchbins; ++i) { + nchbinning.push_back(nchskip * i + o2::analysis::gfw::nchlow + 0.5); + } + AxisSpec nchAxis = {nchbinning, "N_{ch}"}; + registry.add("v02pt", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + registry.add("nchMid", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + int ptbins = o2::analysis::gfw::ptbinning.size() - 1; + fSecondAxis = std::make_unique(ptbins, &o2::analysis::gfw::ptbinning[0]); + + // QA histograms + registry.add("trackQA/before/phi_eta_vtxZ", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("trackQA/before/nch_pt", "#it{p}_{T} vs multiplicity; N_{ch}; #it{p}_{T}", {HistType::kTH2D, {nchAxis, ptAxis}}); + registry.addClone("trackQA/before/", "trackQA/after/"); + registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptreflow, o2::analysis::gfw::ptrefup}}}); + registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoiup}}}); + + registry.add("eventQA/before/multiplicity", "", {HistType::kTH1D, {nchAxis}}); + registry.add("eventQA/before/centrality", "", {HistType::kTH1D, {centAxis}}); + registry.addClone("eventQA/before/", "eventQA/after/"); + + if (o2::analysis::gfw::regions.GetSize() < 0) + LOGF(error, "Configuration contains vectors of different size - check the GFWRegions configurable"); + for (auto i(0); i < o2::analysis::gfw::regions.GetSize(); ++i) { + fGFW->AddRegion(o2::analysis::gfw::regions.GetNames()[i], o2::analysis::gfw::regions.GetEtaMin()[i], o2::analysis::gfw::regions.GetEtaMax()[i], (o2::analysis::gfw::regions.GetpTDifs()[i]) ? ptbins + 1 : 1, o2::analysis::gfw::regions.GetBitmasks()[i]); + } + for (auto i = 0; i < o2::analysis::gfw::configs.GetSize(); ++i) { + corrconfigs.push_back(fGFW->GetCorrelatorConfig(o2::analysis::gfw::configs.GetCorrs()[i], o2::analysis::gfw::configs.GetHeads()[i], o2::analysis::gfw::configs.GetpTDifs()[i])); + } + if (corrconfigs.empty()) + LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); + fGFW->CreateRegions(); + TObjArray* oba = new TObjArray(); + addConfigObjectsToObjArray(oba, corrconfigs); + LOGF(info, "Number of correlators: %d", oba->GetEntries()); + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fSecondAxis.get()); + fFC->Initialize(oba, centAxis, cfgNbootstrap); + delete oba; + + if (cfgConsistentEventFlag) { + posRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refP"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + negRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refN"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + fullRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refFull"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + midRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refMid"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + } + } + + static constexpr std::string_view FillTimeName[] = {"before/", "after/"}; + enum QAFillTime { + kBefore, + kAfter + }; + + void addConfigObjectsToObjArray(TObjArray* oba, const std::vector& configs) + { + for (auto it = configs.begin(); it != configs.end(); ++it) { + if (it->pTDif) { + std::string suffix = "_ptDiff"; + for (auto i = 0; i < fSecondAxis->GetNbins(); ++i) { + std::string index = Form("_pt_%i", i + 1); + oba->Add(new TNamed(it->Head.c_str() + index, it->Head.c_str() + suffix)); + } + } else { + oba->Add(new TNamed(it->Head.c_str(), it->Head.c_str())); + } + } + } + + template + int getNsigmaPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {pidStates.itsResponse.nSigmaITS(track), pidStates.itsResponse.nSigmaITS(track), pidStates.itsResponse.nSigmaITS(track)}; + int pid = -1; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton + + std::array nSigmaToUse = cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::array detectorNsigmaCut = cfgUseItsPID ? pidStates.itsNsigmaCut : pidStates.tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + + bool isPion, isKaon, isProton; + bool isDetectedPion = nSigmaToUse[IndPionUp] < detectorNsigmaCut[IndPionUp] && nSigmaToUse[IndPionUp] > detectorNsigmaCut[IndPionLow]; + bool isDetectedKaon = nSigmaToUse[IndKaonUp] < detectorNsigmaCut[IndKaonUp] && nSigmaToUse[IndKaonUp] > detectorNsigmaCut[IndKaonLow]; + bool isDetectedProton = nSigmaToUse[IndProtonUp] < detectorNsigmaCut[IndProtonUp] && nSigmaToUse[IndProtonUp] > detectorNsigmaCut[IndProtonLow]; + + bool isTofPion = nSigmaTOF[IndPionUp] < pidStates.tofNsigmaCut[IndPionUp] && nSigmaTOF[IndPionUp] > pidStates.tofNsigmaCut[IndPionLow]; + bool isTofKaon = nSigmaTOF[IndKaonUp] < pidStates.tofNsigmaCut[IndKaonUp] && nSigmaTOF[IndKaonUp] > pidStates.tofNsigmaCut[IndKaonLow]; + bool isTofProton = nSigmaTOF[IndProtonUp] < pidStates.tofNsigmaCut[IndProtonUp] && nSigmaTOF[IndProtonUp] > pidStates.tofNsigmaCut[IndProtonLow]; + + if (track.pt() > cfgTofPtCut && !track.hasTOF()) { + return -1; + } else if (track.pt() > cfgTofPtCut && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return -1; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = PidPions; + } else if (isKaon) { + pid = PidKaons; + } else if (isProton) { + pid = PidProtons; + } else { + return -1; // no particle satisfies the criteria + } + + return pid; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton + } + + void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) + { + uint64_t timestamp = bc.timestamp(); + if (cfg.correctionsLoaded) + return; + if (!cfgAcceptance.value.empty()) { + cfg.mAcceptance = ccdb->getForRun(cfgAcceptance.value, timestamp); + } + if (!cfgEfficiency.value.empty()) { + cfg.mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (cfg.mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram from %s", cfgEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)cfg.mEfficiency); + } + cfg.correctionsLoaded = true; + } + + void loadCorrections(int runnumber) + { + if (cfg.correctionsLoaded) + return; + if (!cfgAcceptance.value.empty()) { + cfg.mAcceptance = ccdb->getForRun(cfgAcceptance.value, runnumber); + } + if (!cfgEfficiency.value.empty()) { + cfg.mEfficiency = ccdb->getForRun(cfgEfficiency.value, runnumber); + } + cfg.correctionsLoaded = true; + } + + template + double getAcceptance(TTrack track, const double& /*vtxz*/, const int& /*pidInd*/ = 0) + { + double wacc = 1; + if constexpr (requires { track.weightNUA(); }) + wacc = 1. / track.weightNUA(); + return wacc; + } + + template + double getEfficiency(TTrack track, const int& /*pidInd*/ = 0) + { + double eff = 1.; + if constexpr (requires { track.weightEff(); }) + eff = track.weightEff(); + return eff; + } + + // Define the data type + enum DataType { + kReco, + kGen + }; + + int getPIDIndex(const std::string& corrconfig) + { + if (boost::ifind_first(corrconfig, "pi")) + return PidPions; + if (boost::ifind_first(corrconfig, "ka")) + return PidKaons; + if (boost::ifind_first(corrconfig, "pr")) + return PidProtons; + return PidCharged; + } + + GFW::CorrConfig getRelevantCorrName(const int& pidInd) + { + if (pidInd == PidPions) + return fGFW->GetCorrelatorConfig("piP {2} refN {-2}", "PiGap22", kFALSE); + if (pidInd == PidKaons) + return fGFW->GetCorrelatorConfig("kaP {2} refN {-2}", "KaGap22", kFALSE); + if (pidInd == PidProtons) + return fGFW->GetCorrelatorConfig("prP {2} refN {-2}", "PrGap22", kFALSE); + return fGFW->GetCorrelatorConfig("refP {2} refN {-2}", "ChGap22", kFALSE); + } + + template + void fillOutputContainers(const float& centmult, const double& rndm, const int& /*run*/ = 0) + { + for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { + if (!corrconfigs.at(l_ind).pTDif) { + auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), 0, kTRUE).real(); + if (dnx == 0) + continue; + auto val = fGFW->Calculate(corrconfigs.at(l_ind), 0, kFALSE).real() / dnx; + + if (std::abs(val) < 1) { + fFC->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm); + } + continue; + } + + // Fill pt profiles for different particles + int pidInd = getPIDIndex(corrconfigs.at(l_ind).Head.c_str()); + + // Find the corresponding non-pT-differential correlation configuration + GFW::CorrConfig corrName = getRelevantCorrName(pidInd); // May be used later for QA + + auto dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); + if (dnx == 0) + continue; + auto val = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnx; + double ebyeWeight = (cfgUseMultiplicityFlowWeights) ? dnx : 1.0; + for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { + if (corrconfigs.at(l_ind).Head.find("nch") != std::string::npos) { + ebyeWeight = 1.0; + val = 1.0; + } + double ptFraction = 0; + int normIndex = (cfgNormalizeByCharged) ? PidCharged : pidInd; // Configured to normalize by charged particles or the selected particle + if (pidStates.hPtMid[normIndex]->Integral() > 0) { + ptFraction = pidStates.hPtMid[pidInd]->GetBinContent(i) / pidStates.hPtMid[normIndex]->Integral(); + if (std::abs(val) < 1.01) + fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val * ptFraction, ebyeWeight, rndm); + } + } + } + // Fill the profiles for each pT bin + // printf("Config name: %s\n", corrconfigs.at(0).Head.c_str()); + auto dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); + if (dnx == 0) + return; + auto val = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnx; + for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { + double ptFraction = 0; + if (pidStates.hPtMid[PidCharged]->Integral() > 0) { + ptFraction = pidStates.hPtMid[PidCharged]->GetBinContent(i) / pidStates.hPtMid[PidCharged]->Integral(); + if (std::abs(val) < 1) + registry.fill(HIST("v02pt"), fSecondAxis->GetBinCenter(i), centmult, val * ptFraction, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0); + // printf("bincenter hPtMid: %f, fsecondaxis: %f\n", hPtMid->GetBinCenter(i), fSecondAxis->GetBinCenter(i)); + registry.fill(HIST("nchMid"), fSecondAxis->GetBinCenter(i), centmult, ptFraction); + } + } + return; + } + + struct XAxis { + float centrality; + int64_t multiplicity; + double time; + }; + + struct AcceptedTracks { + int nPos; + int nNeg; + int nFull; + int nMid; + }; + + template + void processCollision(TCollision collision, TTracks tracks, const XAxis& xaxis, const int& run) + { + float vtxz = collision.posZ(); + if (tracks.size() < 1) + return; + if (xaxis.centrality >= 0 && (xaxis.centrality < o2::analysis::gfw::centbinning.front() || xaxis.centrality > o2::analysis::gfw::centbinning.back())) + return; + if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) + return; + fGFW->Clear(); + pidStates.hPtMid[PidCharged]->Reset(); + pidStates.hPtMid[PidPions]->Reset(); + pidStates.hPtMid[PidKaons]->Reset(); + pidStates.hPtMid[PidProtons]->Reset(); + + float lRandom = fRndm->Rndm(); + + // Loop over tracks and check if they are accepted + AcceptedTracks acceptedTracks{0, 0, 0, 0}; + for (const auto& track : tracks) { + processTrack(track, vtxz, xaxis.multiplicity, run, acceptedTracks); + pidStates.hPtMid[PidCharged]->Fill(track.pt(), getEfficiency(track)); + // If PID is identified, fill pt spectrum for the corresponding particle + int pidInd = getNsigmaPID(track); + if (pidInd != -1 && track.eta() > -0.4 && track.eta() < 0.4) { + pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); + } + } + if (cfgConsistentEventFlag & 1) + if (!acceptedTracks.nPos || !acceptedTracks.nNeg) + return; + if (cfgConsistentEventFlag & 2) + if (acceptedTracks.nFull < 4) // o2-linter: disable=magic-number (at least four tracks in full acceptance) + return; + if (cfgConsistentEventFlag & 4) + if (acceptedTracks.nPos < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in each subevent) + return; + if (cfgConsistentEventFlag & 8) + if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in all three subevents) + return; + // Fill output containers + fillOutputContainers
(xaxis.centrality, lRandom, run); + } + + template + void fillAcceptedTracks(TTrack track, AcceptedTracks& acceptedTracks) + { + if (posRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[posRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[posRegionIndex]) + ++acceptedTracks.nPos; + if (negRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[negRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[negRegionIndex]) + ++acceptedTracks.nNeg; + if (fullRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[fullRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[fullRegionIndex]) + ++acceptedTracks.nFull; + if (midRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[midRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[midRegionIndex]) + ++acceptedTracks.nMid; + } + + template + inline void processTrack(TTrack const& track, const float& vtxz, const int& multiplicity, const int& /*run*/, AcceptedTracks& acceptedTracks) + { + // fillPtSums(track); // Fill pT sums + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/before/nch_pt"), multiplicity, track.pt()); + + fillGFW(track, vtxz); // Fill GFW + fillAcceptedTracks(track, acceptedTracks); // Fill accepted tracks + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/after/nch_pt"), multiplicity, track.pt()); + } + + template + inline void fillGFW(TTrack track, const double& vtxz) + { + int pidInd = getNsigmaPID(track); + + bool withinPtRef = (track.pt() > o2::analysis::gfw::ptreflow && track.pt() < o2::analysis::gfw::ptrefup); + bool withinPtPOI = (track.pt() > o2::analysis::gfw::ptpoilow && track.pt() < o2::analysis::gfw::ptpoiup); + + if (!withinPtPOI && !withinPtRef) + return; + double weff = getEfficiency(track, pidInd); + if (weff < 0) + return; + + double wacc = getAcceptance(track, vtxz, pidInd); + + // Fill cumulants for different particles + // ***Need to add proper weights for each particle!*** + if (withinPtRef) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 0); + if (withinPtPOI && pidInd == PidPions) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidPions); + if (withinPtPOI && pidInd == PidKaons) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidKaons); + if (withinPtPOI && pidInd == PidProtons) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidProtons); + return; + } + + template + inline void fillTrackQA(TTrack track, const float vtxz) + { + double wacc = getAcceptance(track, vtxz); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("phi_eta_vtxZ"), track.phi(), track.eta(), vtxz, (ft == kAfter) ? wacc : 1.0); + if (ft == kAfter) { + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("pt_ref"), track.pt()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("pt_poi"), track.pt()); + } + return; + } + + double getTimeSinceStartOfFill(uint64_t, int) { return 0.0; } + + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, GFWTracks const& tracks) + { + auto bc = collision.bc_as(); + int run = bc.runNumber(); + if (run != lastRun) { + lastRun = run; + LOGF(info, "run = %d", run); + } + + loadCorrections(bc); + const XAxis xaxis{collision.centFT0C(), tracks.size(), -1.0}; + processCollision(collision, tracks, xaxis, run); + } + PROCESS_SWITCH(FlowGfwV02, processData, "Process analysis for non-derived data", true); + + void processCFDerived(aod::CFCollision const& collision, soa::Filtered const& tracks) + { + int run = collision.runNumber(); + if (run != lastRun) { + lastRun = run; + LOGF(info, "run = %d", run); + } + loadCorrections(run); + const XAxis xaxis{collision.multiplicity(), tracks.size(), -1.0}; + + registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); + registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); + + // processCollision(collision, tracks, xaxis, run); + } + PROCESS_SWITCH(FlowGfwV02, processCFDerived, "Process analysis for CF derived data", false); + void processCFDerivedCorrected(aod::CFCollision const& collision, soa::Filtered> const& tracks) + { + int run = collision.runNumber(); + if (run != lastRun) { + lastRun = run; + LOGF(info, "run = %d", run); + } + const XAxis xaxis{collision.multiplicity(), tracks.size(), -1.0}; + registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); + registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); + // processCollision(collision, tracks, xaxis, run); + } + PROCESS_SWITCH(FlowGfwV02, processCFDerivedCorrected, "Process analysis for CF derived data with corrections", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index 111e1f8e92b..380de913181 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -8,15 +8,19 @@ // 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 Task for the calculation of SPC with filtered data. -// \author Maxim Virta (maxim.virta@cern.ch), Cindy Mordasini (cindy.mordasini@cern.ch) +/// +/// \file flowJSPCAnalysis.cxx +/// \brief Task for the calculation of SPC with filtered data. +/// \author Maxim Virta (maxim.virta@cern.ch), Cindy Mordasini (cindy.mordasini@cern.ch), Neelkamal Mallick (neelkamal.mallick@cern.ch) // Standard headers. +#include +#include + #include +#include #include #include -#include // O2 headers. // // The first two are mandatory. @@ -46,6 +50,8 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + using MyCollisions = soa::Join().weightNUA()); template using HasWeightEff = decltype(std::declval().weightEff()); + template + using HasTrackType = decltype(std::declval().trackType()); HistogramRegistry qaHistRegistry{"qaHistRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; FlowJHistManager histManager; @@ -84,12 +92,20 @@ struct flowJSPCAnalysis { Configurable cfgMultMin{"cfgMultMin", 10, "Minimum number of particles required for the event to have."}; } cfgEventCuts; + O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint16_t, 0, "Track selection bitmask to use as defined in the filterCorrelations.cxx task"); + O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.") + O2_DEFINE_CONFIGURABLE(cfgMultCutFormula, std::string, "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity, [cFT0M] FT0M centrality") + // // Filters to be applied to the received data. // // The analysis assumes the data has been subjected to a QA of its selection, // // and thus only the final distributions of the data for analysis are saved. Filter collFilter = (nabs(aod::collision::posZ) < cfgEventCuts.cfgZvtxMax); + Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); - Filter cftrackFilter = (aod::cftrack::pt > cfgTrackCuts.cfgPtMin) && (aod::cftrack::pt < cfgTrackCuts.cfgPtMax); // eta cuts done by jfluc + Filter cftrackFilter = (nabs(aod::cftrack::eta) < cfgTrackCuts.cfgEtaMax) && (aod::cftrack::pt > cfgTrackCuts.cfgPtMin) && (aod::cftrack::pt < cfgTrackCuts.cfgPtMax) && ncheckbit(aod::track::trackType, as(cfgTrackBitMask)); + + std::unique_ptr multCutFormula; + std::array multCutFormulaParamIndex; void init(InitContext const&) { @@ -103,6 +119,26 @@ struct flowJSPCAnalysis { histManager.setHistRegistryQA(&qaHistRegistry); histManager.setDebugLog(false); histManager.createHistQA(); + + if (!cfgMultCutFormula.value.empty()) { + multCutFormula = std::make_unique("multCutFormula", cfgMultCutFormula.value.c_str()); + std::fill_n(multCutFormulaParamIndex.begin(), std::size(multCutFormulaParamIndex), ~0u); + std::array pars = {"cFT0C", "mFV0A", "mPV", "mGlob", "cFT0M"}; // must correspond the order of MultiplicityEstimators + for (uint i = 0, n = multCutFormula->GetNpar(); i < n; ++i) { + auto m = std::find(pars.begin(), pars.end(), multCutFormula->GetParName(i)); + if (m == pars.end()) { + LOGF(warning, "Unknown parameter in cfgMultCutFormula: %s", multCutFormula->GetParName(i)); + continue; + } + const uint estIdx = std::distance(pars.begin(), m); + if ((cfgMultCorrelationsMask.value & (1u << estIdx)) == 0) { + LOGF(warning, "The centrality/multiplicity estimator %s is not available to be used in cfgMultCutFormula. Ensure cfgMultCorrelationsMask is correct and matches the CFMultSets in derived data.", m->c_str()); + } else { + multCutFormulaParamIndex[estIdx] = i; + LOGF(info, "Multiplicity cut parameter %s in use.", m->c_str()); + } + } + } } template @@ -119,6 +155,7 @@ struct flowJSPCAnalysis { int cBin = histManager.getCentBin(cent); spcHistograms.fill(HIST("FullCentrality"), cent); int nTracks = tracks.size(); + double wNUA = 1.0; double wEff = 1.0; for (const auto& track : tracks) { @@ -135,6 +172,11 @@ struct flowJSPCAnalysis { if constexpr (std::experimental::is_detected::value) { spcAnalysis.fillQAHistograms(cBin, track.phi(), 1. / track.weightNUA()); } + if constexpr (std::experimental::is_detected::value) { + if (track.trackType() != cfgTrackBitMask.value) { + LOGF(warning, "trackType %d (expected %d) is passed to the analysis", track.trackType(), cfgTrackBitMask.value); + } + } } } @@ -146,6 +188,20 @@ struct flowJSPCAnalysis { spcAnalysis.calculateCorrelators(cBin); } + template + bool passOutlier(CollType const& collision) + { + if (cfgMultCutFormula.value.empty()) + return true; + for (uint i = 0; i < aod::cfmultset::NMultiplicityEstimators; ++i) { + if ((cfgMultCorrelationsMask.value & (1u << i)) == 0 || multCutFormulaParamIndex[i] == ~0u) + continue; + auto estIndex = std::popcount(static_cast(cfgMultCorrelationsMask.value & ((1u << i) - 1))); + multCutFormula->SetParameter(multCutFormulaParamIndex[i], collision.multiplicities()[estIndex]); + } + return multCutFormula->Eval() > 0.0f; + } + void processJDerived(aod::JCollision const& collision, soa::Filtered const& tracks) { analyze(collision, tracks); @@ -164,11 +220,21 @@ struct flowJSPCAnalysis { } PROCESS_SWITCH(flowJSPCAnalysis, processCFDerived, "Process CF derived data", false); - void processCFDerivedCorrected(aod::CFCollision const& collision, soa::Filtered> const& tracks) + void processCFDerivedCorrected(soa::Filtered::iterator const& collision, soa::Filtered> const& tracks) { analyze(collision, tracks); } PROCESS_SWITCH(flowJSPCAnalysis, processCFDerivedCorrected, "Process CF derived data with corrections", true); + + void processCFDerivedMultSetCorrected(soa::Filtered>::iterator const& collision, soa::Filtered> const& tracks) + { + if (std::popcount(static_cast(cfgMultCorrelationsMask.value)) != static_cast(collision.multiplicities().size())) + LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld).", cfgMultCorrelationsMask.value, collision.multiplicities().size()); + if (!passOutlier(collision)) + return; + analyze(collision, tracks); + } + PROCESS_SWITCH(flowJSPCAnalysis, processCFDerivedMultSetCorrected, "Process CF derived data with corrections and multiplicity sets", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx b/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx index c7e2386d409..5a85b8eb58e 100644 --- a/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx @@ -76,6 +76,7 @@ struct jEPFlowAnalysis { Configurable cfgEffCor{"cfgEffCor", false, "flag for efficiency correction"}; Configurable cfgEffCorDir{"cfgEffCorDir", "Users/n/nmallick/Run3OO/Eff/LHC25h3b_FT0C", "path for efficiency correction"}; + Configurable cfgTrkSelFlag{"cfgTrkSelFlag", true, "flag for track selection"}; Configurable cfgSystStudy{"cfgSystStudy", false, "flag for syst study"}; Configurable cfgITSNCls{"cfgITSNCls", 5, "minimum number of its clusters"}; Configurable cfgTPCNclsCR{"cfgTPCNclsCR", 70, "minimum number of tpc cluster crossed rows"}; @@ -117,6 +118,8 @@ struct jEPFlowAnalysis { int currentRunNumber = -999; int lastRunNumber = -999; + float cent; + std::vector shiftprofile{}; std::string fullCCDBShiftCorrPath; @@ -144,6 +147,37 @@ struct jEPFlowAnalysis { } } + template + bool eventSel(const Col& coll) + { + if (std::abs(coll.posZ()) > cfgVertexZ) + return false; + switch (cfgEvtSel) { + case 0: // Sel8 + if (!coll.sel8()) + return false; + break; + case 1: // PbPb standard + if (!coll.sel8() || !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + break; + case 2: // PbPb with pileup + if (!coll.sel8() || !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) || + !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + break; + case 3: // Small systems (OO, NeNe, pp) + if (!coll.sel8() || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + break; + } + // Check occupancy + if (coll.trackOccupancyInTimeRange() > cfgMaxOccupancy || coll.trackOccupancyInTimeRange() < cfgMinOccupancy) + return false; + + return true; + } + template uint8_t trackSel(const Trk& track) { @@ -173,6 +207,97 @@ struct jEPFlowAnalysis { return tracksel; } + template + void fillvn(const Col& coll, const Trk& tracks) + { + float eps[3] = {0.}; + float qx_shifted[3] = {0.}; + float qy_shifted[3] = {0.}; + + for (int i = 0; i < cfgnMode; i++) { // loop over different harmonic orders + harmInd = cfgnTotalSystem * 4 * (i) + 3; // harmonic index to access corresponding Q-vector as all Q-vectors are in same vector + eps[0] = helperEP.GetEventPlane(coll.qvecRe()[4 * detId + harmInd], coll.qvecIm()[4 * detId + harmInd], i + 2); + eps[1] = helperEP.GetEventPlane(coll.qvecRe()[4 * refAId + harmInd], coll.qvecIm()[4 * refAId + harmInd], i + 2); + eps[2] = helperEP.GetEventPlane(coll.qvecRe()[4 * refBId + harmInd], coll.qvecIm()[4 * refBId + harmInd], i + 2); + + auto deltapsiDet = 0.0; + auto deltapsiRefA = 0.0; + auto deltapsiRefB = 0.0; + + float weight = 1.0; + + qx_shifted[0] = coll.qvecRe()[4 * detId + harmInd]; + qy_shifted[0] = coll.qvecIm()[4 * detId + harmInd]; + qx_shifted[1] = coll.qvecRe()[4 * refAId + harmInd]; + qy_shifted[1] = coll.qvecIm()[4 * refAId + harmInd]; + qx_shifted[2] = coll.qvecRe()[4 * refBId + harmInd]; + qy_shifted[2] = coll.qvecIm()[4 * refBId + harmInd]; + + if (cfgManShiftCorr) { + constexpr int kShiftBins = 10; + for (int ishift = 1; ishift <= kShiftBins; ishift++) { + auto coeffshiftxDet = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * detId + 0.5, ishift - 0.5)); + auto coeffshiftyDet = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * detId + 1.5, ishift - 0.5)); + auto coeffshiftxRefA = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refAId + 0.5, ishift - 0.5)); + auto coeffshiftyRefA = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refAId + 1.5, ishift - 0.5)); + auto coeffshiftxRefB = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refBId + 0.5, ishift - 0.5)); + auto coeffshiftyRefB = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refBId + 1.5, ishift - 0.5)); + + deltapsiDet += ((2. / (1.0 * ishift)) * (-coeffshiftxDet * std::cos(ishift * static_cast(i + 2) * eps[0]) + coeffshiftyDet * std::sin(ishift * static_cast(i + 2) * eps[0]))) / static_cast(i + 2); + deltapsiRefA += ((2. / (1.0 * ishift)) * (-coeffshiftxRefA * std::cos(ishift * static_cast(i + 2) * eps[1]) + coeffshiftyRefA * std::sin(ishift * static_cast(i + 2) * eps[1]))) / static_cast(i + 2); + deltapsiRefB += ((2. / (1.0 * ishift)) * (-coeffshiftxRefB * std::cos(ishift * static_cast(i + 2) * eps[2]) + coeffshiftyRefB * std::sin(ishift * static_cast(i + 2) * eps[2]))) / static_cast(i + 2); + } + + eps[0] += deltapsiDet; + eps[1] += deltapsiRefA; + eps[2] += deltapsiRefB; + + qx_shifted[0] = coll.qvecRe()[4 * detId + harmInd] * std::cos(deltapsiDet) - coll.qvecIm()[4 * detId + harmInd] * std::sin(deltapsiDet); + qy_shifted[0] = coll.qvecRe()[4 * detId + harmInd] * std::sin(deltapsiDet) + coll.qvecIm()[4 * detId + harmInd] * std::cos(deltapsiDet); + qx_shifted[1] = coll.qvecRe()[4 * refAId + harmInd] * std::cos(deltapsiRefA) - coll.qvecIm()[4 * refAId + harmInd] * std::sin(deltapsiRefA); + qy_shifted[1] = coll.qvecRe()[4 * refAId + harmInd] * std::sin(deltapsiRefA) + coll.qvecIm()[4 * refAId + harmInd] * std::cos(deltapsiRefA); + qx_shifted[2] = coll.qvecRe()[4 * refBId + harmInd] * std::cos(deltapsiRefB) - coll.qvecIm()[4 * refBId + harmInd] * std::sin(deltapsiRefB); + qy_shifted[2] = coll.qvecRe()[4 * refBId + harmInd] * std::sin(deltapsiRefB) + coll.qvecIm()[4 * refBId + harmInd] * std::cos(deltapsiRefB); + } + float resNumA = helperEP.GetResolution(eps[0], eps[1], i + 2); + float resNumB = helperEP.GetResolution(eps[0], eps[2], i + 2); + float resDenom = helperEP.GetResolution(eps[1], eps[2], i + 2); + + epFlowHistograms.fill(HIST("EpDet"), i + 2, cent, eps[0]); + epFlowHistograms.fill(HIST("EpRefA"), i + 2, cent, eps[1]); + epFlowHistograms.fill(HIST("EpRefB"), i + 2, cent, eps[2]); + + epFlowHistograms.fill(HIST("EpResDetRefA"), i + 2, cent, resNumA); + epFlowHistograms.fill(HIST("EpResDetRefB"), i + 2, cent, resNumB); + epFlowHistograms.fill(HIST("EpResRefARefB"), i + 2, cent, resDenom); + + epFlowHistograms.fill(HIST("EpResQvecDetRefAxx"), i + 2, cent, qx_shifted[0] * qx_shifted[1] + qy_shifted[0] * qy_shifted[1]); + epFlowHistograms.fill(HIST("EpResQvecDetRefAxy"), i + 2, cent, qx_shifted[1] * qy_shifted[0] - qx_shifted[0] * qy_shifted[1]); + epFlowHistograms.fill(HIST("EpResQvecDetRefBxx"), i + 2, cent, qx_shifted[0] * qx_shifted[2] + qy_shifted[0] * qy_shifted[2]); + epFlowHistograms.fill(HIST("EpResQvecDetRefBxy"), i + 2, cent, qx_shifted[2] * qy_shifted[0] - qx_shifted[0] * qy_shifted[2]); + epFlowHistograms.fill(HIST("EpResQvecRefARefBxx"), i + 2, cent, qx_shifted[1] * qx_shifted[2] + qy_shifted[1] * qy_shifted[2]); + epFlowHistograms.fill(HIST("EpResQvecRefARefBxy"), i + 2, cent, qx_shifted[2] * qy_shifted[1] - qx_shifted[1] * qy_shifted[2]); + + for (const auto& track : tracks) { + if (cfgTrkSelFlag && trackSel(track)) + continue; + + if (cfgEffCor) { + weight = getEfficiencyCorrection(effMap, track.eta(), track.pt(), cent, coll.posZ()); + } + + float vn = std::cos((i + 2) * (track.phi() - eps[0])); + float vnSin = std::sin((i + 2) * (track.phi() - eps[0])); + + epFlowHistograms.fill(HIST("vncos"), i + 2, cent, track.pt(), vn, weight); + epFlowHistograms.fill(HIST("vnsin"), i + 2, cent, track.pt(), vnSin, weight); + + epFlowHistograms.fill(HIST("SPvnxx"), i + 2, cent, track.pt(), (std::cos(track.phi() * static_cast(i + 2)) * qx_shifted[0] + std::sin(track.phi() * static_cast(i + 2)) * qy_shifted[0]), weight); + epFlowHistograms.fill(HIST("SPvnxy"), i + 2, cent, track.pt(), (std::sin(track.phi() * static_cast(i + 2)) * qx_shifted[0] - std::cos(track.phi() * static_cast(i + 2)) * qy_shifted[0]), weight); + } + } + } + double getEfficiencyCorrection(THn* eff, float eta, float pt, float multiplicity, float posZ) { int effVars[4]; @@ -243,31 +368,7 @@ struct jEPFlowAnalysis { void processDefault(MyCollisions::iterator const& coll, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) { if (cfgAddEvtSel) { - if (std::abs(coll.posZ()) > cfgVertexZ) - return; - switch (cfgEvtSel) { - case 0: // Sel8 - if (!coll.sel8()) - return; - break; - case 1: // PbPb standard - if (!coll.sel8() || !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) - return; - break; - case 2: // PbPb with pileup - if (!coll.sel8() || !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) || - !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) - return; - break; - case 3: // Small systems (OO, NeNe, pp) - if (!coll.sel8() || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) - return; - break; - default: - LOGF(warning, "Event selection flag was not found, continuing without basic event selections!\n"); - } - // Check occupancy - if (coll.trackOccupancyInTimeRange() > cfgMaxOccupancy || coll.trackOccupancyInTimeRange() < cfgMinOccupancy) + if (!eventSel(coll)) return; } @@ -280,12 +381,9 @@ struct jEPFlowAnalysis { } } - float cent = coll.cent(); + cent = coll.cent(); epFlowHistograms.fill(HIST("hCentrality"), cent); epFlowHistograms.fill(HIST("hVertex"), coll.posZ()); - float eps[3] = {0.}; - float qx_shifted[3] = {0.}; - float qy_shifted[3] = {0.}; if (cfgManShiftCorr) { auto bc = coll.bc_as(); @@ -306,89 +404,7 @@ struct jEPFlowAnalysis { if (coll.qvecAmp()[detId] < 1e-5 || coll.qvecAmp()[refAId] < 1e-5 || coll.qvecAmp()[refBId] < 1e-5) return; - for (int i = 0; i < cfgnMode; i++) { // loop over different harmonic orders - harmInd = cfgnTotalSystem * 4 * (i) + 3; // harmonic index to access corresponding Q-vector as all Q-vectors are in same vector - eps[0] = helperEP.GetEventPlane(coll.qvecRe()[4 * detId + harmInd], coll.qvecIm()[4 * detId + harmInd], i + 2); - eps[1] = helperEP.GetEventPlane(coll.qvecRe()[4 * refAId + harmInd], coll.qvecIm()[4 * refAId + harmInd], i + 2); - eps[2] = helperEP.GetEventPlane(coll.qvecRe()[4 * refBId + harmInd], coll.qvecIm()[4 * refBId + harmInd], i + 2); - - auto deltapsiDet = 0.0; - auto deltapsiRefA = 0.0; - auto deltapsiRefB = 0.0; - - float weight = 1.0; - - qx_shifted[0] = coll.qvecRe()[4 * detId + harmInd]; - qy_shifted[0] = coll.qvecIm()[4 * detId + harmInd]; - qx_shifted[1] = coll.qvecRe()[4 * refAId + harmInd]; - qy_shifted[1] = coll.qvecIm()[4 * refAId + harmInd]; - qx_shifted[2] = coll.qvecRe()[4 * refBId + harmInd]; - qy_shifted[2] = coll.qvecIm()[4 * refBId + harmInd]; - - if (cfgManShiftCorr) { - constexpr int kShiftBins = 10; - for (int ishift = 1; ishift <= kShiftBins; ishift++) { - auto coeffshiftxDet = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * detId + 0.5, ishift - 0.5)); - auto coeffshiftyDet = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * detId + 1.5, ishift - 0.5)); - auto coeffshiftxRefA = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refAId + 0.5, ishift - 0.5)); - auto coeffshiftyRefA = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refAId + 1.5, ishift - 0.5)); - auto coeffshiftxRefB = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refBId + 0.5, ishift - 0.5)); - auto coeffshiftyRefB = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refBId + 1.5, ishift - 0.5)); - - deltapsiDet += ((2. / (1.0 * ishift)) * (-coeffshiftxDet * std::cos(ishift * static_cast(i + 2) * eps[0]) + coeffshiftyDet * std::sin(ishift * static_cast(i + 2) * eps[0]))) / static_cast(i + 2); - deltapsiRefA += ((2. / (1.0 * ishift)) * (-coeffshiftxRefA * std::cos(ishift * static_cast(i + 2) * eps[1]) + coeffshiftyRefA * std::sin(ishift * static_cast(i + 2) * eps[1]))) / static_cast(i + 2); - deltapsiRefB += ((2. / (1.0 * ishift)) * (-coeffshiftxRefB * std::cos(ishift * static_cast(i + 2) * eps[2]) + coeffshiftyRefB * std::sin(ishift * static_cast(i + 2) * eps[2]))) / static_cast(i + 2); - } - - eps[0] += deltapsiDet; - eps[1] += deltapsiRefA; - eps[2] += deltapsiRefB; - - qx_shifted[0] = coll.qvecRe()[4 * detId + harmInd] * std::cos(deltapsiDet) - coll.qvecIm()[4 * detId + harmInd] * std::sin(deltapsiDet); - qy_shifted[0] = coll.qvecRe()[4 * detId + harmInd] * std::sin(deltapsiDet) + coll.qvecIm()[4 * detId + harmInd] * std::cos(deltapsiDet); - qx_shifted[1] = coll.qvecRe()[4 * refAId + harmInd] * std::cos(deltapsiRefA) - coll.qvecIm()[4 * refAId + harmInd] * std::sin(deltapsiRefA); - qy_shifted[1] = coll.qvecRe()[4 * refAId + harmInd] * std::sin(deltapsiRefA) + coll.qvecIm()[4 * refAId + harmInd] * std::cos(deltapsiRefA); - qx_shifted[2] = coll.qvecRe()[4 * refBId + harmInd] * std::cos(deltapsiRefB) - coll.qvecIm()[4 * refBId + harmInd] * std::sin(deltapsiRefB); - qy_shifted[2] = coll.qvecRe()[4 * refBId + harmInd] * std::sin(deltapsiRefB) + coll.qvecIm()[4 * refBId + harmInd] * std::cos(deltapsiRefB); - } - - float resNumA = helperEP.GetResolution(eps[0], eps[1], i + 2); - float resNumB = helperEP.GetResolution(eps[0], eps[2], i + 2); - float resDenom = helperEP.GetResolution(eps[1], eps[2], i + 2); - - epFlowHistograms.fill(HIST("EpDet"), i + 2, cent, eps[0]); - epFlowHistograms.fill(HIST("EpRefA"), i + 2, cent, eps[1]); - epFlowHistograms.fill(HIST("EpRefB"), i + 2, cent, eps[2]); - - epFlowHistograms.fill(HIST("EpResDetRefA"), i + 2, cent, resNumA); - epFlowHistograms.fill(HIST("EpResDetRefB"), i + 2, cent, resNumB); - epFlowHistograms.fill(HIST("EpResRefARefB"), i + 2, cent, resDenom); - - epFlowHistograms.fill(HIST("EpResQvecDetRefAxx"), i + 2, cent, qx_shifted[0] * qx_shifted[1] + qy_shifted[0] * qy_shifted[1]); - epFlowHistograms.fill(HIST("EpResQvecDetRefAxy"), i + 2, cent, qx_shifted[1] * qy_shifted[0] - qx_shifted[0] * qy_shifted[1]); - epFlowHistograms.fill(HIST("EpResQvecDetRefBxx"), i + 2, cent, qx_shifted[0] * qx_shifted[2] + qy_shifted[0] * qy_shifted[2]); - epFlowHistograms.fill(HIST("EpResQvecDetRefBxy"), i + 2, cent, qx_shifted[2] * qy_shifted[0] - qx_shifted[0] * qy_shifted[2]); - epFlowHistograms.fill(HIST("EpResQvecRefARefBxx"), i + 2, cent, qx_shifted[1] * qx_shifted[2] + qy_shifted[1] * qy_shifted[2]); - epFlowHistograms.fill(HIST("EpResQvecRefARefBxy"), i + 2, cent, qx_shifted[2] * qy_shifted[1] - qx_shifted[1] * qy_shifted[2]); - - for (const auto& track : tracks) { - if (trackSel(track)) - continue; - - if (cfgEffCor) { - weight = getEfficiencyCorrection(effMap, track.eta(), track.pt(), cent, coll.posZ()); - } - - float vn = std::cos((i + 2) * (track.phi() - eps[0])); - float vnSin = std::sin((i + 2) * (track.phi() - eps[0])); - - epFlowHistograms.fill(HIST("vncos"), i + 2, cent, track.pt(), vn, weight); - epFlowHistograms.fill(HIST("vnsin"), i + 2, cent, track.pt(), vnSin, weight); - - epFlowHistograms.fill(HIST("SPvnxx"), i + 2, cent, track.pt(), (std::cos(track.phi() * static_cast(i + 2)) * qx_shifted[0] + std::sin(track.phi() * static_cast(i + 2)) * qy_shifted[0]), weight); - epFlowHistograms.fill(HIST("SPvnxy"), i + 2, cent, track.pt(), (std::sin(track.phi() * static_cast(i + 2)) * qx_shifted[0] - std::cos(track.phi() * static_cast(i + 2)) * qy_shifted[0]), weight); - } - } + fillvn(coll, tracks); } PROCESS_SWITCH(jEPFlowAnalysis, processDefault, "default process", true); @@ -399,31 +415,7 @@ struct jEPFlowAnalysis { } if (cfgAddEvtSel) { - if (std::abs(coll.posZ()) > cfgVertexZ) - return; - switch (cfgEvtSel) { - case 0: // Sel8 - if (!coll.sel8()) - return; - break; - case 1: // PbPb standard - if (!coll.sel8() || !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) - return; - break; - case 2: // PbPb with pileup - if (!coll.sel8() || !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) || - !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) - return; - break; - case 3: // Small systems (OO, NeNe, pp) - if (!coll.sel8() || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) - return; - break; - default: - LOGF(warning, "Event selection flag was not found, continuing without basic event selections!\n"); - } - // Check occupancy - if (coll.trackOccupancyInTimeRange() > cfgMaxOccupancy || coll.trackOccupancyInTimeRange() < cfgMinOccupancy) + if (!eventSel(coll)) return; } @@ -450,7 +442,7 @@ struct jEPFlowAnalysis { epFlowHistograms.fill(HIST("MC/hPartRec"), cent, coll.posZ(), trk.eta(), trk.phi(), trk.pt()); auto mctrk = trk.mcParticle(); if (mctrk.isPhysicalPrimary()) { - epFlowHistograms.fill(HIST("MChPartRecPr"), cent, coll.posZ(), trk.eta(), trk.phi(), trk.pt()); + epFlowHistograms.fill(HIST("MC/hPartRecPr"), cent, coll.posZ(), trk.eta(), trk.phi(), trk.pt()); } } } diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h index 4b5cf165b44..9f9304d4d1e 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h @@ -143,8 +143,8 @@ struct : ConfigurableGroup { Configurable> cfBookParticleHistograms{"cfBookParticleHistograms", {"1-Phi", "1-Pt", "1-Eta", "1-Charge", "1-tpcNClsFindable", "1-tpcNClsShared", "1-itsChi2NCl", "1-tpcNClsFound", "1-tpcNClsCrossedRows", "1-itsNCls", "1-itsNClsInnerBarrel", "1-tpcCrossedRowsOverFindableCls", "1-tpcFoundOverFindableCls", "1-tpcFractionSharedCls", "1-tpcChi2NCl", "1-dcaXY", "1-dcaZ", "0-PDG"}, "Book (1) or do not book (0) particle histogram"}; Configurable cfFillParticleHistograms2D{"cfFillParticleHistograms2D", false, "if false, all 2D particle histograms are not filled. if kTRUE, the ones for which fBookParticleHistograms2D[...] is kTRUE, are filled"}; Configurable> cfBookParticleHistograms2D{"cfBookParticleHistograms2D", {"1-Phi_vs_Pt", "1-Phi_vs_Eta"}, "Book (1) or do not book (0) 2D particle histograms"}; - Configurable cfRebinSparse{"cfRebinSparse", 1, "used only for all fixed-length bins which are implemented directly for sparse histograms (i.e. not inherited from results histograms)"}; - Configurable> cfBookParticleSparseHistograms{"cfBookParticleSparseHistograms", {"0-DWPhi", "0-DWPt", "0-DWEta"}, "Book (1) or do not book (0) particular category of sparse histograms"}; + Configurable> cfRebinSparse{"cfRebinSparse", {1., 1., 1., 1., 1., 1.}, "Ordering is the same as in eDiffPhiWeights. To make bins factor 2 finer use 0.5, to make bins factor 5 coarser use 5."}; + Configurable> cfBookParticleSparseHistograms{"cfBookParticleSparseHistograms", {"0-DWPhi", "0-DWPt", "0-DWEta", "0-DWCharge"}, "Book (1) or do not book (0) particular category of sparse histograms"}; Configurable cfFillParticleSparseHistogramsBeforeCuts{"cfFillParticleSparseHistogramsBeforeCuts", false, "I need sparse histograms before cuts only when testing pt and eta weights, in internal validation"}; // TBI 20250223 add eventually configurable for FillParticleSparseHistogramsDimension } cf_ph; @@ -157,7 +157,7 @@ struct : ConfigurableGroup { Configurable> cfPhi{"cfPhi", {0.0, o2::constants::math::TwoPI}, "phi range: {min, max}[rad], with convention: min <= phi < max"}; Configurable> cfPt{"cfPt", {0.2, 5.0}, "pt range: {min, max}[GeV], with convention: min <= pt < max"}; Configurable> cfEta{"cfEta", {-0.8, 0.8}, "eta range: {min, max}, with convention: min <= eta < max"}; - Configurable> cfCharge{"cfCharge", {-1.5, 1.5}, "particle charge. {-1.5,0} = only negative, {0,1.5} = only positive"}; + Configurable> cfCharge{"cfCharge", {-2.0, 2.0}, "particle charge. {-2.0,0} = only negative, {0,2.0} = only positive (keep in sync with res.fResultsProBinEdges[AFO_CHARGE])"}; Configurable> cftpcNClsFindable{"cftpcNClsFindable", {-1000., 1000.}, "tpcNClsFindable range: {min, max}, with convention: min <= cftpcNClsFindable < max"}; Configurable> cftpcNClsShared{"cftpcNClsShared", {-1000., 1000.}, "tpcNClsShared range: {min, max}, with convention: min <= cftpcNClsShared < max"}; Configurable> cfitsChi2NCl{"cfitsChi2NCl", {-1000., 36.}, "itsChi2NCl range: {min, max}, with convention: min <= cfitsChi2NCl < max"}; @@ -231,8 +231,9 @@ struct : ConfigurableGroup { Configurable cfUseDiffPhiPtWeights{"cfUseDiffPhiPtWeights", false, "use or not differential phi(pt) weights"}; Configurable cfUseDiffPhiEtaWeights{"cfUseDiffPhiEtaWeights", false, "use or not differential phi(eta) weights"}; Configurable> cfWhichDiffPhiWeights{"cfWhichDiffPhiWeights", {"1-wPhi", "1-wPt", "1-wEta", "1-wCharge", "1-wCentrality", "1-wVertexZ"}, "use (1) or do not use (0) differential phi weight for particular dimension. If only phi is set to 1, integrated phi weights are used. If phi is set to 0, ALL dimensions are switched off (yes!)"}; - Configurable> cfWhichDiffPtWeights{"cfWhichDiffPtWeights", {"0-wPt", "0-wCharge", "0-wCentrality"}, "use (1) or do not use (0) differential pt weight for particular dimension. If only pt is set to 1, integrated pt weights are used. If pt is set to 0, ALL dimensions are switched off (yes!)"}; - Configurable> cfWhichDiffEtaWeights{"cfWhichDiffEtaWeights", {"0-wEta", "0-wCharge", "0-wCentrality"}, "use (1) or do not use (0) differential eta weight for particular dimension. If only eta is set to 1, integrated eta weights are used. If eta is set to 0, ALL dimensions are switched off (yes!)"}; + Configurable> cfWhichDiffPtWeights{"cfWhichDiffPtWeights", {"0-wPt", "0-wEta", "0-wCharge", "0-wCentrality"}, "use (1) or do not use (0) differential pt weight for particular dimension. If only pt is set to 1, integrated pt weights are used. If pt is set to 0, ALL dimensions are switched off (yes!)"}; + Configurable> cfWhichDiffEtaWeights{"cfWhichDiffEtaWeights", {"0-wEta", "0-wPt", "0-wCharge", "0-wCentrality"}, "use (1) or do not use (0) differential eta weight for particular dimension. If only eta is set to 1, integrated eta weights are used. If eta is set to 0, ALL dimensions are switched off (yes!)"}; + Configurable> cfWhichDiffChargeWeights{"cfWhichDiffChargeWeights", {"0-wCharge", "0-wPt", "0-wEta", "0-wCentrality"}, "use (1) or do not use (0) differential charge weight for particular dimension. If only charge is set to 1, integrated charge weights are used. If charge is set to 0, ALL dimensions are switched off (yes!)"}; Configurable cfFileWithWeights{"cfFileWithWeights", "/home/abilandz/DatasetsO2/weights.root", "path to external ROOT file which holds all particle weights in O2 format"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" } cf_pw; @@ -252,9 +253,9 @@ struct : ConfigurableGroup { // *) Toy NUA: struct : ConfigurableGroup { - Configurable> cfApplyNUAPDF{"cfApplyNUAPDF", {0, 0, 0}, "Apply (1) or do not apply (0) NUA on variable, ordering is the same as in enum eNUAPDF (phi, pt, eta)"}; - Configurable> cfUseDefaultNUAPDF{"cfUseDefaultNUAPDF", {1, 1, 1}, "Use (1) or do not use (0) default NUA profile, ordering is the same as in enum eNUAPDF (phi, pt, eta)"}; - Configurable> cfCustomNUAPDFHistNames{"cfCustomNUAPDFHistNames", {"a", "bb", "ccc"}, "the names of histograms holding custom NUA in an external file."}; + Configurable> cfApplyNUAPDF{"cfApplyNUAPDF", {0, 0, 0, 0}, "Apply (1) or do not apply (0) NUA on variable, ordering is the same as in enum eNUAPDF (phi, pt, eta, charge)"}; + Configurable> cfUseDefaultNUAPDF{"cfUseDefaultNUAPDF", {1, 1, 1, 1}, "Use (1) or do not use (0) default NUA profile, ordering is the same as in enum eNUAPDF (phi, pt, eta, charge)"}; + Configurable> cfCustomNUAPDFHistNames{"cfCustomNUAPDFHistNames", {"a", "bb", "ccc", "dddd"}, "the names of histograms holding custom NUA in an external file."}; Configurable cfFileWithCustomNUA{"cfFileWithCustomNUA", "/home/abilandz/DatasetsO2/customNUA.root", "path to external ROOT file which holds all histograms with custom NUA"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" } cf_nua; @@ -263,7 +264,7 @@ struct : ConfigurableGroup { Configurable cfUseInternalValidation{"cfUseInternalValidation", false, "perform internal validation using flow analysis on-the-fly"}; Configurable cfInternalValidationForceBailout{"cfInternalValidationForceBailout", false, "force bailout (use only locally, since there is no graceful exit (yet))"}; Configurable cfnEventsInternalValidation{"cfnEventsInternalValidation", 0, "number of events simulated on-the-fly for internal validation"}; - Configurable cfHarmonicsOptionInternalValidation{"cfHarmonicsOptionInternalValidation", "constant", "for internal validation, supported options are \"constant\", \"correlated\", \"persistent\", \"ptDependent\", and \"ptEtaDependent\""}; + Configurable cfHarmonicsOptionInternalValidation{"cfHarmonicsOptionInternalValidation", "constant", "for internal validation, supported options are \"constant\", \"correlated\", \"persistent\", \"ptDependent\", \"ptEtaDependent\", and \"ptEtaChargeDependent\""}; Configurable cfRescaleWithTheoreticalInput{"cfRescaleWithTheoreticalInput", false, "if kTRUE, all correlators are rescaled with theoretical input, so that all results in profiles are 1"}; Configurable cfRandomizeReactionPlane{"cfRandomizeReactionPlane", true, "set to false only when validating against theoretical value the non-isotropic correlators"}; Configurable> cfInternalValidationAmplitudes{"cfInternalValidationAmplitudes", {0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09}, "{v1, v2, v3, v4, ...} + has an effect only in combination with cfHarmonicsOptionInternalValidation = \"constant\". Max number of vn's is gMaxHarmonic."}; diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h index 79a383076a7..32df4c726ee 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h @@ -262,7 +262,7 @@ struct ParticleHistograms { int fParticleSparseHistogramsNBins[eDiffWeightCategory_N][gMaxNumberSparseDimensions] = {{0}}; // number of bins. I do not have min and max, because for sparse I use BinEdges, see below TArrayD* fParticleSparseHistogramsBinEdges[eDiffWeightCategory_N][gMaxNumberSparseDimensions] = {{NULL}}; // arrays holding bin edges, see the usage of SetBinEdges for sparse histograms TString fParticleSparseHistogramsAxisTitle[eDiffWeightCategory_N][gMaxNumberSparseDimensions] = {{""}}; // axis title - int fRebinSparse = 1; // used only for all fixed-length bins which are implemented directly for sparse histograms (i.e. not inherited from results histograms) + float fRebinSparse[eDiffWeightCategory_N][gMaxNumberSparseDimensions] = {{1.}}; // used only for all fixed-length bins which are implemented directly for sparse histograms (i.e. not inherited from results histograms) } ph; // "ph" labels an instance of group of histograms "ParticleHistograms" // *) Particle cuts: @@ -343,6 +343,7 @@ struct ParticleWeights { bool fUseDiffPhiWeights[eDiffPhiWeights_N] = {false}; // use differential phi weights, see enum eDiffPhiWeights for supported dimensions bool fUseDiffPtWeights[eDiffPtWeights_N] = {false}; // use differential pt weights, see enum eDiffPtWeights for supported dimensions bool fUseDiffEtaWeights[eDiffEtaWeights_N] = {false}; // use differential eta weights, see enum eDiffEtaWeights for supported dimensions + bool fUseDiffChargeWeights[eDiffChargeWeights_N] = {false}; // use differential charge weights, see enum eDiffChargeWeights for supported dimensions // ... int fDWdimension[eDiffWeightCategory_N] = {0}; // dimension of differential weight for each category in current analysis TArrayD* fFindBinVector[eDiffWeightCategory_N] = {NULL}; // this is the vector I use to find bin when I obtain weights with sparse histograms @@ -399,7 +400,7 @@ struct InternalValidation { // Remember that for each real event, I do fnEventsInternalValidation events on-the-fly. // Can be used in combination with setting fSequentialBailout > 0. unsigned int fnEventsInternalValidation = 0; // how many on-the-fly events will be sampled for each real event, for internal validation - TString* fHarmonicsOptionInternalValidation = NULL; // "constant", "correlated", "persistent", "ptDependent", "ptEtaDependent", see .cxx for full documentation + TString* fHarmonicsOptionInternalValidation = NULL; // "constant", "correlated", "persistent", "ptDependent", "ptEtaDependent", "ptEtaChargeDependent", see .cxx for full documentation bool fRescaleWithTheoreticalInput = false; // if true, all measured correlators are rescaled with theoretical input, so that in profiles everything is at 1 bool fRandomizeReactionPlane = true; // if true, RP is randomized e-by-e. I need false basically only when validating against theoretical input non-isotropic correlators TArrayD* fInternalValidationVnPsin[2] = {NULL}; // 0 = { v1, v2, ... }, 1 = { Psi1, Psi2, ... } diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-Enums.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-Enums.h index fd2bc36920f..86fb4a7844e 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-Enums.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-Enums.h @@ -107,6 +107,7 @@ enum eDiffWeightCategory { eDWPhi = 0, // corresponds to eDiffPhiWeights structure, here the fundamental 0-th axis never to be projected out is "phi" eDWPt, // corresponds to eDiffPtWeights structure, here the fundamental 0-th axis never to be projected out is "pt" eDWEta, // corresponds to eDiffEtaWeights structure, here the fundamental 0-th axis never to be projected out is "eta" + eDWCharge, // corresponds to eDiffChargeWeights structure, here the fundamental 0-th axis never to be projected out is "charge" // ... eDiffWeightCategory_N }; @@ -121,8 +122,9 @@ enum eDiffPhiWeights { eDiffPhiWeights_N }; -enum eDiffPtWeights { +enum eDiffPtWeights { // if i add new entry here, or in eDiffPhiWeights and eDiffEtaWeights, I need to update also GetParticleWeights() + FillQvectorFromSparse() + WeightFromSparse() wPtPtAxis = 0, + wPtEtaAxis, wPtChargeAxis, wPtCentralityAxis, eDiffPtWeights_N @@ -130,11 +132,20 @@ enum eDiffPtWeights { enum eDiffEtaWeights { wEtaEtaAxis = 0, + wEtaPtAxis, wEtaChargeAxis, wEtaCentralityAxis, eDiffEtaWeights_N }; +enum eDiffChargeWeights { + wChargeChargeAxis = 0, + wChargePtAxis, + wChargeEtaAxis, + wChargeCentralityAxis, + eDiffChargeWeights_N +}; + enum eVnPsin { eVn = 0, ePsin = 1 }; @@ -359,6 +370,7 @@ enum eNUAPDF { ePhiNUAPDF = 0, ePtNUAPDF, eEtaNUAPDF, + eChargeNUAPDF, eNUAPDF_N }; diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h index 4635f8f9c7d..09b8968976a 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h @@ -667,6 +667,8 @@ void defaultConfiguration() for (int dpw = 0; dpw < eDiffPtWeights_N; dpw++) { // "differential pt weight" if (TString(lWhichDiffPtWeights[dpw]).Contains("wPt")) { pw.fUseDiffPtWeights[wPtPtAxis] = Alright(lWhichDiffPtWeights[dpw]); // if I pass "1-Pt" => true, "0-Pt" => false + } else if (TString(lWhichDiffPtWeights[dpw]).Contains("wEta")) { + pw.fUseDiffPtWeights[wPtEtaAxis] = Alright(lWhichDiffPtWeights[dpw]) && pw.fUseDiffPtWeights[wPtPtAxis]; } else if (TString(lWhichDiffPtWeights[dpw]).Contains("wCharge")) { pw.fUseDiffPtWeights[wPtChargeAxis] = Alright(lWhichDiffPtWeights[dpw]) && pw.fUseDiffPtWeights[wPtPtAxis]; } else if (TString(lWhichDiffPtWeights[dpw]).Contains("wCentrality")) { @@ -686,6 +688,8 @@ void defaultConfiguration() for (int dpw = 0; dpw < eDiffEtaWeights_N; dpw++) { // "differential eta weight" if (TString(lWhichDiffEtaWeights[dpw]).Contains("wEta")) { pw.fUseDiffEtaWeights[wEtaEtaAxis] = Alright(lWhichDiffEtaWeights[dpw]); // if I pass "1-Eta" => true, "0-Eta" => false + } else if (TString(lWhichDiffEtaWeights[dpw]).Contains("wPt")) { + pw.fUseDiffEtaWeights[wEtaPtAxis] = Alright(lWhichDiffEtaWeights[dpw]) && pw.fUseDiffEtaWeights[wEtaEtaAxis]; } else if (TString(lWhichDiffEtaWeights[dpw]).Contains("wCharge")) { pw.fUseDiffEtaWeights[wEtaChargeAxis] = Alright(lWhichDiffEtaWeights[dpw]) && pw.fUseDiffEtaWeights[wEtaEtaAxis]; } else if (TString(lWhichDiffEtaWeights[dpw]).Contains("wCentrality")) { @@ -695,6 +699,33 @@ void defaultConfiguration() } } + // **) Differential multidimensional charge weights: + auto lWhichDiffChargeWeights = cf_pw.cfWhichDiffChargeWeights.value; + if (lWhichDiffChargeWeights.size() != eDiffChargeWeights_N) { + LOGF(info, "\033[1;31m lWhichDiffChargeWeights.size() = %d\033[0m", lWhichDiffChargeWeights.size()); + LOGF(info, "\033[1;31m eDiffChargeWeights_N = %d\033[0m", static_cast(eDiffChargeWeights_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfWhichDiffChargeWeights, and number of entries in enum eDiffChargeWeights_N \n \033[0m", __FUNCTION__, __LINE__); + } + for (int dpw = 0; dpw < eDiffChargeWeights_N; dpw++) { // "differential charge weight" + if (TString(lWhichDiffChargeWeights[dpw]).Contains("wCharge")) { + pw.fUseDiffChargeWeights[wChargeChargeAxis] = Alright(lWhichDiffChargeWeights[dpw]); // if I pass "1-Charge" => true, "0-Charge" => false + } else if (TString(lWhichDiffChargeWeights[dpw]).Contains("wPt")) { + pw.fUseDiffChargeWeights[wChargePtAxis] = Alright(lWhichDiffChargeWeights[dpw]) && pw.fUseDiffChargeWeights[wChargeChargeAxis]; + } else if (TString(lWhichDiffChargeWeights[dpw]).Contains("wEta")) { + pw.fUseDiffChargeWeights[wChargeEtaAxis] = Alright(lWhichDiffChargeWeights[dpw]) && pw.fUseDiffChargeWeights[wChargeChargeAxis]; + } else if (TString(lWhichDiffChargeWeights[dpw]).Contains("wCentrality")) { + pw.fUseDiffChargeWeights[wChargeCentralityAxis] = Alright(lWhichDiffChargeWeights[dpw]) && pw.fUseDiffChargeWeights[wChargeChargeAxis]; + } else { + LOGF(fatal, "\033[1;31m%s at line %d : The setting %s in configurable cfWhichDiffChargeWeights is not supported yet. See enum eDiffChargeWeights . \n \033[0m", __FUNCTION__, __LINE__, TString(lWhichDiffChargeWeights[dpw]).Data()); + } + } + + // **) Only for debugging purposes, print all enabled weights: + if (tc.fVerbose) { + LOGF(info, "\033[1;31m%s at line %d : printing current status of all weights flags\033[0m", __FUNCTION__, __LINE__); + PrintAllWeightsFlags(); + } // if (tc.fVerbose) { + // **) File holding all particle weights: pw.fFileWithWeights = cf_pw.cfFileWithWeights; @@ -722,9 +753,10 @@ void defaultConfiguration() nua.fApplyNUAPDF[ePhiNUAPDF] = static_cast(lApplyNUAPDF[ePhiNUAPDF]); nua.fApplyNUAPDF[ePtNUAPDF] = static_cast(lApplyNUAPDF[ePtNUAPDF]); nua.fApplyNUAPDF[eEtaNUAPDF] = static_cast(lApplyNUAPDF[eEtaNUAPDF]); + nua.fApplyNUAPDF[eChargeNUAPDF] = static_cast(lApplyNUAPDF[eChargeNUAPDF]); // **) Execute the lines below, only if toy NUA (either default or custom) is requested for at least one kine variable: - if (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF]) { + if (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] || nua.fApplyNUAPDF[eChargeNUAPDF]) { auto lUseDefaultNUAPDF = (std::vector)cf_nua.cfUseDefaultNUAPDF; if (lUseDefaultNUAPDF.size() != eNUAPDF_N) { @@ -735,11 +767,13 @@ void defaultConfiguration() nua.fUseDefaultNUAPDF[ePhiNUAPDF] = static_cast(lUseDefaultNUAPDF[ePhiNUAPDF]); nua.fUseDefaultNUAPDF[ePtNUAPDF] = static_cast(lUseDefaultNUAPDF[ePtNUAPDF]); nua.fUseDefaultNUAPDF[eEtaNUAPDF] = static_cast(lUseDefaultNUAPDF[eEtaNUAPDF]); + nua.fUseDefaultNUAPDF[eChargeNUAPDF] = static_cast(lUseDefaultNUAPDF[eChargeNUAPDF]); // **) Execute the lines below, only if custom toy NUA is requested in at least one kine variable: if (!((nua.fApplyNUAPDF[ePhiNUAPDF] && nua.fUseDefaultNUAPDF[ePhiNUAPDF]) || (nua.fApplyNUAPDF[ePtNUAPDF] && nua.fUseDefaultNUAPDF[ePtNUAPDF]) || - (nua.fApplyNUAPDF[eEtaNUAPDF] && nua.fUseDefaultNUAPDF[eEtaNUAPDF]))) { + (nua.fApplyNUAPDF[eEtaNUAPDF] && nua.fUseDefaultNUAPDF[eEtaNUAPDF]) || + (nua.fApplyNUAPDF[eChargeNUAPDF] && nua.fUseDefaultNUAPDF[eChargeNUAPDF]))) { // If the above conditon is true, as least one NUA is requested and is not default, i.e. it's custom NUA obtained from external file, which was requested to be used. // TBI 20240501 Can I simplify the logic above, it's a bit cryptic... @@ -777,9 +811,16 @@ void defaultConfiguration() LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } } - } // if (!(nua.fUseDefaultNUAPDF[ePhiNUAPDF] || nua.fUseDefaultNUAPDF[ePtNUAPDF] || nua.fUseDefaultNUAPDF[eEtaNUAPDF])) { + if (!nua.fUseDefaultNUAPDF[eChargeNUAPDF]) { + nua.fCustomNUAPDFHistNames[eChargeNUAPDF] = new TString(lCustomNUAPDFHistNames[eChargeNUAPDF]); + this->GetHistogramWithCustomNUA(nua.fFileWithCustomNUA.Data(), eChargeNUAPDF); + if (!nua.fCustomNUAPDF[eChargeNUAPDF]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + } // if (!(nua.fUseDefaultNUAPDF[ePhiNUAPDF] || nua.fUseDefaultNUAPDF[ePtNUAPDF] || nua.fUseDefaultNUAPDF[eEtaNUAPDF] || nua.fUseDefaultNUAPDF[eChargeNUAPDF])) { - } // if ( nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] ) { + } // if ( nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] || nua.fApplyNUAPDF[eChargeNUAPDF]) { // *) Internal validation: iv.fUseInternalValidation = cf_iv.cfUseInternalValidation; @@ -1005,6 +1046,9 @@ void defaultConfiguration() ph.fParticleSparseHistogramsName[eDWEta] = "fParticleSparseHistograms_DWEta"; ph.fParticleSparseHistogramsTitle[eDWEta] = "sparse histogram for differential #eta weights,"; + ph.fParticleSparseHistogramsName[eDWCharge] = "fParticleSparseHistograms_DWCharge"; + ph.fParticleSparseHistogramsTitle[eDWCharge] = "sparse histogram for differential charge weights,"; + // ... // ** Eta separations: @@ -1132,6 +1176,31 @@ void defaultConfiguration() //============================================================ +void PrintAllWeightsFlags() +{ + // Simple utility function, to print current status of all weights flags. + + LOGF(info, "\033[1;33m Which multidimensional phi weights will be used (the ordering is the same as in enum eDiffPhiWeights):\033[0m"); + for (int dpw = 0; dpw < eDiffPhiWeights_N; dpw++) { + LOGF(info, "\033[1;33m %d \033[0m", pw.fUseDiffPhiWeights[dpw]); + } + LOGF(info, "\033[1;33m Which multidimensional pt weights will be used (the ordering is the same as in enum eDiffPtWeights):\033[0m"); + for (int dpw = 0; dpw < eDiffPtWeights_N; dpw++) { + LOGF(info, "\033[1;33m %d \033[0m", pw.fUseDiffPtWeights[dpw]); + } + LOGF(info, "\033[1;33m Which multidimensional eta weights will be used (the ordering is the same as in enum eDiffEtaWeights):\033[0m"); + for (int dpw = 0; dpw < eDiffEtaWeights_N; dpw++) { + LOGF(info, "\033[1;33m %d \033[0m", pw.fUseDiffEtaWeights[dpw]); + } + LOGF(info, "\033[1;33m Which multidimensional charge weights will be used (the ordering is the same as in enum eDiffChargeWeights):\033[0m"); + for (int dpw = 0; dpw < eDiffChargeWeights_N; dpw++) { + LOGF(info, "\033[1;33m %d \033[0m", pw.fUseDiffChargeWeights[dpw]); + } + +} // void PrintAllWeightsFlags() + +//============================================================ + bool Alright(TString s) { // Simple utility function, which for a string formatted "0-someName" returns false, and for "1-someName" returns true. @@ -1310,7 +1379,33 @@ void defaultBooking() ph.fBookParticleHistograms2D[ePhiEta] = Alright(lBookParticleHistograms2D[ePhiEta]) && ph.fFillParticleHistograms2D; // e) Particle sparse histograms: - ph.fRebinSparse = cf_ph.cfRebinSparse; + auto lRebinSparse = (std::vector)cf_ph.cfRebinSparse; + + ph.fRebinSparse[eDWPhi][wPhiPhiAxis] = lRebinSparse[wPhiPhiAxis]; + ph.fRebinSparse[eDWPhi][wPhiPtAxis] = lRebinSparse[wPhiPtAxis]; + ph.fRebinSparse[eDWPhi][wPhiEtaAxis] = lRebinSparse[wPhiEtaAxis]; + ph.fRebinSparse[eDWPhi][wPhiChargeAxis] = lRebinSparse[wPhiChargeAxis]; + ph.fRebinSparse[eDWPhi][wPhiCentralityAxis] = lRebinSparse[wPhiCentralityAxis]; + ph.fRebinSparse[eDWPhi][wPhiVertexZAxis] = lRebinSparse[wPhiVertexZAxis]; + // ... + + ph.fRebinSparse[eDWPt][wPtPtAxis] = lRebinSparse[wPhiPtAxis]; // yes, wPhiPtAxis is on the RHS, becase I defined ordering of cfRebinSparse by using ordering in eDiffPhiWeights + ph.fRebinSparse[eDWPt][wPtEtaAxis] = lRebinSparse[wPhiEtaAxis]; + ph.fRebinSparse[eDWPt][wPtChargeAxis] = lRebinSparse[wPhiChargeAxis]; + ph.fRebinSparse[eDWPt][wPtCentralityAxis] = lRebinSparse[wPhiCentralityAxis]; + // ... + + ph.fRebinSparse[eDWEta][wEtaEtaAxis] = lRebinSparse[wPhiEtaAxis]; // yes, wPhiEtaAxis is on the RHS, becase I defined ordering of cfRebinSparse by using ordering in eDiffPhiWeights + ph.fRebinSparse[eDWEta][wEtaPtAxis] = lRebinSparse[wPhiPtAxis]; + ph.fRebinSparse[eDWEta][wEtaChargeAxis] = lRebinSparse[wPhiChargeAxis]; + ph.fRebinSparse[eDWEta][wEtaCentralityAxis] = lRebinSparse[wPhiCentralityAxis]; + // ... + + ph.fRebinSparse[eDWCharge][wChargeChargeAxis] = lRebinSparse[wPhiChargeAxis]; // yes, wPhiChargeAxis is on the RHS, becase I defined ordering of cfRebinSparse by using ordering in eDiffPhiWeights + ph.fRebinSparse[eDWCharge][wChargePtAxis] = lRebinSparse[wPhiPtAxis]; + ph.fRebinSparse[eDWCharge][wChargeEtaAxis] = lRebinSparse[wPhiEtaAxis]; + ph.fRebinSparse[eDWCharge][wChargeCentralityAxis] = lRebinSparse[wPhiCentralityAxis]; + // ... // *) Categories of sparse histograms: auto lBookParticleSparseHistograms = cf_ph.cfBookParticleSparseHistograms.value; // fill or not particulat category of sparse histograms @@ -1339,6 +1434,7 @@ void defaultBooking() ph.fBookParticleSparseHistograms[eDWPhi] = Alright(lBookParticleSparseHistograms[eDWPhi]); ph.fBookParticleSparseHistograms[eDWPt] = Alright(lBookParticleSparseHistograms[eDWPt]); ph.fBookParticleSparseHistograms[eDWEta] = Alright(lBookParticleSparseHistograms[eDWEta]); + ph.fBookParticleSparseHistograms[eDWCharge] = Alright(lBookParticleSparseHistograms[eDWCharge]); // f) QA: @@ -1571,8 +1667,11 @@ void defaultBinning() // Default binning for all histograms. // TBI 20240114 If some of these values are going to change frequently, add support for them in MuPa-Configurables.h, - // in the same way I did it for defaultCuts(). - // At the moment, I added to configurables support only for binning of sparse histograms, because there memory managment is critical. + // in the same way I did it for defaultCuts(). + // TBI 20260223 If ever I will add also support for variable-length binning for control histograms, re-think first what I did in the + // booking of sparse histograms, because the code there hinges on the usage of fixed-length binning and the usage of + // configurable cfRebinSparse. But I doubt I will even need here variable-length binning, I have always rebin in such a way + // all control histograms in offline postprocessing. // a) Default binning for event histograms; // b) Default binning for particle histograms 1D; @@ -1648,11 +1747,11 @@ void defaultBinning() ph.fParticleHistogramsBins[ePt][0] = 2000; ph.fParticleHistogramsBins[ePt][1] = 0.; - ph.fParticleHistogramsBins[ePt][2] = 200.; + ph.fParticleHistogramsBins[ePt][2] = 20.; - ph.fParticleHistogramsBins[eEta][0] = 500; - ph.fParticleHistogramsBins[eEta][1] = -5.; - ph.fParticleHistogramsBins[eEta][2] = 5.; + ph.fParticleHistogramsBins[eEta][0] = 400; + ph.fParticleHistogramsBins[eEta][1] = -2.; + ph.fParticleHistogramsBins[eEta][2] = 2.; ph.fParticleHistogramsBins[eCharge][0] = 7; ph.fParticleHistogramsBins[eCharge][1] = -3.5; // anticipating I might be storing charge of Delta++, etc. @@ -1797,6 +1896,7 @@ void defaultBinning() // *) Binning vs. particle charge => binning is always the same nBins = 2 in (-2.,2), so that the center of bins is at +/- 1: // Therefore, I shall never initialize or set for ill-defined cases the charge to 0., because when filling, that one will go to bin for +1 charge ("lower boundary included"). + // Keep in sync with Configurable> cfCharge{ ... res.fResultsProBinEdges[AFO_CHARGE] = new TArrayD(3); res.fResultsProBinEdges[AFO_CHARGE]->AddAt(-2., 0); res.fResultsProBinEdges[AFO_CHARGE]->AddAt(0., 1); @@ -2861,7 +2961,7 @@ void insanityChecksBeforeBooking() } // **) Enforce that if the fixed number of randomly selected tracks is used that Toy NUA is disabled: - if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF])) { + if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] || nua.fApplyNUAPDF[eChargeNUAPDF])) { LOGF(fatal, "\033[1;31m%s at line %d : Not supported at the moment: use FixedNumberOfRandomlySelectedTracks + Toy NUA enabled.\nI cannot in an easy way ensure that ParticleCuts behave exactly the same in the Main and Banishment loops, because e.g. I call consequtively for same partcile gRandom->Uniform(...) in ParticleCuts, and that can't work.\033[0m", __FUNCTION__, __LINE__); } @@ -2955,6 +3055,9 @@ void insanityChecksBeforeBooking() if (eDiffEtaWeights_N > gMaxNumberSparseDimensions) { LOGF(fatal, "\033[1;31m%s at line %d : set eDiffEtaWeights_N = %d is bigger than gMaxNumberSparseDimensions = %d\033[0m", __FUNCTION__, __LINE__, static_cast(eDiffEtaWeights_N), gMaxNumberSparseDimensions); } + if (eDiffChargeWeights_N > gMaxNumberSparseDimensions) { + LOGF(fatal, "\033[1;31m%s at line %d : set eDiffChargeWeights_N = %d is bigger than gMaxNumberSparseDimensions = %d\033[0m", __FUNCTION__, __LINE__, static_cast(eDiffChargeWeights_N), gMaxNumberSparseDimensions); + } // ** For simulated data when fDatabasePDG is NOT used, I have to disable cut on charge, since that info is not available: if ((tc.fProcess[eGenericRecSim] || tc.fProcess[eGenericSim]) && pc.fUseParticleCuts[eCharge] && !tc.fUseDatabasePDG) { @@ -3231,7 +3334,8 @@ void insanityChecksBeforeBooking() iv.fHarmonicsOptionInternalValidation->EqualTo("correlated", TString::kIgnoreCase) || iv.fHarmonicsOptionInternalValidation->EqualTo("persistent", TString::kIgnoreCase) || iv.fHarmonicsOptionInternalValidation->EqualTo("ptDependent", TString::kIgnoreCase) || - iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent", TString::kIgnoreCase))) { + iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent", TString::kIgnoreCase) || + iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaChargeDependent", TString::kIgnoreCase))) { LOGF(fatal, "\033[1;31m%s at line %d : fHarmonicsOptionInternalValidation = %s is not supported. \033[0m", __FUNCTION__, __LINE__, iv.fHarmonicsOptionInternalValidation->Data()); } @@ -3243,6 +3347,18 @@ void insanityChecksBeforeBooking() LOGF(fatal, "\033[1;31m%s at line %d : in IV eMultiplicityEstimator cannot be set to \"ReferenceMultiplicity\" (yet) \033[0m", __FUNCTION__, __LINE__); } + if (!tc.fCalculateAsFunctionOf[AFO_PT] && pc.fUseParticleCuts[ePt]) { + LOGF(fatal, "\033[1;31m%s at line %d : in IV you do not calculate vs pt, but the cut on pt is on in IV\033[0m", __FUNCTION__, __LINE__); + } + + if (!tc.fCalculateAsFunctionOf[AFO_ETA] && pc.fUseParticleCuts[eEta]) { + LOGF(fatal, "\033[1;31m%s at line %d : in IV you do not calculate vs eta, but the cut on eta is on in IV\033[0m", __FUNCTION__, __LINE__); + } + + if (!tc.fCalculateAsFunctionOf[AFO_CHARGE] && pc.fUseParticleCuts[eCharge]) { + LOGF(fatal, "\033[1;31m%s at line %d : in IV you do not calculate vs charge, but the cut on charge is on in IV\033[0m", __FUNCTION__, __LINE__); + } + } // if (iv.fUseInternalValidation) { // h) Insanity checks on results histograms: @@ -3309,6 +3425,9 @@ void insanityChecksAfterBooking() if (iv.fRescaleWithTheoreticalInput && iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent")) { LOGF(fatal, "\033[1;31m%s at line %d : rescaling with theoretical input doesn't make sanse for fHarmonicsOptionInternalValidation = \"ptEtaDependent\". \033[0m", __FUNCTION__, __LINE__); } + if (iv.fRescaleWithTheoreticalInput && iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaChargeDependent")) { + LOGF(fatal, "\033[1;31m%s at line %d : rescaling with theoretical input doesn't make sanse for fHarmonicsOptionInternalValidation = \"ptEtaChargeDependent\". \033[0m", __FUNCTION__, __LINE__); + } // **) Print a warning if this histogram is not booked: if (!eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]) { @@ -4998,8 +5117,8 @@ void bookParticleHistograms() // a) Book the profile holding flags; // b) Book specific particle histograms 1D; // c) Book specific particle histograms 2D; - // e) Default binning for particle sparse histograms (yes, here, see comments below); - // d) Book specific particle sparse histograms (n-dimensions). + // d) Default binning for particle sparse histograms (yes, here, see comments below); + // e) Book specific particle sparse histograms (n-dimensions). if (tc.fVerbose) { StartFunction(__FUNCTION__); @@ -5153,28 +5272,31 @@ void bookParticleHistograms() // eParticleHistograms // d) Default binning for particle sparse histograms: - // Remark 0: This requires the special treatment, because I re-use in some cases bins from results histograns. - // Therefore, I can do all this only after bookResultsHistograms() was already called. + // Remark 0: I am using binning from particle or event control histograms, and I can optionally make it coarser or finer via configurable array fRebinSparse. + // It is important to vary fRebinSparse as a part of systematics. Note that I can do additional rebinning offline when making weights, so keep it here + // as fine as possible. // Remark 1: I anticipate I will need them only when I need to calculate differential weights, therefore I couple them intentionally // with enum's for differential weights from very beginning. - // Remark 2: Whenever possible, I re-use binning from results histograms. + // Remark 2: Do NOT re-use binning from results histograms, here the bin widths cannot be varied as a part of systematics (see Remark 0 above); // Remark 3: For variable-length binning, for each dimension of THnSparse, I have to call SetBinEdges (see below). // Therefore, to facilitate the whole procedure, fixed-length bins which I implemented directly (e.g. for phi dimension, which I do not have in results histograms), // I convert also in arrays. For fixed-length bins in results histograms I do NOT have to do that, because for that case I call GetArray() in any case, which is // doing such conversion automatically. + // TBI 20260223 I didn't really check variable-length binning for sparse extensively, use only fixed-length binning for the time being. // Remark 4: If I do not need particular dimension in sparse histogram, e.g. pt, in the config simply set // "cfFixedLengthPtBins": {"values": ["1", "0.2", "5.0"]}, // where lower and upper pt boundary must be the same as in the pt cut, defined via // "cfPt": {"values": ["0.2","5.0"]}, // Keep this convention in sync with what I am doing in the macro MakeWeightsFromSparse(...) + // Remark 5: Do not mix below eh.fEventHistograms and ph.fParticleHistograms // **) eDiffWeightCategory = eDWPhi: TAxis* lAxis = NULL; // local helper TAxis, to convert in one line the booking of fixed-length array into array of corresponding bin edges - // ***) phi-axis for diff phi weights: at the moment I support only fixed-length binning, which optionally can be made finer or coarser with ph.fRebinSparse configurable: - ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPhiAxis] = static_cast(180. / ph.fRebinSparse); - lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPhiAxis], 0., o2::constants::math::TwoPI); + // ***) phi-axis for diff phi weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPhiAxis] = static_cast(ph.fParticleHistogramsBins[ePhi][0] / ph.fRebinSparse[eDWPhi][wPhiPhiAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPhiAxis], ph.fParticleHistogramsBins[ePhi][1], ph.fParticleHistogramsBins[ePhi][2]); ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPhiAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPhiAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPhiAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); @@ -5183,170 +5305,207 @@ void bookParticleHistograms() delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiPhiAxis] = FancyFormatting("Phi"); - // ***) pt-axis for diff phi weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_PT]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_PT] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPtAxis] = res.fResultsPro[AFO_PT]->GetNbinsX(); // :55 - lAxis = res.fResultsPro[AFO_PT]->GetXaxis(); + // ***) pt-axis for diff phi weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPtAxis] = static_cast(ph.fParticleHistogramsBins[ePt][0] / ph.fRebinSparse[eDWPhi][wPhiPtAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPtAxis], ph.fParticleHistogramsBins[ePt][1], ph.fParticleHistogramsBins[ePt][2]); ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPtAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPtAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPtAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPtAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiPtAxis] = FancyFormatting("Pt"); - // ***) eta-axis for diff phi weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_ETA]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_ETA] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiEtaAxis] = res.fResultsPro[AFO_ETA]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_ETA]->GetXaxis(); + // ***) eta-axis for diff phi weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiEtaAxis] = static_cast(ph.fParticleHistogramsBins[eEta][0] / ph.fRebinSparse[eDWPhi][wPhiEtaAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiEtaAxis], ph.fParticleHistogramsBins[eEta][1], ph.fParticleHistogramsBins[eEta][2]); ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiEtaAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiEtaAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiEtaAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiEtaAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiEtaAxis] = FancyFormatting("Eta"); - // ***) charge-axis for diff phi weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_CHARGE]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CHARGE] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis] = res.fResultsPro[AFO_CHARGE]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_CHARGE]->GetXaxis(); + // ***) charge-axis for diff phi weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis] = static_cast(ph.fParticleHistogramsBins[eCharge][0] / ph.fRebinSparse[eDWPhi][wPhiChargeAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis], ph.fParticleHistogramsBins[eCharge][1], ph.fParticleHistogramsBins[eCharge][2]); ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiChargeAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiChargeAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiChargeAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiChargeAxis] = FancyFormatting("Charge"); - // ***) centrality-axis for diff phi weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_CENTRALITY]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CENTRALITY] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiCentralityAxis] = res.fResultsPro[AFO_CENTRALITY]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_CENTRALITY]->GetXaxis(); + // ***) centrality-axis for diff phi weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiCentralityAxis] = static_cast(eh.fEventHistogramsBins[eCentrality][0] / ph.fRebinSparse[eDWPhi][wPhiCentralityAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiCentralityAxis], eh.fEventHistogramsBins[eCentrality][1], eh.fEventHistogramsBins[eCentrality][2]); ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiCentralityAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiCentralityAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiCentralityAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiCentralityAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiCentralityAxis] = "Centrality"; // TBI 20250222 I cannot call here FancyFormatting for "Centrality", because ec.fsEventCuts[eCentralityEstimator] is still not fetched and set from configurable. Re-think how to proceed for this specific case. - // ***) VertexZ-axis for diff phi weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_VZ]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_VZ] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiVertexZAxis] = res.fResultsPro[AFO_VZ]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_VZ]->GetXaxis(); + // ***) VertexZ-axis for diff phi weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiVertexZAxis] = static_cast(eh.fEventHistogramsBins[eVertexZ][0] / ph.fRebinSparse[eDWPhi][wPhiVertexZAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiVertexZAxis], eh.fEventHistogramsBins[eVertexZ][1], eh.fEventHistogramsBins[eVertexZ][2]); ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiVertexZAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiVertexZAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiVertexZAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiVertexZAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) - ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiVertexZAxis] = "VertexZ"; // TBI 20250222 I cannot call here FancyFormatting for "Centrality", because ec.fsEventCuts[eCentralityEstimator] + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiVertexZAxis] = "VertexZ"; // ... // **) eDiffWeightCategory = eDWPt: - // ***) pt-axis for diff pt weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_PT]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_PT] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWPt][wPtPtAxis] = res.fResultsPro[AFO_PT]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_PT]->GetXaxis(); + // ***) pt-axis for diff pt weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPt][wPtPtAxis] = static_cast(ph.fParticleHistogramsBins[ePt][0] / ph.fRebinSparse[eDWPt][wPtPtAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPt][wPtPtAxis], ph.fParticleHistogramsBins[ePt][1], ph.fParticleHistogramsBins[ePt][2]); ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtPtAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPt][wPtPtAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtPtAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtPtAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPt][wPtPtAxis] = FancyFormatting("Pt"); - // ***) charge-axis for diff pt weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_CHARGE]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CHARGE] is NULL \033[0m", __FUNCTION__, __LINE__); + // ***) eta-axis for diff pt weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPt][wPtEtaAxis] = static_cast(ph.fParticleHistogramsBins[eEta][0] / ph.fRebinSparse[eDWPt][wPtEtaAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPt][wPtEtaAxis], ph.fParticleHistogramsBins[eEta][1], ph.fParticleHistogramsBins[eEta][2]); + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtEtaAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPt][wPtEtaAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtEtaAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } - ph.fParticleSparseHistogramsNBins[eDWPt][wPtChargeAxis] = res.fResultsPro[AFO_CHARGE]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_CHARGE]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtEtaAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWPt][wPtEtaAxis] = FancyFormatting("Eta"); + + // ***) charge-axis for diff pt weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPt][wPtChargeAxis] = static_cast(ph.fParticleHistogramsBins[eCharge][0] / ph.fRebinSparse[eDWPt][wPtChargeAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPt][wPtChargeAxis], ph.fParticleHistogramsBins[eCharge][1], ph.fParticleHistogramsBins[eCharge][2]); ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtChargeAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPt][wPtChargeAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtChargeAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtChargeAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPt][wPtChargeAxis] = FancyFormatting("Charge"); - // ***) centrality-axis for diff pt weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_CENTRALITY]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CENTRALITY] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWPt][wPtCentralityAxis] = res.fResultsPro[AFO_CENTRALITY]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_CENTRALITY]->GetXaxis(); + // ***) centrality-axis for diff pt weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWPt][wPtCentralityAxis] = static_cast(eh.fEventHistogramsBins[eCentrality][0] / ph.fRebinSparse[eDWPt][wPtCentralityAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPt][wPtCentralityAxis], eh.fEventHistogramsBins[eCentrality][1], eh.fEventHistogramsBins[eCentrality][2]); ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtCentralityAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPt][wPtCentralityAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtCentralityAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtCentralityAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWPt][wPtCentralityAxis] = "Centrality"; // TBI 20250222 I cannot call here FancyFormatting for "Centrality", because ec.fsEventCuts[eCentralityEstimator] is still not fetched and set from configurable. Re-think how to proceed for this specific case. // ... // **) eDiffWeightCategory = eDWEta: - // ***) eta-axis for diff eta weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_ETA]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_ETA] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWEta][wEtaEtaAxis] = res.fResultsPro[AFO_ETA]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_ETA]->GetXaxis(); + // ***) eta-axis for diff eta weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaEtaAxis] = static_cast(ph.fParticleHistogramsBins[eEta][0] / ph.fRebinSparse[eDWEta][wEtaEtaAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWEta][wEtaEtaAxis], ph.fParticleHistogramsBins[eEta][1], ph.fParticleHistogramsBins[eEta][2]); ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaEtaAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaEtaAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaEtaAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaEtaAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWEta][wEtaEtaAxis] = FancyFormatting("Eta"); - // ***) charge-axis for diff eta weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_CHARGE]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CHARGE] is NULL \033[0m", __FUNCTION__, __LINE__); + // ***) pt-axis for diff eta weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaPtAxis] = static_cast(ph.fParticleHistogramsBins[ePt][0] / ph.fRebinSparse[eDWEta][wEtaPtAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWEta][wEtaPtAxis], ph.fParticleHistogramsBins[ePt][1], ph.fParticleHistogramsBins[ePt][2]); + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaPtAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaPtAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaPtAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } - ph.fParticleSparseHistogramsNBins[eDWEta][wEtaChargeAxis] = res.fResultsPro[AFO_CHARGE]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_CHARGE]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaPtAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWEta][wEtaPtAxis] = FancyFormatting("Pt"); + + // ***) charge-axis for diff eta weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaChargeAxis] = static_cast(ph.fParticleHistogramsBins[eCharge][0] / ph.fRebinSparse[eDWEta][wEtaChargeAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWEta][wEtaChargeAxis], ph.fParticleHistogramsBins[eCharge][1], ph.fParticleHistogramsBins[eCharge][2]); ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaChargeAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaChargeAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaChargeAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaChargeAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWEta][wEtaChargeAxis] = FancyFormatting("Charge"); - // ***) centrality-axis for diff eta weights - I re-use binning from results histograms: - if (!res.fResultsPro[AFO_CENTRALITY]) { - LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CENTRALITY] is NULL \033[0m", __FUNCTION__, __LINE__); - } - ph.fParticleSparseHistogramsNBins[eDWEta][wEtaCentralityAxis] = res.fResultsPro[AFO_CENTRALITY]->GetNbinsX(); - lAxis = res.fResultsPro[AFO_CENTRALITY]->GetXaxis(); + // ***) centrality-axis for diff eta weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaCentralityAxis] = static_cast(eh.fEventHistogramsBins[eCentrality][0] / ph.fRebinSparse[eDWEta][wEtaCentralityAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWEta][wEtaCentralityAxis], eh.fEventHistogramsBins[eCentrality][1], eh.fEventHistogramsBins[eCentrality][2]); ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaCentralityAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaCentralityAxis]); for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaCentralityAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); } ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaCentralityAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin - // delete lAxis; // I do not need to delete here, only when new TAxis(...) + delete lAxis; ph.fParticleSparseHistogramsAxisTitle[eDWEta][wEtaCentralityAxis] = "Centrality"; // TBI 20250222 I cannot call here FancyFormatting for "Centrality", because ec.fsEventCuts[eCentralityEstimator] is still not fetched and set from configurable. Re-think how to proceed for this specific case. // ... + // **) eDiffWeightCategory = eDWCharge: + + // ***) charge-axis for diff charge weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeChargeAxis] = static_cast(ph.fParticleHistogramsBins[eCharge][0] / ph.fRebinSparse[eDWCharge][wChargeChargeAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeChargeAxis], ph.fParticleHistogramsBins[eCharge][1], ph.fParticleHistogramsBins[eCharge][2]); + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeChargeAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeChargeAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeChargeAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeChargeAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWCharge][wChargeChargeAxis] = FancyFormatting("charge"); + + // ***) pt-axis for diff charge weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargePtAxis] = static_cast(ph.fParticleHistogramsBins[ePt][0] / ph.fRebinSparse[eDWCharge][wChargePtAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWCharge][wChargePtAxis], ph.fParticleHistogramsBins[ePt][1], ph.fParticleHistogramsBins[ePt][2]); + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargePtAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargePtAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargePtAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargePtAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWCharge][wChargePtAxis] = FancyFormatting("Pt"); + + // ***) eta-axis for diff charge weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeEtaAxis] = static_cast(ph.fParticleHistogramsBins[eEta][0] / ph.fRebinSparse[eDWCharge][wChargeEtaAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeEtaAxis], ph.fParticleHistogramsBins[eEta][1], ph.fParticleHistogramsBins[eEta][2]); + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeEtaAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeEtaAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeEtaAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeEtaAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWCharge][wChargeEtaAxis] = FancyFormatting("Eta"); + + // ***) centrality-axis for diff charge weights - at the moment I support only fixed-length binning from control histograms, which optionally can be made finer or coarser with cfRebinSparse configurable: + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeCentralityAxis] = static_cast(eh.fEventHistogramsBins[eCentrality][0] / ph.fRebinSparse[eDWCharge][wChargeCentralityAxis]); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeCentralityAxis], eh.fEventHistogramsBins[eCentrality][1], eh.fEventHistogramsBins[eCentrality][2]); + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeCentralityAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWCharge][wChargeCentralityAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeCentralityAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWCharge][wChargeCentralityAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWCharge][wChargeCentralityAxis] = "Centrality"; // TBI 20250222 I cannot call here FancyFormatting for "Centrality", because ec.fsEventCuts[eCentralityEstimator] is still not fetched and set from configurable. Re-think how to proceed for this specific case. + + // ... + // e) Book specific particle sparse histograms (n-dimensions): if (ph.fBookParticleSparseHistograms[eDWPhi]) { BookParticleSparseHistograms(eDWPhi); @@ -5360,6 +5519,10 @@ void bookParticleHistograms() BookParticleSparseHistograms(eDWEta); } + if (ph.fBookParticleSparseHistograms[eDWCharge]) { + BookParticleSparseHistograms(eDWCharge); + } + if (tc.fVerbose) { ExitFunction(__FUNCTION__); } @@ -5391,6 +5554,10 @@ void BookParticleSparseHistograms(eDiffWeightCategory dwc) nDimensions = static_cast(eDiffEtaWeights_N); break; } + case eDWCharge: { + nDimensions = static_cast(eDiffChargeWeights_N); + break; + } default: { LOGF(fatal, "\033[1;31m%s at line %d : This differential weight category, dwc = %d, is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(dwc)); break; @@ -5945,7 +6112,7 @@ void bookWeightsHistograms() } // a) Book the profile holding flags: - pw.fWeightsFlagsPro = new TProfile("fWeightsFlagsPro", "flags for particle weights", 17, 0., 17.); + pw.fWeightsFlagsPro = new TProfile("fWeightsFlagsPro", "flags for particle weights", 23, 0., 23.); pw.fWeightsFlagsPro->SetStats(false); pw.fWeightsFlagsPro->SetLineColor(eColor); pw.fWeightsFlagsPro->SetFillColor(eFillColor); @@ -5959,7 +6126,7 @@ void bookWeightsHistograms() pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(4, "(w_{#varphi})_{| p_{T}}"); // TBI 20241019 not sure if this is the final notation, keep in sync with void SetDiffWeightsHist(...) pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(5, "(w_{#varphi})_{| #eta}"); // TBI 20241019 not sure if this is the final notation, keep in sync with void SetDiffWeightsHist(...) - // **) differential phi weights using sparse: + // **) differential phi weights using sparse (keep in sync with enum eDiffPhiWeights): pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(6, "(w_{#varphi})_{phi axis (sparse)}"); pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(7, "(w_{#varphi})_{p_{T} axis (sparse)}"); pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(8, "(w_{#varphi})_{#eta axis (sparse)}"); @@ -5967,11 +6134,23 @@ void bookWeightsHistograms() pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(10, "(w_{#varphi})_{centrality axis (sparse)}"); pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(11, "(w_{#varphi})_{VertexZ axis (sparse)}"); - // **) differential pt weights using sparse: + // **) differential pt weights using sparse (keep in sync with enum eDiffPtWeights): pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(12, "(w_{p_{T}})_{pt axis (sparse)}"); - - // **) differential eta weights using sparse: - pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(13, "(w_{#eta})_{eta axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(13, "(w_{p_{T}})_{eta axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(14, "(w_{p_{T}})_{charge axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(15, "(w_{p_{T}})_{centrality axis (sparse)}"); + + // **) differential eta weights using sparse (keep in sync with enum eDiffEtaWeights): + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(16, "(w_{#eta})_{eta axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(17, "(w_{#eta})_{pt axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(18, "(w_{#eta})_{charge axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(19, "(w_{#eta})_{centrality axis (sparse)}"); + + // **) differential charge weights using sparse (keep in sync with enum eDiffChargeWeights): + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(20, "(w_{charge})_{charge axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(21, "(w_{charge})_{pt axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(22, "(w_{charge})_{eta axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(23, "(w_{charge})_{centrality axis (sparse)}"); } else { @@ -5984,7 +6163,7 @@ void bookWeightsHistograms() yAxisTitle += TString::Format("%d:(w_{#varphi})_{| p_{T}}; ", 4); yAxisTitle += TString::Format("%d:(w_{#varphi})_{| #eta}; ", 5); - // **) differential phi weights using sparse: + // **) differential phi weights using sparse (keep in sync with enum eDiffPhiWeights): yAxisTitle += TString::Format("%d:(w_{#varphi})_{phi axis (sparse)}; ", 6); yAxisTitle += TString::Format("%d:(w_{#varphi})_{p_{T} axis (sparse)}; ", 7); yAxisTitle += TString::Format("%d:(w_{#varphi})_{#eta axis (sparse)}; ", 8); @@ -5992,15 +6171,23 @@ void bookWeightsHistograms() yAxisTitle += TString::Format("%d:(w_{#varphi})_{centrality axis (sparse)}; ", 10); yAxisTitle += TString::Format("%d:(w_{#varphi})_{VertexZ axis (sparse)}; ", 11); - // **) differential pt weights using sparse: + // **) differential pt weights using sparse (keep in sync with enum eDiffPtWeights): yAxisTitle += TString::Format("%d:(w_{p_{T}})_{pt axis (sparse)}; ", 12); - yAxisTitle += TString::Format("%d:(w_{p_{T}})_{charge axis (sparse)}; ", 13); - yAxisTitle += TString::Format("%d:(w_{p_{T}})_{centrality axis (sparse)}; ", 14); - - // **) differential eta weights using sparse: - yAxisTitle += TString::Format("%d:(w_{#eta})_{eta axis (sparse)}; ", 15); - yAxisTitle += TString::Format("%d:(w_{#eta})_{charge axis (sparse)}; ", 16); - yAxisTitle += TString::Format("%d:(w_{#eta})_{centrality axis (sparse)}; ", 17); + yAxisTitle += TString::Format("%d:(w_{p_{T}})_{eta axis (sparse)}; ", 13); + yAxisTitle += TString::Format("%d:(w_{p_{T}})_{charge axis (sparse)}; ", 14); + yAxisTitle += TString::Format("%d:(w_{p_{T}})_{centrality axis (sparse)}; ", 15); + + // **) differential eta weights using sparse (keep in sync with enum eDiffEtaWeights): + yAxisTitle += TString::Format("%d:(w_{#eta})_{eta axis (sparse)}; ", 16); + yAxisTitle += TString::Format("%d:(w_{#eta})_{pt axis (sparse)}; ", 17); + yAxisTitle += TString::Format("%d:(w_{#eta})_{charge axis (sparse)}; ", 18); + yAxisTitle += TString::Format("%d:(w_{#eta})_{centrality axis (sparse)}; ", 19); + + // **) differential charge weights using sparse (keep in sync with enum eDiffChargeWeights): + yAxisTitle += TString::Format("%d:(w_{charge})_{charge axis (sparse)}; ", 20); + yAxisTitle += TString::Format("%d:(w_{charge})_{pt axis (sparse)}; ", 21); + yAxisTitle += TString::Format("%d:(w_{charge})_{eta axis (sparse)}; ", 22); + yAxisTitle += TString::Format("%d:(w_{charge})_{centrality axis (sparse)}; ", 23); // ... @@ -6057,23 +6244,43 @@ void bookWeightsHistograms() if (pw.fUseDiffPtWeights[wPtPtAxis]) { pw.fWeightsFlagsPro->Fill(11.5, 1.); } - if (pw.fUseDiffPhiWeights[wPtChargeAxis]) { + if (pw.fUseDiffPtWeights[wPtEtaAxis]) { pw.fWeightsFlagsPro->Fill(12.5, 1.); } - if (pw.fUseDiffPhiWeights[wPtCentralityAxis]) { + if (pw.fUseDiffPtWeights[wPtChargeAxis]) { pw.fWeightsFlagsPro->Fill(13.5, 1.); } + if (pw.fUseDiffPtWeights[wPtCentralityAxis]) { + pw.fWeightsFlagsPro->Fill(14.5, 1.); + } // **) differential eta weights using sparse: if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { - pw.fWeightsFlagsPro->Fill(14.5, 1.); - } - if (pw.fUseDiffPhiWeights[wEtaChargeAxis]) { pw.fWeightsFlagsPro->Fill(15.5, 1.); } - if (pw.fUseDiffPhiWeights[wEtaCentralityAxis]) { + if (pw.fUseDiffEtaWeights[wEtaPtAxis]) { pw.fWeightsFlagsPro->Fill(16.5, 1.); } + if (pw.fUseDiffEtaWeights[wEtaChargeAxis]) { + pw.fWeightsFlagsPro->Fill(17.5, 1.); + } + if (pw.fUseDiffEtaWeights[wEtaCentralityAxis]) { + pw.fWeightsFlagsPro->Fill(18.5, 1.); + } + + // **) differential charge weights using sparse: + if (pw.fUseDiffChargeWeights[wChargeChargeAxis]) { + pw.fWeightsFlagsPro->Fill(19.5, 1.); + } + if (pw.fUseDiffChargeWeights[wChargePtAxis]) { + pw.fWeightsFlagsPro->Fill(20.5, 1.); + } + if (pw.fUseDiffChargeWeights[wChargeEtaAxis]) { + pw.fWeightsFlagsPro->Fill(21.5, 1.); + } + if (pw.fUseDiffChargeWeights[wChargeCentralityAxis]) { + pw.fWeightsFlagsPro->Fill(22.5, 1.); + } pw.fWeightsList->Add(pw.fWeightsFlagsPro); @@ -6395,20 +6602,22 @@ void bookNUAHistograms() } // a) Book the profile holding flags: - nua.fNUAFlagsPro = new TProfile("fNUAFlagsPro", "flags for Toy NUA", 6, 0.5, 6.5); + nua.fNUAFlagsPro = new TProfile("fNUAFlagsPro", "flags for Toy NUA", 8, 0.5, 8.5); nua.fNUAFlagsPro->SetStats(false); nua.fNUAFlagsPro->SetLineColor(eColor); nua.fNUAFlagsPro->SetFillColor(eFillColor); nua.fNUAFlagsPro->GetXaxis()->SetLabelSize(0.03); - // TBI 20240429 the binning below is a bit fragile, but ok... + // TBI 20260312 the binning below is a bit fragile, but ok... if (tc.fUseSetBinLabel) { nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(1 + ePhiNUAPDF), "fApplyNUAPDF[phi]"); nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(1 + ePtNUAPDF), "fApplyNUAPDF[pt]"); nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(1 + eEtaNUAPDF), "fApplyNUAPDF[eta]"); - nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(4 + ePhiNUAPDF), "fUseDefaultNUAPDF[phi]"); - nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(4 + ePtNUAPDF), "fUseDefaultNUAPDF[pt]"); - nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(4 + eEtaNUAPDF), "fUseDefaultNUAPDF[eta]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(1 + eChargeNUAPDF), "fApplyNUAPDF[charge]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(5 + ePhiNUAPDF), "fUseDefaultNUAPDF[phi]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(5 + ePtNUAPDF), "fUseDefaultNUAPDF[pt]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(5 + eEtaNUAPDF), "fUseDefaultNUAPDF[eta]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(5 + eChargeNUAPDF), "fUseDefaultNUAPDF[charge]"); // ... @@ -6420,9 +6629,11 @@ void bookNUAHistograms() yAxisTitle += TString::Format("%d:fApplyNUAPDF[phi]; ", static_cast(1 + ePhiNUAPDF)); yAxisTitle += TString::Format("%d:fApplyNUAPDF[pt]; ", static_cast(1 + ePtNUAPDF)); yAxisTitle += TString::Format("%d:fApplyNUAPDF[eta]; ", static_cast(1 + eEtaNUAPDF)); - yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[phi]; ", static_cast(4 + ePhiNUAPDF)); - yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[pt]; ", static_cast(4 + ePtNUAPDF)); - yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[eta]; ", static_cast(4 + eEtaNUAPDF)); + yAxisTitle += TString::Format("%d:fApplyNUAPDF[charge]; ", static_cast(1 + eChargeNUAPDF)); + yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[phi]; ", static_cast(5 + ePhiNUAPDF)); + yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[pt]; ", static_cast(5 + ePtNUAPDF)); + yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[eta]; ", static_cast(5 + eEtaNUAPDF)); + yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[charge]; ", static_cast(5 + eChargeNUAPDF)); // ... @@ -6449,26 +6660,32 @@ void bookNUAHistograms() if (nua.fApplyNUAPDF[eEtaNUAPDF]) { nua.fNUAFlagsPro->Fill(static_cast(1 + eEtaNUAPDF), 1.); } + if (nua.fApplyNUAPDF[eChargeNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(1 + eChargeNUAPDF), 1.); + } if (nua.fUseDefaultNUAPDF[ePhiNUAPDF]) { - nua.fNUAFlagsPro->Fill(static_cast(4 + ePhiNUAPDF), 1.); + nua.fNUAFlagsPro->Fill(static_cast(5 + ePhiNUAPDF), 1.); } if (nua.fUseDefaultNUAPDF[ePtNUAPDF]) { - nua.fNUAFlagsPro->Fill(static_cast(4 + ePtNUAPDF), 1.); + nua.fNUAFlagsPro->Fill(static_cast(5 + ePtNUAPDF), 1.); } if (nua.fUseDefaultNUAPDF[eEtaNUAPDF]) { - nua.fNUAFlagsPro->Fill(static_cast(4 + eEtaNUAPDF), 1.); + nua.fNUAFlagsPro->Fill(static_cast(5 + eEtaNUAPDF), 1.); + } + if (nua.fUseDefaultNUAPDF[eChargeNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(5 + eChargeNUAPDF), 1.); } nua.fNUAList->Add(nua.fNUAFlagsPro); - if (!(nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF])) { + if (!(nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] || nua.fApplyNUAPDF[eChargeNUAPDF])) { return; } // b) Common local labels: - TString sVariable[eNUAPDF_N] = {"#varphi", "p_{t}", "#eta"}; // has to be in sync with the ordering of enum eNUAPDF + TString sVariable[eNUAPDF_N] = {"#varphi", "p_{t}", "#eta", "charge"}; // has to be in sync with the ordering of enum eNUAPDF // c) Histograms: - for (int pdf = 0; pdf < eNUAPDF_N; pdf++) // use pdfs for NUA in (phi, pt, eta, ...) + for (int pdf = 0; pdf < eNUAPDF_N; pdf++) // use pdfs for NUA in (phi, pt, eta, charge, ...) { if (!nua.fCustomNUAPDF[pdf]) // yes, because these histos are cloned from the external ones, see void SetNUAPDF(TH1D* const hist, const char* variable); { @@ -6515,8 +6732,8 @@ void bookNUAHistograms() if (!nua.fApplyNUAPDF[eEtaNUAPDF]) { continue; } - // Define default detector acceptance in pseudorapidity: One sectors, with probability < 1. - double dSector[2] = {0.2, 0.5}; // sector is defined as 0.2 < eta < 0.5 + // Define default detector acceptance in pseudorapidity: One sector, with probability < 1. + double dSector[2] = {0.2, 0.6}; // sector is defined as 0.2 < eta < 0.6 double dProbability = 0.2; // probability, so after being set this way, only 20% of particles in that sector are reconstructed nua.fDefaultNUAPDF[eEtaNUAPDF] = new TF1(TString::Format("fDefaultNUAPDF[%d]", eEtaNUAPDF), "1.-(x>=[0])*(1.-[2]) + (x>=[1])*(1.-[2])", ph.fParticleHistogramsBins[eEta][1], ph.fParticleHistogramsBins[eEta][2]); @@ -6524,6 +6741,21 @@ void bookNUAHistograms() nua.fDefaultNUAPDF[eEtaNUAPDF]->SetParameter(1, dSector[1]); nua.fDefaultNUAPDF[eEtaNUAPDF]->SetParameter(2, dProbability); nua.fNUAList->Add(nua.fDefaultNUAPDF[eEtaNUAPDF]); + } else if (sVariable[pdf].EqualTo("charge")) { + + // *) default NUA for charge pdf: + if (!nua.fApplyNUAPDF[eChargeNUAPDF]) { + continue; + } + // Define default detector acceptance in charge: Particles with negative charge, I take with probability 50% + double dSector[2] = {-1., 0.}; // nua sector is defined for charge in the range -1. < charge < 0. + double dProbability = 0.5; // probability, so after being set this way, only 50% of particles in that sector are reconstructed + nua.fDefaultNUAPDF[eChargeNUAPDF] = new TF1(TString::Format("fDefaultNUAPDF[%d]", eChargeNUAPDF), "1.-(x>=[0])*(1.-[2]) + (x>=[1])*(1.-[2])", + ph.fParticleHistogramsBins[eCharge][1], ph.fParticleHistogramsBins[eCharge][2]); + nua.fDefaultNUAPDF[eChargeNUAPDF]->SetParameter(0, dSector[0]); + nua.fDefaultNUAPDF[eChargeNUAPDF]->SetParameter(1, dSector[1]); + nua.fDefaultNUAPDF[eChargeNUAPDF]->SetParameter(2, dProbability); + nua.fNUAList->Add(nua.fDefaultNUAPDF[eChargeNUAPDF]); } else { LOGF(fatal, "\033[1;31m%s at line %d : pdf = %s is not supported (yet)\n \033[0m", __FUNCTION__, __LINE__, sVariable[pdf].Data()); } @@ -6547,7 +6779,7 @@ void bookNUAHistograms() nua.fMaxValuePDF[pdf] = nua.fDefaultNUAPDF[pdf]->GetMaximum(ph.fParticleHistogramsBins[pdf][1], ph.fParticleHistogramsBins[pdf][2]); } - } // for(int pdf=0;pdfSetParameter(1, 0.04); // v1 = 0.04 = const in this parameterization fPhiPDF->SetParameter(3, 0.06); // v3 = 0.06 = const in this parameterization // Amplitude v2(pt) and reaction plane are pbyp set ebye in the loop below - } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent")) { - // For this option, one selected vn harmonic (v2) depends both on pT and eta. - // pt dependence is the same as defined in Eq. (32) in arXiv:1312.3572 - // eta dependence is defined as 0.4 - (1/4) eta^2, so that v2(eta) = 0.24 at eta = +-0.8, and v2(eta) = 0.4 at eta = 0 (keep in sync with details below, when I am sampling pt and eta) - // to increase significance, I multiply by factor of 2 the sampled v2(pt,eta) (see the formula below when sampling) - // I still use constant v1 = 0.04 and v3 = 0.06 in this example + one common reaction plane. + } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent") || iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaChargeDependent")) { + // a) "ptEtaDependent": + // For this option, one selected vn harmonic (v2) depends both on pT and eta. + // pt dependence is the same as defined in Eq. (32) in arXiv:1312.3572 + // eta dependence is defined as 0.4 - (1/4) eta^2, so that v2(eta) = 0.24 at eta = +-0.8, and v2(eta) = 0.4 at eta = 0 (keep in sync with details below, when I am sampling pt and eta) + // to increase significance, I multiply by factor of 2 the sampled v2(pt,eta) (see the formula below when sampling) + // I still use constant v1 = 0.04 and v3 = 0.06 in this example + one common reaction plane. + + // b) "ptEtaChargeDependent": + // For this option, one selected vn harmonic (v2) depends on pT, eta and charge. + // pt and eta dependence, and all other settings are the same as in the option "ptEtaDependent" + // The only difference in this option that for particles with positive charge, I downscale their v2 by 25%, i.e. v2(positive) = 0.75 v2 (negative), everything else is the same. + // Therefore, I can use the same config here both for "ptEtaDependent" and "ptEtaChargeDependent", the charge dependence I introduce later in the loop below // Azimuthal angles are sampled from this pdf: fPhiPDF = new TF1("fPhiPDF", "1 + 2.*[1]*std::cos(x-[0]) + 2.*[2]*std::cos(2.*(x-[0])) + 2.*[3]*std::cos(3.*(x-[0]))", 0., o2::constants::math::TwoPI); @@ -6912,7 +7159,7 @@ void InternalValidation() // Set constant parameters here: fPhiPDF->SetParameter(1, 0.04); // v1 = 0.04 = const in this parameterization fPhiPDF->SetParameter(3, 0.06); // v3 = 0.06 = const in this parameterization - // Amplitude v2(pt,eta) and reaction plane are pbyp set ebye in the loop below + // Amplitude v2(pt,eta) for option "ptEtaDependent" and amplitude v2(pt,eta,charge) for option "ptEtaChargeDependent", and reaction plane are pbyp set ebye in the loop below } // b) Loop over on-the-fly events: @@ -6937,7 +7184,7 @@ void InternalValidation() fPhiPDF->SetParameter(3, fReactionPlane); } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptDependent")) { fPhiPDF->SetParameter(0, fReactionPlane); - } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent")) { + } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent") || iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaChargeDependent")) { fPhiPDF->SetParameter(0, fReactionPlane); } // Remark: I do not need here anything for option "persistent", because RP is not used for that case. See below how 3 symmetry planes are introduced with persistent correlation @@ -7038,7 +7285,7 @@ void InternalValidation() float fV2vsPtMax = 0.3; // v2(pt): for pt < fV2vsPtCutOff v2 increases linearly, for pt >= fV2vsPtCutOff v2 = fV2vsPtMax, see Eq. (32) in arXiv:1312.3572 pbyp.fPt < fV2vsPtCutOff ? fPhiPDF->SetParameter(2, pbyp.fPt * fV2vsPtMax / fV2vsPtCutOff) : fPhiPDF->SetParameter(2, fV2vsPtMax); - } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent")) { + } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent") || iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaChargeDependent")) { float fV2vsPtCutOff = 2.0; // TBI 20250729 I could add configurables for these 2 variables at some point, otherwise, simply hardwire the constants in the expression below float fV2vsPtMax = 0.3; // TBI 20250729 I shall NOT use f to name these two variables, rename eventually // pt dependence: for pt < fV2vsPtCutOff v2 increases linearly, for pt >= fV2vsPtCutOff v2 = fV2vsPtMax, see Eq. (32) in arXiv:1312.3572 @@ -7049,7 +7296,14 @@ void InternalValidation() if (v2 < 0. || v2 > 0.5) { LOGF(fatal, "\033[1;31m%s at line %d : v2 = %f\033[0m", __FUNCTION__, __LINE__, v2); } - fPhiPDF->SetParameter(2, v2); // set v2(pt,eta) for this particle + if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaDependent")) { + fPhiPDF->SetParameter(2, v2); // set v2(pt,eta) for this particle + } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("ptEtaChargeDependent")) { + if (pbyp.fCharge > 0.) { + v2 *= 0.75; // trim down by 25% only v2 of positive particles in this toy model + } + fPhiPDF->SetParameter(2, v2); // set v2(pt,eta,charge) for this particle + } } // Finally, sample particle angle: @@ -7078,15 +7332,23 @@ void InternalValidation() // **) eDWPt : here the fundamental 0-th axis never to be projected out is "pt" if (ph.fBookParticleSparseHistograms[eDWPt]) { // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffPtWeights - double vector[eDiffPtWeights_N] = {pbyp.fPt, pbyp.fCharge, ebye.fCentrality}; + double vector[eDiffPtWeights_N] = {pbyp.fPt, pbyp.fEta, pbyp.fCharge, ebye.fCentrality}; ph.fParticleSparseHistograms[eDWPt][eSim][eBefore]->Fill(vector); } // **) eDWEta : here the fundamental 0-th axis never to be projected out is "eta" if (ph.fBookParticleSparseHistograms[eDWEta]) { // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffEtaWeights - double vector[eDiffEtaWeights_N] = {pbyp.fEta, pbyp.fCharge, ebye.fCentrality}; + double vector[eDiffEtaWeights_N] = {pbyp.fEta, pbyp.fPt, pbyp.fCharge, ebye.fCentrality}; ph.fParticleSparseHistograms[eDWEta][eSim][eBefore]->Fill(vector); } + + // **) eDWCharge : here the fundamental 0-th axis never to be projected out is "charge" + if (ph.fBookParticleSparseHistograms[eDWCharge]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffChargeWeights + double vector[eDiffChargeWeights_N] = {pbyp.fCharge, pbyp.fPt, pbyp.fEta, ebye.fCentrality}; + ph.fParticleSparseHistograms[eDWCharge][eSim][eBefore]->Fill(vector); + } + } // ph.fFillParticleSparseHistogramsBeforeCuts } // if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) @@ -7124,6 +7386,9 @@ void InternalValidation() if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(pbyp.fEta, eEtaNUAPDF)) { continue; } + if (nua.fApplyNUAPDF[eChargeNUAPDF] && !Accept(pbyp.fCharge, eChargeNUAPDF)) { + continue; + } // *) Fill few selected particle histograms after cuts here directly here: // Remark: I do not call FillParticleHistograms(track, eAfter), as I do not want to bother to make here full 'track' object, etc., just to fill simple kine info: @@ -7146,15 +7411,21 @@ void InternalValidation() // **) eDWPt : here the fundamental 0-th axis never to be projected out is "pt" if (ph.fBookParticleSparseHistograms[eDWPt]) { // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffPtWeights - double vector[eDiffPtWeights_N] = {pbyp.fPt, pbyp.fCharge, ebye.fCentrality}; + double vector[eDiffPtWeights_N] = {pbyp.fPt, pbyp.fEta, pbyp.fCharge, ebye.fCentrality}; ph.fParticleSparseHistograms[eDWPt][eSim][eAfter]->Fill(vector); } // **) eDWEta : here the fundamental 0-th axis never to be projected out is "eta" if (ph.fBookParticleSparseHistograms[eDWEta]) { // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffEtaWeights - double vector[eDiffEtaWeights_N] = {pbyp.fEta, pbyp.fCharge, ebye.fCentrality}; + double vector[eDiffEtaWeights_N] = {pbyp.fEta, pbyp.fPt, pbyp.fCharge, ebye.fCentrality}; ph.fParticleSparseHistograms[eDWEta][eSim][eAfter]->Fill(vector); } + // **) eDWCharge : here the fundamental 0-th axis never to be projected out is "charge" + if (ph.fBookParticleSparseHistograms[eDWCharge]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffChargeWeights + double vector[eDiffChargeWeights_N] = {pbyp.fCharge, pbyp.fPt, pbyp.fEta, ebye.fCentrality}; + ph.fParticleSparseHistograms[eDWCharge][eSim][eAfter]->Fill(vector); + } } // if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) // Remark: Keep in sync all calls and flags below with the ones in MainLoopOverParticles(). @@ -7263,8 +7534,8 @@ bool Accept(const double& value, int var) // Given the acceptance profile for this observable, accept or not that observable for the analysis. // Use in Toy NUA studies. - // Remark: var corresponds to the field in enum eNUAPDF { ePhiNUAPDF, ePtNUAPDF, eEtaNUAPDF }; - // Therefore, always call this function as e.g. Accept(someAngle, ePhiNUAPDF) or Accept(somePt, ePtNUAPDF) + // Remark: var corresponds to the field in enum eNUAPDF { ePhiNUAPDF, ePtNUAPDF, eEtaNUAPDF, eChargeNUAPDF }; + // Therefore, always call this function as e.g. Accept(someAngle, ePhiNUAPDF) or Accept(somePt, ePtNUAPDF), etc. if (tc.fVerboseForEachParticle) { LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); @@ -11050,7 +11321,7 @@ bool ParticleCuts(T const& track, eCutModus cutModus) // *) Toy NUA: // TBI 20250718 Check if can optimize here something by using new global pbyp.fPhi, pbyp.fPt, etc, variables. Most likely yes, since I would avoid calling again track.phi(), etc. // But I do not use Toy NUA in any case for real large-scale data analysis. - if (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF]) { + if (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] || nua.fApplyNUAPDF[eChargeNUAPDF]) { // Remark: I do not for the time being add Toy NUA cuts to particle cut counters, since in this case I can inspect direcly from phi, pt and eta distributions. @@ -11058,12 +11329,14 @@ bool ParticleCuts(T const& track, eCutModus cutModus) double dPhi = 0.; double dPt = 0.; double dEta = 0.; + double dCharge = 0.; // *) Apply Toy NUA on info available in reconstructed (and the corresponding MC truth simulated track); if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { dPhi = track.phi(); dPt = track.pt(); dEta = track.eta(); + dCharge = track.sign(); // Apply NUA on these kine variables: if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { @@ -11075,6 +11348,9 @@ bool ParticleCuts(T const& track, eCutModus cutModus) if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { return false; } + if (nua.fApplyNUAPDF[eChargeNUAPDF] && !Accept(dCharge, eChargeNUAPDF)) { + return false; + } // ... and corresponding MC truth simulated ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { @@ -11086,6 +11362,12 @@ bool ParticleCuts(T const& track, eCutModus cutModus) dPhi = mcParticle.phi(); dPt = mcParticle.pt(); dEta = mcParticle.eta(); + // special treatment for charge, because there is no getter mcParticle.sign() + dCharge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + dCharge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } // Apply NUA on these kine variables: if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { @@ -11097,6 +11379,9 @@ bool ParticleCuts(T const& track, eCutModus cutModus) if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { return false; } + if (nua.fApplyNUAPDF[eChargeNUAPDF] && !Accept(dCharge, eChargeNUAPDF)) { + return false; + } } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { @@ -11107,6 +11392,12 @@ bool ParticleCuts(T const& track, eCutModus cutModus) dPhi = track.phi(); dPt = track.pt(); dEta = track.eta(); + // special treatment for charge, because there is no getter mcParticle.sign() + dCharge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(track.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + dCharge = tc.fDatabasePDG->GetParticle(track.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } // Apply NUA on these kine variables: if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { @@ -11118,9 +11409,12 @@ bool ParticleCuts(T const& track, eCutModus cutModus) if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { return false; } + if (nua.fApplyNUAPDF[eChargeNUAPDF] && !Accept(dCharge, eChargeNUAPDF)) { + return false; + } } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { - } // if(nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF]) { + } // if(nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] || nua.fApplyNUAPDF[eChargeNUAPDF]) { return true; @@ -11254,15 +11548,21 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, int weight = 1) // **) eDWPt : here the fundamental 0-th axis never to be projected out is "pt" if (ph.fBookParticleSparseHistograms[eDWPt]) { // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffPtWeights - double vector[eDiffPtWeights_N] = {track.pt(), static_cast(track.sign()), ebye.fCentrality}; + double vector[eDiffPtWeights_N] = {track.pt(), track.eta(), static_cast(track.sign()), ebye.fCentrality}; ph.fParticleSparseHistograms[eDWPt][eRec][ba]->Fill(vector, weight); } // **) eDWEta : here the fundamental 0-th axis never to be projected out is "eta" if (ph.fBookParticleSparseHistograms[eDWEta]) { // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffEtaWeights - double vector[eDiffEtaWeights_N] = {track.eta(), static_cast(track.sign()), ebye.fCentrality}; + double vector[eDiffEtaWeights_N] = {track.eta(), track.pt(), static_cast(track.sign()), ebye.fCentrality}; ph.fParticleSparseHistograms[eDWEta][eRec][ba]->Fill(vector, weight); } + // **) eDWCharge : here the fundamental 0-th axis never to be projected out is "charge" + if (ph.fBookParticleSparseHistograms[eDWCharge]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffChargeWeights + double vector[eDiffChargeWeights_N] = {static_cast(track.sign()), track.pt(), track.eta(), ebye.fCentrality}; + ph.fParticleSparseHistograms[eDWCharge][eRec][ba]->Fill(vector, weight); + } } // if (ba == eAfter ... ) { // QA: @@ -11411,7 +11711,7 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, int weight = 1) // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL charge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks } - double vector[eDiffPtWeights_N] = {mcParticle.pt(), charge, ebye.fCentralitySim}; + double vector[eDiffPtWeights_N] = {mcParticle.pt(), mcParticle.eta(), charge, ebye.fCentralitySim}; ph.fParticleSparseHistograms[eDWPt][eSim][ba]->Fill(vector, weight); } // **) eDWEta : here the fundamental 0-th axis never to be projected out is "eta" @@ -11424,9 +11724,23 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, int weight = 1) // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL charge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks } - double vector[eDiffEtaWeights_N] = {mcParticle.eta(), charge, ebye.fCentralitySim}; + double vector[eDiffEtaWeights_N] = {mcParticle.eta(), mcParticle.pt(), charge, ebye.fCentralitySim}; ph.fParticleSparseHistograms[eDWEta][eSim][ba]->Fill(vector, weight); } + // **) eDWCharge : here the fundamental 0-th axis never to be projected out is "charge" + if (ph.fBookParticleSparseHistograms[eDWCharge]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffChargeWeights + + // special treatment for charge, because there is no getter mcParticle.sign() + double charge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + charge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } + double vector[eDiffChargeWeights_N] = {charge, mcParticle.pt(), mcParticle.eta(), ebye.fCentralitySim}; + ph.fParticleSparseHistograms[eDWCharge][eSim][ba]->Fill(vector, weight); + } + } // if (ba == eAfter ... ) { } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { @@ -13231,16 +13545,37 @@ void FillNestedLoopsContainers(const int& particleIndex) double wPhi = 1.; double wPt = 1.; double wEta = 1.; - if (pw.fUseWeights[wPHI]) { + double wCharge = 1.; + + if (pw.fUseDiffPhiWeights[wPhiPhiAxis]) { // yes, 0th axis serves as a common boolean for this category + wPhi = WeightFromSparse(eDWPhi); + } + + if (pw.fUseDiffPtWeights[wPtPtAxis]) { // yes, 0th axis serves as a common boolean for this category + wPt = WeightFromSparse(eDWPt); + } + + if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { // yes, 0th axis serves as a common boolean for this category + wEta = WeightFromSparse(eDWEta); + } + + if (pw.fUseDiffChargeWeights[wChargeChargeAxis]) { // yes, 0th axis serves as a common boolean for this category + wCharge = WeightFromSparse(eDWCharge); + } + + if (pw.fUseWeights[wPHI]) { // TBI 20260216 obsolete, remove eventually wPhi = Weight(pbyp.fPhi, wPHI); } - if (pw.fUseWeights[wPT]) { + + if (pw.fUseWeights[wPT]) { // TBI 20260216 obsolete, remove eventually wPt = Weight(pbyp.fPt, wPT); } - if (pw.fUseWeights[wETA]) { + + if (pw.fUseWeights[wETA]) { // TBI 20260216 obsolete, remove eventually wEta = Weight(pbyp.fEta, wETA); } - nl.ftaNestedLoops[1]->AddAt(wPhi * wPt * wEta, particleIndex); // remember that the 2nd argument here must start from 0 + + nl.ftaNestedLoops[1]->AddAt(wPhi * wPt * wEta * wCharge, particleIndex); // remember that the 2nd argument here must start from 0 } if (tc.fVerbose) { @@ -13989,30 +14324,126 @@ void SetDiffWeightsSparse(THnSparseF* const sparse, eDiffWeightCategory dwc) // Finally, add to corresponding TList: pw.fWeightsList->Add(pw.fDiffWeightsSparse[dwc]); - // TBI 20250530 check this code snippet - do I need it? - // // Cosmetics: TBI 20240216 do I really want to overwrite initial cosmetics, perhaps this shall go better into MakeWeights.C ? - // // Or I could move all this to GetHistogramWithWeights, where in any case I am setting e.g. histogram title, etc. - // TString sVariable[eDiffWeights_N] = {"#varphi", "#varphi"}; // yes, for the time being, x-axis is always phi - // TString sWeights[eDiffWeights_N] = {"(w_{#varphi})_{| p_{T}}", "(w_{#varphi})_{| #eta}"}; - // pw.fDiffWeightsSparse[whichDiffWeight][bin]->SetStats(false); - // pw.fDiffWeightsSparse[whichDiffWeight][bin]->GetXaxis()->SetTitle(sVariable[whichDiffWeight].Data()); - // pw.fDiffWeightsSparse[whichDiffWeight][bin]->GetYaxis()->SetTitle(sWeights[whichDiffWeight].Data()); - // pw.fDiffWeightsSparse[whichDiffWeight][bin]->SetFillColor(eFillColor); - // pw.fDiffWeightsSparse[whichDiffWeight][bin]->SetLineColor(eColor); - // pw.fWeightsList->Add(pw.fDiffWeightsSparse[whichDiffWeight][bin]); // This is working at the moment, because I am fetching all weights in Preprocess(), which is called after init() - // // But if eventually it will be possible to fetch run number programatically in init(), I will have to re-think this line. - - // // Flag: - // if (!pw.fUseDiffWeights[whichDiffWeight]) // yes, set it only once to true, for all bins - // { - // pw.fUseDiffWeights[whichDiffWeight] = true; - // } + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } - // if (tc.fVerbose) { - // ExitFunction(__FUNCTION__); - // } +} // void SetDiffWeightsSparse(THnSparseF* const sparse, eDiffWeightCategory dwc) + +//============================================================ + +void insanitizeDiffWeightsSparse(THnSparseF* const sparse) +{ + // Check if particle weights are avaiable for the phase window I have selected for each dimension with cuts. + // Basically, I check whether range of each axis in sparse histograms is compatible with the cuts i used for variable on that axis. + + // TBI 20260223 : I am doing one unnecessary extra check in each if statement below to prevent rounding problem - check this further + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + if (!sparse) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + int nDim = sparse->GetNdimensions(); + for (int d = 0; d < nDim; d++) { + + // get title for this axis: + std::string axisTitle = sparse->GetAxis(d)->GetTitle(); + + // insanity check on the title: + if (axisTitle.empty()) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d of sparse %s has an empty title \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName()); + } + + // check all supported observables: + if (!axisTitle.compare("#varphi")) { // I have to negate, becase compare() returns 0 if strings are equal + keep in sync hardwired string here with what i have in FancyFormatting(...) + + // check lower boundary: + if ((pc.fdParticleCuts[ePhi][eMin] < sparse->GetAxis(d)->GetBinLowEdge(1)) && (std::abs(sparse->GetAxis(d)->GetBinLowEdge(1) - pc.fdParticleCuts[ePhi][eMin]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (#varphi) of sparse %s has lower boundary %f, while lower cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinLowEdge(1), pc.fdParticleCuts[ePhi][eMin]); + } + + // check upper boundary: + if ((pc.fdParticleCuts[ePhi][eMax] > sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins())) && (std::abs(sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()) - pc.fdParticleCuts[ePhi][eMax]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (#varphi) of sparse %s has upper boundary %f, while upper cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()), pc.fdParticleCuts[ePhi][eMax]); + } + + } else if (!axisTitle.compare("p_{T}")) { + + // check lower boundary: + if ((pc.fdParticleCuts[ePt][eMin] < sparse->GetAxis(d)->GetBinLowEdge(1)) && (std::abs(sparse->GetAxis(d)->GetBinLowEdge(1) - pc.fdParticleCuts[ePt][eMin]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (p_{T}) of sparse %s has lower boundary %f, while lower cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinLowEdge(1), pc.fdParticleCuts[ePt][eMin]); + } + + // check upper boundary: + if ((pc.fdParticleCuts[ePt][eMax] > sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins())) && (std::abs(sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()) - pc.fdParticleCuts[ePt][eMax]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (p_{T}) of sparse %s has upper boundary %f, while upper cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()), pc.fdParticleCuts[ePt][eMax]); + } + + } else if (!axisTitle.compare("#eta")) { + + // check lower boundary: + if ((pc.fdParticleCuts[eEta][eMin] < sparse->GetAxis(d)->GetBinLowEdge(1)) && (std::abs(sparse->GetAxis(d)->GetBinLowEdge(1) - pc.fdParticleCuts[eEta][eMin]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (#eta) of sparse %s has lower boundary %f, while lower cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinLowEdge(1), pc.fdParticleCuts[eEta][eMin]); + } + + // check upper boundary: + if ((pc.fdParticleCuts[eEta][eMax] > sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins())) && (std::abs(sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()) - pc.fdParticleCuts[eEta][eMax]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (#eta) of sparse %s has upper boundary %f, while upper cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()), pc.fdParticleCuts[eEta][eMax]); + } + + } else if (!axisTitle.compare("Charge") || !axisTitle.compare("charge")) { + + // check lower boundary: + if ((pc.fdParticleCuts[eCharge][eMin] < sparse->GetAxis(d)->GetBinLowEdge(1)) && (std::abs(sparse->GetAxis(d)->GetBinLowEdge(1) - pc.fdParticleCuts[eCharge][eMin]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (Charge) of sparse %s has lower boundary %f, while lower cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinLowEdge(1), pc.fdParticleCuts[eCharge][eMin]); + } + + // check upper boundary: + if ((pc.fdParticleCuts[eCharge][eMax] > sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins())) && (std::abs(sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()) - pc.fdParticleCuts[eCharge][eMax]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (Charge) of sparse %s has upper boundary %f, while upper cut on that variable is %f. This means that for some particles I won't be able to fetch weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()), pc.fdParticleCuts[eCharge][eMax]); + } + + } else if (!axisTitle.find("Centrality")) { // I have to use here find() instead, because title also contains centrality estimator name, e.g. "Centality (FT0C)" -} // void SetDiffWeightsSparse(THnSparseF* const sparse) + // check lower boundary: + if ((ec.fdEventCuts[eCentrality][eMin] < sparse->GetAxis(d)->GetBinLowEdge(1)) && (std::abs(sparse->GetAxis(d)->GetBinLowEdge(1) - ec.fdEventCuts[eCentrality][eMin]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (Centrality) of sparse %s has lower boundary %f, while lower cut on that variable is %f. This means that for some events I won't be able to fetch particle weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinLowEdge(1), ec.fdEventCuts[eCentrality][eMin]); + } + + // check upper boundary: + if ((ec.fdEventCuts[eCentrality][eMax] > sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins())) && (std::abs(sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()) - ec.fdEventCuts[eCentrality][eMax]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (Centrality) of sparse %s has upper boundary %f, while upper cut on that variable is %f. This means that for some events I won't be able to fetch particles weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()), ec.fdEventCuts[eCentrality][eMax]); + } + + } else if (!(axisTitle.compare("V_{z}")) || !(axisTitle.compare("VertexZ"))) { // TBI 20260217 I use indeed "VertexZ" for the time being, not sure why I didn't use here also FancyFormatting. But it doesn't hurt to add check for both + + // check lower boundary: + if ((ec.fdEventCuts[eVertexZ][eMin] < sparse->GetAxis(d)->GetBinLowEdge(1)) && (std::abs(sparse->GetAxis(d)->GetBinLowEdge(1) - ec.fdEventCuts[eVertexZ][eMin]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (V_{z} or VertexZ) of sparse %s has lower boundary %f, while lower cut on that variable is %f. This means that for some events I won't be able to fetch particle weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinLowEdge(1), ec.fdEventCuts[eVertexZ][eMin]); + } + + // check upper boundary: + if ((ec.fdEventCuts[eVertexZ][eMax] > sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins())) && (std::abs(sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()) - ec.fdEventCuts[eVertexZ][eMax]) > tc.fFloatingPointPrecision)) { + LOGF(fatal, "\033[1;31m%s at line %d : axis %d (V_{z} or VertexZ) of sparse %s has upper boundary %f, while upper cut on that variable is %f. This means that for some events I won't be able to fetch particles weights from this sparse. \033[0m", __FUNCTION__, __LINE__, d, sparse->GetName(), sparse->GetAxis(d)->GetBinUpEdge(sparse->GetAxis(d)->GetNbins()), ec.fdEventCuts[eVertexZ][eMax]); + } + + // ... add in the same way check for any other variable + + } else { + LOGF(fatal, "\033[1;31m%s at line %d : axisTitle = %s of sparse = %s is not supported yet in this function \033[0m", __FUNCTION__, __LINE__, axisTitle.data(), sparse->GetName()); + } + + } // for(int d = 0; d < nDim; d++) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void insanitizeDiffWeightsSparse(THnSparseF* const sparse) //============================================================ @@ -14407,7 +14838,7 @@ THnSparseF* GetSparseHistogramWithWeights(const char* filePath, const char* runN // b) Basic protection for arguments: // Remark: below I do one more specific check. - if (!(TString(whichCategory).EqualTo("phi") || TString(whichCategory).EqualTo("pt") || TString(whichCategory).EqualTo("eta"))) { + if (!(TString(whichCategory).EqualTo("phi") || TString(whichCategory).EqualTo("pt") || TString(whichCategory).EqualTo("eta") || TString(whichCategory).EqualTo("charge"))) { LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } if (TString(whichDimensions).EqualTo("")) { @@ -14568,6 +14999,8 @@ THnSparseF* GetSparseHistogramWithWeights(const char* filePath, const char* runN } if (!sparseHist) { + LOGF(info, "\033[1;33m%s at line %d : filePath = \"%s\"\033[0m", __FUNCTION__, __LINE__, filePath); + LOGF(info, "\033[1;33m%s at line %d : runNumber = \"%s\"\033[0m", __FUNCTION__, __LINE__, runNumber); listWithRuns->ls(); LOGF(fatal, "\033[1;31m%s at line %d : couldn't fetch sparse histogram with name = %s from this list\033[0m", __FUNCTION__, __LINE__, sparseHistName.Data()); } @@ -15619,7 +16052,10 @@ double WeightFromSparse(eDiffWeightCategory dwc) if (tc.fVerbose) { StartFunction(__FUNCTION__); - } + LOGF(info, "\033[1;31m dwc = %d\033[0m", static_cast(dwc)); + LOGF(info, "\033[1;31m%s at line %d : printing current status of all weights flags\033[0m", __FUNCTION__, __LINE__); + PrintAllWeightsFlags(); + } // if (tc.fVerbose) { // *) Reduce dimensionality if possible, i.e. look up only the dimensions in sparse histogram which were requested in this analysis: int dim = 1; // yes, because dimension 0 is always reserved for each category @@ -15648,6 +16084,9 @@ double WeightFromSparse(eDiffWeightCategory dwc) case eDWPt: { pw.fFindBinVector[dwc]->AddAt(pbyp.fPt, 0); // special treatment for pt in eDWPt category // Remember that ordering here has to resemble ordering in eDiffPtWeights + if (pw.fUseDiffPtWeights[wPtEtaAxis]) { + pw.fFindBinVector[dwc]->AddAt(pbyp.fEta, dim++); + } if (pw.fUseDiffPtWeights[wPtChargeAxis]) { pw.fFindBinVector[dwc]->AddAt(pbyp.fCharge, dim++); } @@ -15663,12 +16102,30 @@ double WeightFromSparse(eDiffWeightCategory dwc) if (pw.fUseDiffEtaWeights[wEtaChargeAxis]) { pw.fFindBinVector[dwc]->AddAt(pbyp.fCharge, dim++); } + if (pw.fUseDiffEtaWeights[wEtaPtAxis]) { + pw.fFindBinVector[dwc]->AddAt(pbyp.fPt, dim++); + } if (pw.fUseDiffEtaWeights[wEtaCentralityAxis]) { pw.fFindBinVector[dwc]->AddAt(ebye.fCentrality, dim++); } // ... break; } + case eDWCharge: { + pw.fFindBinVector[dwc]->AddAt(pbyp.fCharge, 0); // special treatment for charge in eDWCharge category + // Remember that ordering here has to resemble ordering in eDiffChargeWeights + if (pw.fUseDiffChargeWeights[wChargePtAxis]) { + pw.fFindBinVector[dwc]->AddAt(pbyp.fPt, dim++); + } + if (pw.fUseDiffChargeWeights[wChargeEtaAxis]) { + pw.fFindBinVector[dwc]->AddAt(pbyp.fEta, dim++); + } + if (pw.fUseDiffChargeWeights[wChargeCentralityAxis]) { + pw.fFindBinVector[dwc]->AddAt(ebye.fCentrality, dim++); + } + // ... + break; + } default: { LOGF(fatal, "\033[1;31m%s at line %d : This differential weight category, dwc = %d, is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(dwc)); break; @@ -15828,7 +16285,8 @@ void GetParticleWeights() // b) Differential weights; => TBI 20250225 this is now obsolete and superseeded with c), where I use more general approach with sparse histograms // c) Differential phi weights using sparse histograms; // d) Differential pt weights using sparse histograms; - // e) Differential eta weights using sparse histograms. + // e) Differential eta weights using sparse histograms; + // f) Differential charge weights using sparse histograms. if (tc.fVerbose) { StartFunction(__FUNCTION__); @@ -15864,7 +16322,7 @@ void GetParticleWeights() // b) Differential weights: // differential phi(pt) weights: - if (pw.fUseDiffWeights[wPHIPT]) { + if (pw.fUseDiffWeights[wPHIPT]) { // TBI 20260217 obsolete branch, remove eventually TH1D* phiptWeights = NULL; int nPtBins = res.fResultsPro[AFO_PT]->GetXaxis()->GetNbins(); for (int b = 0; b < nPtBins; b++) { @@ -15893,7 +16351,7 @@ void GetParticleWeights() } // if (pw.fUseDiffWeights[wPHIPT]) { // differential phi(eta) weights: - if (pw.fUseDiffWeights[wPHIETA]) { + if (pw.fUseDiffWeights[wPHIETA]) { // TBI 20260217 obsolete branch, remove eventually TH1D* phietaWeights = NULL; int nEtaBins = res.fResultsPro[AFO_ETA]->GetXaxis()->GetNbins(); for (int b = 0; b < nEtaBins; b++) { @@ -15945,14 +16403,17 @@ void GetParticleWeights() } // ... - // TBI-today ... check if particle weights are avaiable for the phase window I have selected for each dimension with cuts - THnSparseF* diffWeightsSparse = GetSparseHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), whichCategory.Data(), whichDimensions.Data()); if (!diffWeightsSparse) { LOGF(fatal, "\033[1;31m%s at line %d : diffWeightsSparse for category \"phi\" is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); } - // okay, just use this sparse histogram with weights: + // Check if particle weights are avaiable for the phase window I have selected for each dimension with cuts. + // Basically, I check whether range of each axis is compatible with the cuts i used for variable on that axis. + // Since GetParticleWeights() is called only once, this check is also performed only once. + insanitizeDiffWeightsSparse(diffWeightsSparse); + + // Okay, just use this sparse histogram with weights: SetDiffWeightsSparse(diffWeightsSparse, eDWPhi); } // if (pw.fUseDiffPhiWeights[wPhiPhiAxis]) { @@ -15963,7 +16424,10 @@ void GetParticleWeights() TString whichCategory = "pt"; // differential pt weights TString whichDimensions = ""; // differential pt weights as a function of particular dimension - // Remark: the naming convention hardwired here for axes dimensions have to be in sync with what I have in the macro to make these weights + // Remark: the naming convention hardwired here for axes dimensions have to be in sync with what I have in the macro to make these weights. + if (pw.fUseDiffPtWeights[wPtEtaAxis]) { + whichDimensions += "_eta"; + } if (pw.fUseDiffPtWeights[wPtChargeAxis]) { whichDimensions += "_charge"; } @@ -15972,13 +16436,16 @@ void GetParticleWeights() } // ... - // TBI-today ... check if particles weights are avaiable for the phase window I have selected for each dimension with cuts - THnSparseF* diffWeightsSparse = GetSparseHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), whichCategory.Data(), whichDimensions.Data()); if (!diffWeightsSparse) { LOGF(fatal, "\033[1;31m%s at line %d : diffWeightsSparse for category \"pt\" is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); } + // Check if particle weights are avaiable for the phase window I have selected for each dimension with cuts. + // Basically, I check whether range of each axis is compatible with the cuts i used for variable on that axis. + // Since GetParticleWeights() is called only once, this check is also performed only once. + insanitizeDiffWeightsSparse(diffWeightsSparse); + // okay, just use this sparse histogram with weights: SetDiffWeightsSparse(diffWeightsSparse, eDWPt); @@ -15990,8 +16457,10 @@ void GetParticleWeights() TString whichCategory = "eta"; // differential eta weights TString whichDimensions = ""; // differential eta weights as a function of particular dimension - // Remark: the naming convention hardwired here for axes dimensions have to be in sync with what I have in the macro to make these weights - + // Remark: the naming convention hardwired here for axes dimensions have to be in sync with what I have in the macro to make these weights. + if (pw.fUseDiffEtaWeights[wEtaPtAxis]) { + whichDimensions += "_pt"; + } if (pw.fUseDiffEtaWeights[wEtaChargeAxis]) { whichDimensions += "_charge"; } @@ -16000,18 +16469,54 @@ void GetParticleWeights() } // ... - // TBI-today ... check if particles weights are avaiable for the phase window I have selected for each dimension with cuts - THnSparseF* diffWeightsSparse = GetSparseHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), whichCategory.Data(), whichDimensions.Data()); if (!diffWeightsSparse) { LOGF(fatal, "\033[1;31m%s at line %d : diffWeightsSparse for category \"eta\" is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); } + // Check if particle weights are avaiable for the phase window I have selected for each dimension with cuts. + // Basically, I check whether range of each axis is compatible with the cuts i used for variable on that axis. + // Since GetParticleWeights() is called only once, this check is also performed only once. + insanitizeDiffWeightsSparse(diffWeightsSparse); + // okay, just use this sparse histogram with weights: SetDiffWeightsSparse(diffWeightsSparse, eDWEta); } // if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { + // f) Differential charge weights using sparse histograms: + if (pw.fUseDiffChargeWeights[wChargeChargeAxis]) { // yes, remember that flag for charge axis serves also as a common boolean to switch off all differential charge weights + + TString whichCategory = "charge"; // differential charge weights + + TString whichDimensions = ""; // differential charge weights as a function of particular dimension + // Remark: the naming convention hardwired here for axes dimensions have to be in sync with what I have in the macro to make these weights. + if (pw.fUseDiffChargeWeights[wChargePtAxis]) { + whichDimensions += "_pt"; + } + if (pw.fUseDiffChargeWeights[wChargeEtaAxis]) { + whichDimensions += "_eta"; + } + if (pw.fUseDiffChargeWeights[wChargeCentralityAxis]) { + whichDimensions += "_centrality"; + } + // ... + + THnSparseF* diffWeightsSparse = GetSparseHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), whichCategory.Data(), whichDimensions.Data()); + if (!diffWeightsSparse) { + LOGF(fatal, "\033[1;31m%s at line %d : diffWeightsSparse for category \"charge\" is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); + } + + // Check if particle weights are avaiable for the phase window I have selected for each dimension with cuts. + // Basically, I check whether range of each axis is compatible with the cuts i used for variable on that axis. + // Since GetParticleWeights() is called only once, this check is also performed only once. + insanitizeDiffWeightsSparse(diffWeightsSparse); + + // okay, just use this sparse histogram with weights: + SetDiffWeightsSparse(diffWeightsSparse, eDWCharge); + + } // if (pw.fUseDiffChargeWeights[wChargeChargeAxis]) { + if (tc.fVerbose) { ExitFunction(__FUNCTION__); } @@ -16240,6 +16745,9 @@ void EventCounterForDryRun(eEventCounterForDryRun eVar) const char* FancyFormatting(const char* name) { // Simple utility function to convert ordinary name into fancier formatting. + // If I change something in the formatting here, check if that fancy formatting was hardwired elsewhere, e.g. in void insanitizeDiffWeightsSparse(...) + + // :ff // Examples: // 1. use LaTeX syntax (as supported by ROOT!), for the case when it's possible (e.g. "Phi" => "#{varphi}"); @@ -17985,13 +18493,14 @@ void FillQvectorFromSparse() double wPhi = 1.; // differential multidimensional phi weight, its dimensions are defined via enum eDiffPhiWeights double wPt = 1.; // differential multidimensional pt weight, its dimensions are defined via enum eDiffPtWeights double wEta = 1.; // differential multidimensional eta weight, its dimensions are defined via enum eDiffEtaWeights + double wCharge = 1.; // differential multidimensional charge weight, its dimensions are defined via enum eDiffChargeWeights double wToPowerP = 1.; // weight raised to power p // *) Multidimensional phi weights: if (pw.fUseDiffPhiWeights[wPhiPhiAxis]) { // yes, 0th axis serves as a common boolean for this category wPhi = WeightFromSparse(eDWPhi); if (!(wPhi > 0.)) { - LOGF(error, "\033[1;33m%s wPhi is not positive\033[0m", __FUNCTION__); + LOGF(error, "\033[1;33m%s at line %d : wPhi is not positive\033[0m", __FUNCTION__, __LINE__); LOGF(error, "pbyp.fPhi = %f", pbyp.fPhi); if (pw.fUseDiffPhiWeights[wPhiPtAxis]) { LOGF(fatal, "pbyp.fPt = %f", pbyp.fPt); @@ -18016,8 +18525,11 @@ void FillQvectorFromSparse() if (pw.fUseDiffPtWeights[wPtPtAxis]) { // yes, 0th axis serves as a common boolean for this category wPt = WeightFromSparse(eDWPt); if (!(wPt > 0.)) { - LOGF(error, "\033[1;33m%s wPt is not positive\033[0m", __FUNCTION__); + LOGF(error, "\033[1;33m%s at line %d : wPt is not positive\033[0m", __FUNCTION__, __LINE__); LOGF(error, "pbyp.fPt = %f", pbyp.fPt); + if (pw.fUseDiffPtWeights[wPtEtaAxis]) { + LOGF(fatal, "pbyp.fEta = %f", pbyp.fEta); + } if (pw.fUseDiffPtWeights[wPtChargeAxis]) { LOGF(fatal, "pbyp.fCharge = %f", pbyp.fCharge); } @@ -18032,8 +18544,11 @@ void FillQvectorFromSparse() if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { // yes, 0th axis serves as a common boolean for this category wEta = WeightFromSparse(eDWEta); if (!(wEta > 0.)) { - LOGF(error, "\033[1;33m%s wEta is not positive\033[0m", __FUNCTION__); + LOGF(error, "\033[1;33m%s at line %d : wEta is not positive\033[0m", __FUNCTION__, __LINE__); LOGF(error, "pbyp.fEta = %f", pbyp.fEta); + if (pw.fUseDiffEtaWeights[wEtaPtAxis]) { + LOGF(fatal, "pbyp.fPt = %f", pbyp.fPt); + } if (pw.fUseDiffEtaWeights[wEtaChargeAxis]) { LOGF(fatal, "pbyp.fCharge = %f", pbyp.fCharge); } @@ -18044,11 +18559,30 @@ void FillQvectorFromSparse() } } // if(pw.fUseDiffEtaWeights[wEtaEtaAxis]) + // *) Multidimensional charge weights: + if (pw.fUseDiffChargeWeights[wChargeChargeAxis]) { // yes, 0th axis serves as a common boolean for this category + wCharge = WeightFromSparse(eDWCharge); + if (!(wCharge > 0.)) { + LOGF(error, "\033[1;33m%s at line %d : wCharge is not positive\033[0m", __FUNCTION__, __LINE__); + LOGF(error, "pbyp.fCharge = %f", pbyp.fCharge); + if (pw.fUseDiffChargeWeights[wChargePtAxis]) { + LOGF(fatal, "pbyp.fPt = %f", pbyp.fPt); + } + if (pw.fUseDiffChargeWeights[wChargeEtaAxis]) { + LOGF(fatal, "pbyp.fEta = %f", pbyp.fEta); + } + if (pw.fUseDiffChargeWeights[wChargeCentralityAxis]) { + LOGF(fatal, "ebye.fCentrality = %f", ebye.fCentrality); + } + LOGF(fatal, "Multidimensional weight for enabled dimensions is wCharge = %f", wCharge); + } + } // if(pw.fUseDiffChargeWeights[wChargeChargeAxis]) + if (qv.fCalculateQvectors) { for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power - if (pw.fUseDiffPhiWeights[wPhiPhiAxis] || pw.fUseDiffPtWeights[wPtPtAxis] || pw.fUseDiffEtaWeights[wEtaEtaAxis]) { - wToPowerP = std::pow(wPhi * wPt * wEta, wp); + if (pw.fUseDiffPhiWeights[wPhiPhiAxis] || pw.fUseDiffPtWeights[wPtPtAxis] || pw.fUseDiffEtaWeights[wEtaEtaAxis] || pw.fUseDiffChargeWeights[wChargeChargeAxis]) { + wToPowerP = std::pow(wPhi * wPt * wEta * wCharge, wp); qv.fQvector[h][wp] += TComplex(wToPowerP * std::cos(h * pbyp.fPhi), wToPowerP * std::sin(h * pbyp.fPhi)); // Q-vector with weights, legacy code (TBI 20251027 remove this line) // qv.fQvector[h][wp] += std::complex(wToPowerP * std::cos(h * pbyp.fPhi), wToPowerP * std::sin(h * pbyp.fPhi)); // Q-vector with weights, new code // TBI 20251028 I have to keep it this way for the time being, otherwise I have to change all over the place, e.g. in TComplex Q(int n, int wp), etc. @@ -18066,12 +18600,12 @@ void FillQvectorFromSparse() if (pbyp.fEta < 0.) { for (int e = 0; e < gMaxNumberEtaSeparations; e++) { if (pbyp.fEta < -1. * es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 - qv.fMab[0][e] += wPhi * wPt * wEta; + qv.fMab[0][e] += wPhi * wPt * wEta * wCharge; for (int h = 0; h < gMaxHarmonic; h++) { if (es.fEtaSeparationsSkipHarmonics[h]) { continue; } - qv.fQabVector[0][h][e] += TComplex(wPhi * wPt * wEta * std::cos((h + 1) * pbyp.fPhi), wPhi * wPt * wEta * std::sin((h + 1) * pbyp.fPhi)); + qv.fQabVector[0][h][e] += TComplex(wPhi * wPt * wEta * wCharge * std::cos((h + 1) * pbyp.fPhi), wPhi * wPt * wEta * wCharge * std::sin((h + 1) * pbyp.fPhi)); // Remark: I can hardwire linear weights like this only for 2-p correlations // TBI 20251028 Replace TComplex with std::complex (but it's a major modification, see the comment above within if (qv.fCalculateQvectors) ) } @@ -18080,13 +18614,13 @@ void FillQvectorFromSparse() } else if (pbyp.fEta > 0.) { for (int e = 0; e < gMaxNumberEtaSeparations; e++) { if (pbyp.fEta > es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 - qv.fMab[1][e] += wPhi * wPt * wEta; + qv.fMab[1][e] += wPhi * wPt * wEta * wCharge; for (int h = 0; h < gMaxHarmonic; h++) { { if (es.fEtaSeparationsSkipHarmonics[h]) { continue; } - qv.fQabVector[1][h][e] += TComplex(wPhi * wPt * wEta * std::cos((h + 1) * pbyp.fPhi), wPhi * wPt * wEta * std::sin((h + 1) * pbyp.fPhi)); + qv.fQabVector[1][h][e] += TComplex(wPhi * wPt * wEta * wCharge * std::cos((h + 1) * pbyp.fPhi), wPhi * wPt * wEta * wCharge * std::sin((h + 1) * pbyp.fPhi)); // TBI 20251028 Replace TComplex with std::complex (but it's a major modification, see the comment above within if (qv.fCalculateQvectors) ) // Remark: I can hardwire linear weights like this only for 2-p correlations } @@ -18737,7 +19271,7 @@ void Fillqvectors() { // In this function, I fill all requested differential q-vectors, by calling for each requested case a helper function FillqvectorFromSparse(...). - // :44 + // :fqv if (tc.fVerboseForEachParticle) { StartFunction(__FUNCTION__); @@ -18748,10 +19282,11 @@ void Fillqvectors() } // *) Local variables: - int bin = -1; // global kine bin - double wPhi = 1.; // differential multidimensional phi weight, its dimensions are defined via enum eDiffPhiWeights - double wPt = 1.; // differential multidimensional pt weight, its dimensions are defined via enum eDiffPtWeights - double wEta = 1.; // differential multidimensional eta weight, its dimensions are defined via enum eDiffEtaWeights + int bin = -1; // global kine bin + double wPhi = 1.; // differential multidimensional phi weight, its dimensions are defined via enum eDiffPhiWeights + double wPt = 1.; // differential multidimensional pt weight, its dimensions are defined via enum eDiffPtWeights + double wEta = 1.; // differential multidimensional eta weight, its dimensions are defined via enum eDiffEtaWeights + double wCharge = 1.; // differential multidimensional eta weight, its dimensions are defined via enum eDiffChargeWeights /* // TBT // TBI 20250528 check if the test below is computationally heavy. If so, add the flag tc.fInsanityCheckForEachParticle here. @@ -18777,9 +19312,17 @@ void Fillqvectors() if (pw.fUseDiffPtWeights[wPtPtAxis]) { wPt = WeightFromSparse(eDWPt); } + // w_eta(pt): + if (pw.fUseDiffEtaWeights[wEtaPtAxis]) { + wEta = WeightFromSparse(eDWEta); + } + // w_charge(pt): + if (pw.fUseDiffChargeWeights[wChargePtAxis]) { + wCharge = WeightFromSparse(eDWCharge); + } // ****) finally, fill: - FillqvectorFromSparse(PTq, bin, wPhi * wPt * wEta); // weighted q(pT) filled for global bin to which this pT corresponds + FillqvectorFromSparse(PTq, bin, wPhi * wPt * wEta * wCharge); // weighted q(pT) filled for global bin to which this pT corresponds } // if(tc.fCalculateAsFunctionOf[AFO_PT]) @@ -18794,13 +19337,21 @@ void Fillqvectors() if (pw.fUseDiffPhiWeights[wPhiEtaAxis]) { wPhi = WeightFromSparse(eDWPhi); } + // w_pt(eta): + if (pw.fUseDiffPtWeights[wPtEtaAxis]) { + wPt = WeightFromSparse(eDWPt); + } // w_eta(eta): if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { wEta = WeightFromSparse(eDWEta); } + // w_charge(eta): + if (pw.fUseDiffChargeWeights[wChargeEtaAxis]) { + wCharge = WeightFromSparse(eDWCharge); + } // ****) finally, fill: - FillqvectorFromSparse(ETAq, bin, wPhi * wPt * wEta); // weighted q(eta) filled for global bin to which this eta corresponds + FillqvectorFromSparse(ETAq, bin, wPhi * wPt * wEta * wCharge); // weighted q(eta) filled for global bin to which this eta corresponds } // if (mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA] || t0.fCalculateTest0AsFunctionOf[AFO_ETA]) @@ -18817,15 +19368,19 @@ void Fillqvectors() } // w_pt(charge): if (pw.fUseDiffPtWeights[wPtChargeAxis]) { - wPt = WeightFromSparse(eDWPhi); + wPt = WeightFromSparse(eDWPt); } // w_eta(charge): if (pw.fUseDiffEtaWeights[wEtaChargeAxis]) { - wEta = WeightFromSparse(eDWPhi); + wEta = WeightFromSparse(eDWEta); + } + // w_charge(charge): + if (pw.fUseDiffChargeWeights[wChargeChargeAxis]) { + wCharge = WeightFromSparse(eDWCharge); } // ****) finally, fill: - FillqvectorFromSparse(CHARGEq, bin, wPhi * wPt * wEta); // weighted q(charge) filled for global bin to which this charge corresponds + FillqvectorFromSparse(CHARGEq, bin, wPhi * wPt * wEta * wCharge); // weighted q(charge) filled for global bin to which this charge corresponds } // if (mupa.fCalculateCorrelationsAsFunctionOf[AFO_CHARGE] || t0.fCalculateTest0AsFunctionOf[AFO_CHARGE]) @@ -18844,8 +19399,23 @@ void Fillqvectors() wPhi = WeightFromSparse(eDWPhi); } + // w_pt(pt,eta): + if (pw.fUseDiffPtWeights[wPtPtAxis] && pw.fUseDiffPtWeights[wPtEtaAxis]) { + wPt = WeightFromSparse(eDWPt); + } + + // w_eta(pt,eta): + if (pw.fUseDiffEtaWeights[wEtaPtAxis] && pw.fUseDiffEtaWeights[wEtaEtaAxis]) { + wEta = WeightFromSparse(eDWEta); + } + + // w_charge(pt,eta): + if (pw.fUseDiffChargeWeights[wChargePtAxis] && pw.fUseDiffChargeWeights[wChargeEtaAxis]) { + wCharge = WeightFromSparse(eDWCharge); + } + // ****) finally, fill: - FillqvectorFromSparse(PT_ETAq, bin, wPhi * wPt * wEta); // weighted q(pt,eta) filled for global bin to which this (pt,eta) corresponds + FillqvectorFromSparse(PT_ETAq, bin, wPhi * wPt * wEta * wCharge); // weighted q(pt,eta) filled for global bin to which this (pt,eta) corresponds } // if (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_ETA] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA]) @@ -18860,9 +19430,21 @@ void Fillqvectors() if (pw.fUseDiffPhiWeights[wPhiPtAxis] && pw.fUseDiffPhiWeights[wPhiChargeAxis]) { wPhi = WeightFromSparse(eDWPhi); } + // w_pt(pt,charge): + if (pw.fUseDiffPtWeights[wPtPtAxis] && pw.fUseDiffPtWeights[wPtChargeAxis]) { + wPt = WeightFromSparse(eDWPt); + } + // w_eta(pt,charge): + if (pw.fUseDiffEtaWeights[wEtaPtAxis] && pw.fUseDiffEtaWeights[wEtaChargeAxis]) { + wEta = WeightFromSparse(eDWEta); + } + // w_charge(pt,charge): + if (pw.fUseDiffChargeWeights[wChargePtAxis] && pw.fUseDiffChargeWeights[wChargeChargeAxis]) { + wCharge = WeightFromSparse(eDWCharge); + } // ****) finally, fill: - FillqvectorFromSparse(PT_CHARGEq, bin, wPhi * wPt * wEta); // weighted q(pt,charge) filled for global bin to which this (pt,charge) corresponds + FillqvectorFromSparse(PT_CHARGEq, bin, wPhi * wPt * wEta * wCharge); // weighted q(pt,charge) filled for global bin to which this (pt,charge) corresponds } // if (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE]) @@ -18874,12 +19456,24 @@ void Fillqvectors() // ****) determine all supported particle weights: // w_phi(eta,charge): - if (pw.fUseDiffPhiWeights[wEtaChargeAxis] && pw.fUseDiffPhiWeights[wPhiChargeAxis]) { + if (pw.fUseDiffPhiWeights[wPhiEtaAxis] && pw.fUseDiffPhiWeights[wPhiChargeAxis]) { wPhi = WeightFromSparse(eDWPhi); } + // w_pt(eta,charge): + if (pw.fUseDiffPtWeights[wPtEtaAxis] && pw.fUseDiffPtWeights[wPtChargeAxis]) { + wPt = WeightFromSparse(eDWPt); + } + // w_eta(eta,charge): + if (pw.fUseDiffEtaWeights[wEtaEtaAxis] && pw.fUseDiffEtaWeights[wEtaChargeAxis]) { + wEta = WeightFromSparse(eDWEta); + } + // w_charge(eta,charge): + if (pw.fUseDiffChargeWeights[wChargeEtaAxis] && pw.fUseDiffChargeWeights[wChargeChargeAxis]) { + wCharge = WeightFromSparse(eDWCharge); + } // ****) finally, fill: - FillqvectorFromSparse(ETA_CHARGEq, bin, wPhi * wPt * wEta); // weighted q(eta,charge) filled in global bin to which this (eta,charge) corresponds + FillqvectorFromSparse(ETA_CHARGEq, bin, wPhi * wPt * wEta * wCharge); // weighted q(eta,charge) filled in global bin to which this (eta,charge) corresponds } // if (t0.fCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE]) @@ -18898,9 +19492,21 @@ void Fillqvectors() if (pw.fUseDiffPhiWeights[wPhiPtAxis] && pw.fUseDiffPhiWeights[wPhiEtaAxis] && pw.fUseDiffPhiWeights[wPhiChargeAxis]) { wPhi = WeightFromSparse(eDWPhi); } + // w_pt(pt,eta,charge): + if (pw.fUseDiffPtWeights[wPtPtAxis] && pw.fUseDiffPtWeights[wPtEtaAxis] && pw.fUseDiffPtWeights[wPtChargeAxis]) { + wPt = WeightFromSparse(eDWPt); + } + // w_eta(pt,eta,charge): + if (pw.fUseDiffEtaWeights[wEtaPtAxis] && pw.fUseDiffEtaWeights[wEtaEtaAxis] && pw.fUseDiffEtaWeights[wEtaChargeAxis]) { + wEta = WeightFromSparse(eDWEta); + } + // w_charge(pt,eta,charge): + if (pw.fUseDiffChargeWeights[wChargePtAxis] && pw.fUseDiffChargeWeights[wChargeEtaAxis] && pw.fUseDiffChargeWeights[wChargeChargeAxis]) { + wCharge = WeightFromSparse(eDWCharge); + } // ****) finally, fill: - FillqvectorFromSparse(PT_ETA_CHARGEq, bin, wPhi * wPt * wEta); // weighted q(pt,eta,charge) filled in global bin to which this (pt,eta,charge) corresponds + FillqvectorFromSparse(PT_ETA_CHARGEq, bin, wPhi * wPt * wEta * wCharge); // weighted q(pt,eta,charge) filled in global bin to which this (pt,eta,charge) corresponds } if (tc.fVerboseForEachParticle) { @@ -18926,10 +19532,10 @@ void FillqvectorFromSparse(const eqvectorKine& kineVarChoice, const int& bin, co double wToPowerP = 1.; // weight raised to power p for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power - if (pw.fUseDiffPhiWeights[wPhiPhiAxis] || pw.fUseDiffPtWeights[wPtPtAxis] || pw.fUseDiffEtaWeights[wEtaEtaAxis]) { // yes, because the first enum serves as a boolean for that category - wToPowerP = std::pow(dWeight, wp); // dWeight = wPhi * wPt * wEta - qv.fqvector[kineVarChoice][bin][h][wp] += std::complex(wToPowerP * std::cos(h * pbyp.fPhi), wToPowerP * std::sin(h * pbyp.fPhi)); // q-vector with weights + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + if (pw.fUseDiffPhiWeights[wPhiPhiAxis] || pw.fUseDiffPtWeights[wPtPtAxis] || pw.fUseDiffEtaWeights[wEtaEtaAxis] || pw.fUseDiffChargeWeights[wChargeChargeAxis]) { // yes, because the first enum serves as a boolean for that category + wToPowerP = std::pow(dWeight, wp); // dWeight = wPhi * wPt * wEta * wcharge + qv.fqvector[kineVarChoice][bin][h][wp] += std::complex(wToPowerP * std::cos(h * pbyp.fPhi), wToPowerP * std::sin(h * pbyp.fPhi)); // q-vector with weights } else { qv.fqvector[kineVarChoice][bin][h][wp] += std::complex(std::cos(h * pbyp.fPhi), std::sin(h * pbyp.fPhi)); // bare q-vector without weights } @@ -18939,7 +19545,7 @@ void FillqvectorFromSparse(const eqvectorKine& kineVarChoice, const int& bin, co // *) Differential nested loops: if (nl.fCalculateKineCustomNestedLoops) { nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->AddAt(pbyp.fPhi, qv.fqvectorEntries[kineVarChoice][bin]); - nl.ftaNestedLoopsKine[kineVarChoice][bin][1]->AddAt(dWeight, qv.fqvectorEntries[kineVarChoice][bin]); // dWeight = wPhi * wPt * wEta + nl.ftaNestedLoopsKine[kineVarChoice][bin][1]->AddAt(dWeight, qv.fqvectorEntries[kineVarChoice][bin]); // dWeight = wPhi * wPt * wEta * wCharge } // *) Multiplicity counter in this bin: @@ -18955,25 +19561,25 @@ void FillqvectorFromSparse(const eqvectorKine& kineVarChoice, const int& bin, co if (pbyp.fEta < 0.) { for (int e = 0; e < gMaxNumberEtaSeparations; e++) { if (pbyp.fEta < -1. * es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 - qv.fmab[0][kineVarChoice][bin][e] += dWeight; // dWeight = wPhi * wPt * wEta => Remark: I can hardwire linear weight like this only for 2-p correlation + qv.fmab[0][kineVarChoice][bin][e] += dWeight; // dWeight = wPhi * wPt * wEta * wCharge => Remark: I can hardwire linear weight like this only for 2-p correlation for (int h = 0; h < gMaxHarmonic; h++) { if (es.fEtaSeparationsSkipHarmonics[h]) { continue; } - qv.fqabVector[0][kineVarChoice][bin][h][e] += std::complex(dWeight * std::cos((h + 1) * pbyp.fPhi), dWeight * std::sin((h + 1) * pbyp.fPhi)); // dWeight = wPhi * wPt * wEta => Remark: I can hardwire linear weight like this only for 2-p correlation + qv.fqabVector[0][kineVarChoice][bin][h][e] += std::complex(dWeight * std::cos((h + 1) * pbyp.fPhi), dWeight * std::sin((h + 1) * pbyp.fPhi)); // dWeight = wPhi * wPt * wEta * wCharge => Remark: I can hardwire linear weight like this only for 2-p correlation } } // for (int h = 0; h < gMaxHarmonic; h++) { } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation } else if (pbyp.fEta > 0.) { for (int e = 0; e < gMaxNumberEtaSeparations; e++) { if (pbyp.fEta > es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 - qv.fmab[1][kineVarChoice][bin][e] += dWeight; // dWeight = wPhi * wPt * wEta => Remark: I can hardwire linear weight like this only for 2-p correlation + qv.fmab[1][kineVarChoice][bin][e] += dWeight; // dWeight = wPhi * wPt * wEta * wCharge => Remark: I can hardwire linear weight like this only for 2-p correlation for (int h = 0; h < gMaxHarmonic; h++) { { if (es.fEtaSeparationsSkipHarmonics[h]) { continue; } - qv.fqabVector[1][kineVarChoice][bin][h][e] += std::complex(dWeight * std::cos((h + 1) * pbyp.fPhi), dWeight * std::sin((h + 1) * pbyp.fPhi)); // dWeight = wPhi * wPt * wEta => Remark: I can hardwire linear weight like this only for 2-p correlation + qv.fqabVector[1][kineVarChoice][bin][h][e] += std::complex(dWeight * std::cos((h + 1) * pbyp.fPhi), dWeight * std::sin((h + 1) * pbyp.fPhi)); // dWeight = wPhi * wPt * wEta * wCharge => Remark: I can hardwire linear weight like this only for 2-p correlation } } // for (int h = 0; h < gMaxHarmonic; h++) { } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation @@ -19230,7 +19836,7 @@ void MainLoopOverParticles(T const& tracks) // *) Fill nested loops containers (integrated => I fill kine containers for nested loops in FillqvectorNdim(...)): if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) { - this->FillNestedLoopsContainers(ebye.fSelectedTracks); // all 4 arguments are passed by reference + this->FillNestedLoopsContainers(ebye.fSelectedTracks); // all 4 arguments are passed by reference => not true any longer, I have now 4 pbyp data members } // *) Counter of selected tracks in the current event: @@ -19431,7 +20037,19 @@ void Steer(T1 const& collision, T2 const& bcs, T3 const& tracks) ExitFunction(__FUNCTION__); } - // memStatus (summary): Last update: 20250602 + // memStatus (summary): Status at 20260218 (wf-13.sh + file 2023/LHC23zzh/544116/apass5/0140/o2_ctf_run00544116_orbit0034437888_tf0000000601_epn103/008/AO2D.root) + // Remark: disable sequential bailout before doing this test (yes!) + all of UseSetBinLabel, ... UseDatabasetPDG + // ~47K (dry run with 1D objects booked) + // ~61K (all object declaration besides kine objects (diff. q-vectors and eta separations) + all calculus and 1D histograms filled, trivial labels) + // ~61K (all object declaration + 1D kine objects (diff. q-vectors in coarse kine bins: 2 bins in pt and 2 in eta) + all calculus and 1D histograms filled, standard labels) + // ~61K (all object declaration + 1D kine objects (diff. q-vectors in fine kine bins: 16 bins in pt and 10 in eta) + all calculus and 1D histograms filled, standard labels) + // ~62K (all object declaration + 1D kine objects (diff. q-vectors in fine kine bins: 16 bins in pt and 10 in eta) + all calculus and 1D histograms filled, Set_0 labels + // + all 3 sparse histograms only after the cuts) + // ~80K (all object declaration + 1D kine objects (diff. q-vectors in fine kine bins: 16 bins in pt and 10 in eta) + all calculus and 1D histograms filled, Set_0 labels + // + all 3 sparse histograms before and after the cuts) + // ~102K (all object declaration + 1D + 2D + 3D kine objects (diff. q-vectors in fine kine bins: same as above) + all calculus and 1D histograms filled, Set_0 labels) + + // memStatus (summary): Status at 20250602 // Remark: disable sequential bailout before doing this test (yes!) + all of UseSetBinLabel, ... UseDatabasetPDG // ~46K (skeleton - literally) // ~50K (dry run with 1D objects booked) diff --git a/PWGCF/TableProducer/dptDptFilter.cxx b/PWGCF/TableProducer/dptDptFilter.cxx index 86db0a8ce95..dd703f3b3c3 100644 --- a/PWGCF/TableProducer/dptDptFilter.cxx +++ b/PWGCF/TableProducer/dptDptFilter.cxx @@ -128,7 +128,7 @@ static constexpr float MultiplicityUpperLimitBase[11][8] = { }; /* helpers for the multiplicity/centrality correlations exclusion formulae */ -static const std::string multiplicityCentralityCorrelationsFormulaBase[11][1] = { +static const std::string multiplicityCentralityCorrelationsFormulaBase[11][1] = { // NOLINT /* no system */ {""}, /* pp Run2 */ {""}, /* pPb Run2 */ {""}, @@ -142,7 +142,7 @@ static const std::string multiplicityCentralityCorrelationsFormulaBase[11][1] = /* pO Run3 */ {""}}; /* helpers for the system type assignment */ -static const std::string periodsOnSystemType[11][1] = { +static const std::string periodsOnSystemType[11][1] = { // NOLINT /* no system */ {""}, /* pp Run2 */ {""}, /* pPb Run2 */ {""}, @@ -316,8 +316,8 @@ struct Multiplicity { MultEst classestimator = kV0M; - static constexpr float kForMultiplicityPtLowLimit = 0.001f; - static constexpr float kForMultiplicityPtHighLimit = 50.0f; + static constexpr float KForMultiplicityPtLowLimit = 0.001f; + static constexpr float KForMultiplicityPtHighLimit = 50.0f; float multiplicityClass = -1.0; float multiplicity = 0.0; bool inelgth0 = false; @@ -353,7 +353,7 @@ struct Multiplicity { void setMultiplicityPercentiles(TList* list) { - LOGF(info, "setMultiplicityPercentiles()", "From list %s", list->GetName()); + LOGF(info, "setMultiplicityPercentiles(). From list %s", list->GetName()); fhV0MMultPercentile = reinterpret_cast(list->FindObject("V0MCentMult")); fhCL1MultPercentile = reinterpret_cast(list->FindObject("CL1MCentMult")); fhCL1EtaGapMultPercentile = reinterpret_cast(list->FindObject("CL1EtaGapMCentMult")); @@ -385,7 +385,7 @@ struct Multiplicity { case kProton: /* not clear if we should use IsPhysicalPrimary here */ /* TODO: adapt to FT0M Run 3 and other estimators */ - if (kForMultiplicityPtLowLimit < p.pt() && p.pt() < kForMultiplicityPtHighLimit) { + if (KForMultiplicityPtLowLimit < p.pt() && p.pt() < KForMultiplicityPtHighLimit) { if (p.eta() < 1.0f && -1.0f < p.eta()) { inelgth0 = true; } @@ -434,24 +434,28 @@ struct Multiplicity { if (fhCL1EtaGapMultiplicity != nullptr) { fhCL1EtaGapMultiplicity->Fill(cl1EtaGapM, dNchdEta); } + /* if there is not calibration assign 50% mutltiplicity */ + if (fhV0MMultPercentile == nullptr && fhCL1MultPercentile == nullptr && fhCL1EtaGapMultPercentile == nullptr) { + multiplicityClass = 50; + } switch (classestimator) { case kV0M: if (fhV0MMultPercentile != nullptr) { multiplicityClass = fhV0MMultPercentile->GetBinContent(fhV0MMultPercentile->FindFixBin(v0am + v0cm)); - multiplicity = v0am + v0cm; } + multiplicity = v0am + v0cm; break; case kCL1: if (fhCL1MultPercentile != nullptr) { multiplicityClass = fhCL1MultPercentile->GetBinContent(fhCL1MultPercentile->FindFixBin(cl1m)); - multiplicity = cl1m; } + multiplicity = cl1m; break; case kCL1GAP: if (fhCL1EtaGapMultPercentile != nullptr) { multiplicityClass = fhCL1EtaGapMultPercentile->GetBinContent(fhCL1EtaGapMultPercentile->FindFixBin(cl1EtaGapM)); - multiplicity = cl1EtaGapM; } + multiplicity = cl1EtaGapM; break; default: break; @@ -541,8 +545,10 @@ struct DptDptFilter { Configurable url{"url", "http://ccdb-test.cern.ch:8080", "The CCDB url for the input file"}; Configurable pathNameCorrections{"pathNameCorrections", "", "The CCDB path for the corrections file. Default \"\", i.e. don't load from CCDB"}; Configurable pathNamePID{"pathNamePID", "", "The CCDB path for the PID adjusts file. Default \"\", i.e. don't load from CCDB"}; + Configurable pathNameOTF{"pathNameOTF", "", "The CCDB path for the OTF configuration file. Default \"\", i.e. don't load from CCDB"}; Configurable dateCorrections{"dateCorrections", "20220307", "The CCDB date for the corrections input file"}; Configurable datePID{"datePID", "20220307", "The CCDB date for the PID adjustments input file"}; + Configurable dateOTF{"dateOTF", "20260306", "The CCDB date for the OTF configuration file"}; Configurable suffix{"suffix", "", "Dataset period suffix for metadata discrimination"}; } cfginputfile; Configurable cfgFullDerivedData{"cfgFullDerivedData", false, "Produce the full derived data for external storage. Default false"}; @@ -591,9 +597,12 @@ struct DptDptFilter { Produces gencollisionsinfo; Multiplicity multiplicity; + std::string otfGenerator; + Service ccdb; + bool storedCcdbInfo = false; Preslice perCollision = aod::track::collisionId; - void init(InitContext const&) + void init(InitContext& initContext) { using namespace dptdptfilter; @@ -639,10 +648,25 @@ struct DptDptFilter { triggerSelectionFlags = getTriggerSelection(cfgEventSelection.triggSel.value.c_str()); traceCollId0 = cfgTraceCollId0; - /* get the system type */ - fSystem = getSystemType(cfgSystemForPeriod.value); - fLhcRun = multRunForSystemMap.at(fSystem); + /* get the data type and the system type */ fDataType = getDataType(cfgDataType); + if (fDataType != kOnTheFly) { + fSystem = getSystemType(cfgSystemForPeriod.value); + fLhcRun = multRunForSystemMap.at(fSystem); + } else { + std::string tmpstr; + getTaskOptionValue(initContext, "generator-task", "configFile", tmpstr, false); + TString fullPath = tmpstr; + auto tokens = fullPath.Tokenize("/"); + if (tokens->GetEntries() > 0) { + otfGenerator = TString(tokens->At(tokens->GetEntries() - 1)->GetName()).ReplaceAll(".ini", ""); + } else { + /* let's take it from the time being from the data type string */ + otfGenerator = TString(cfgDataType).ReplaceAll("OnTheFlyMC_", ""); + } + delete tokens; + LOGF(info, "The generator configuration file: %s", otfGenerator.c_str()); + } /* the multiplicities outliers exclusion */ multiplicityCentralityCorrelationsExclusion = getExclusionFormula(cfgEventSelection.multiplicitiesExclusionFormula->getData()[fSystem][0].c_str()); @@ -762,6 +786,23 @@ struct DptDptFilter { fOutputList->Add(fhTrueVertexZAA); } } + /* initialize access to the CCDB */ + ccdb->setURL(cfginputfile.url); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + + void getCCDBInformation() + { + /* let's get a potential OTF configuration */ + if ((cfginputfile.dateOTF.value.length() > 0) && (cfginputfile.pathNameOTF.value.length() > 0) && !storedCcdbInfo) { + LOGF(info, "Getting information for OTF configuration from %s, at %s", cfginputfile.pathNameOTF.value.c_str(), cfginputfile.dateOTF.value.c_str()); + TList* otfinfo = getCCDBInput(ccdb, cfginputfile.pathNameOTF.value.c_str(), cfginputfile.dateOTF.value.c_str(), true, otfGenerator); + if (otfinfo != nullptr) { + multiplicity.setMultiplicityPercentiles(otfinfo); + } + storedCcdbInfo = true; + } } template @@ -1052,6 +1093,8 @@ void DptDptFilter::processOnTheFlyGeneratorLevel(aod::McCollision const& mccolli fhTrueVertexZB->Fill(mccollision.posZ()); /* we assign a default value for the time being */ float centormult = 50.0f; + /* ask for configuration */ + getCCDBInformation(); if (isEventSelected(mccollision, centormult)) { acceptedEvent = true; multiplicity.extractMultiplicity(mcparticles); @@ -1200,13 +1243,13 @@ struct DptDptFilterTracks { tpcExcluder = TpcExcludeTrack(tpcExclude); tpcExcluder.setCuts(pLowCut, pUpCut, nLowCut, nUpCut); - /* self configure system type and data type */ - o2::framework::LabeledArray tmpLabeledArray = {}; - getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgSystemForPeriod", tmpLabeledArray, false); - fSystem = getSystemType(tmpLabeledArray); + /* self configure data type and system */ std::string tmpstr; getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgDataType", tmpstr, false); fDataType = getDataType(tmpstr); + o2::framework::LabeledArray tmpLabeledArray = {}; + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgSystemForPeriod", tmpLabeledArray, false); + fSystem = getSystemType(tmpLabeledArray); /* required ambiguous tracks checks? */ if (dofilterDetectorLevelWithoutPIDAmbiguous || dofilterDetectorLevelWithPIDAmbiguous || dofilterDetectorLevelWithFullPIDAmbiguous || diff --git a/PWGCF/TableProducer/dptDptFilter.h b/PWGCF/TableProducer/dptDptFilter.h index 1d431bbde3f..9c51fbbf60a 100644 --- a/PWGCF/TableProducer/dptDptFilter.h +++ b/PWGCF/TableProducer/dptDptFilter.h @@ -809,6 +809,23 @@ struct DptDptTrackSelection { bool requirePvContributor = false; }; +SystemType fSystem = SystemNoSystem; +MultRunType fLhcRun = MultRunRUN1RUN2; +DataType fDataType = kData; +CentMultEstimatorType fCentMultEstimator = CentMultV0M; +OccupancyEstimationType fOccupancyEstimation = OccupancyNOOCC; /* the occupancy estimator to use */ + +float fMinOccupancy = 0.0f; /* the minimum allowed occupancy */ +float fMaxOccupancy = 1e6f; /* the maximum allowed occupancy */ + +/* adaptations for the pp nightly checks */ +analysis::CheckRangeCfg traceDCAOutliers; +bool traceOutOfSpeciesParticles = false; +int recoIdMethod = 0; +float particleMaxDCAxy = 999.9f; +float particleMaxDCAZ = 999.9f; +bool traceCollId0 = false; + inline TList* getCCDBInput(auto& ccdb, const char* ccdbpath, const char* ccdbdate, bool periodInPath = false, const std::string& suffix = "") { std::tm cfgtm = {}; @@ -826,13 +843,20 @@ inline TList* getCCDBInput(auto& ccdb, const char* ccdbpath, const char* ccdbdat return tmpStr; }; - std::string actualPeriod = cleanPeriod(metadataInfo.get("LPMProductionTag")); + std::string actualPeriod; + if (fDataType != kOnTheFly) { + actualPeriod = cleanPeriod(metadataInfo.get("LPMProductionTag")); + } else { + actualPeriod = suffix; + } std::string actualPath = ccdbpath; if (periodInPath) { actualPath = actualPath + "/" + actualPeriod; } - if (suffix.length() > 0) { - actualPeriod = actualPeriod + "_" + suffix; + if (fDataType != kOnTheFly) { + if (suffix.length() > 0) { + actualPeriod = actualPeriod + "_" + suffix; + } } TList* lst = nullptr; @@ -846,23 +870,6 @@ inline TList* getCCDBInput(auto& ccdb, const char* ccdbpath, const char* ccdbdat return lst; } -SystemType fSystem = SystemNoSystem; -MultRunType fLhcRun = MultRunRUN1RUN2; -DataType fDataType = kData; -CentMultEstimatorType fCentMultEstimator = CentMultV0M; -OccupancyEstimationType fOccupancyEstimation = OccupancyNOOCC; /* the occupancy estimator to use */ - -float fMinOccupancy = 0.0f; /* the minimum allowed occupancy */ -float fMaxOccupancy = 1e6f; /* the maximum allowed occupancy */ - -/* adaptations for the pp nightly checks */ -analysis::CheckRangeCfg traceDCAOutliers; -bool traceOutOfSpeciesParticles = false; -int recoIdMethod = 0; -float particleMaxDCAxy = 999.9f; -float particleMaxDCAZ = 999.9f; -bool traceCollId0 = false; - inline std::bitset<32> getTriggerSelection(std::string_view const& triggstr) { std::bitset<32> flags; @@ -896,27 +903,31 @@ inline std::bitset<32> getTriggerSelection(std::string_view const& triggstr) inline SystemType getSystemType(auto const& periodsForSysType) { - auto period = metadataInfo.get("LPMProductionTag"); - auto anchoredPeriod = metadataInfo.get("AnchorProduction"); - bool checkAnchor = anchoredPeriod.length() > 0; - - for (SystemType sT = SystemNoSystem; sT < SystemNoOfSystems; ++sT) { - const std::string& periods = periodsForSysType[static_cast(sT)][0]; - auto contains = [periods](auto const& period) { - if (periods.find(period) != std::string::npos) { - return true; - } - return false; - }; - if (periods.length() > 0) { - if (contains(period) || (checkAnchor && contains(anchoredPeriod))) { - LOGF(info, "DptDptCorrelations::getSystemType(). Assigned system type %s for period %s", systemExternalNamesMap.at(static_cast(sT)).data(), period.c_str()); - return sT; + if (fDataType != kOnTheFly) { + auto period = metadataInfo.get("LPMProductionTag"); + auto anchoredPeriod = metadataInfo.get("AnchorProduction"); + bool checkAnchor = anchoredPeriod.length() > 0; + + for (SystemType sT = SystemNoSystem; sT < SystemNoOfSystems; ++sT) { + const std::string& periods = periodsForSysType[static_cast(sT)][0]; + auto contains = [periods](auto const& period) { + if (periods.find(period) != std::string::npos) { + return true; + } + return false; + }; + if (periods.length() > 0) { + if (contains(period) || (checkAnchor && contains(anchoredPeriod))) { + LOGF(info, "DptDptCorrelations::getSystemType(). Assigned system type %s for period %s", systemExternalNamesMap.at(static_cast(sT)).data(), period.c_str()); + return sT; + } } } + LOGF(fatal, "DptDptCorrelations::getSystemType(). No system type for period: %s", period.c_str()); + return SystemPbPb; + } else { + return SystemNeNeRun3; } - LOGF(fatal, "DptDptCorrelations::getSystemType(). No system type for period: %s", period.c_str()); - return SystemPbPb; } /// \brief Type of data according to the configuration string @@ -933,7 +944,7 @@ inline DataType getDataType(std::string const& datastr) return kMC; } else if (datastr == "FastMC") { return kFastMC; - } else if (datastr == "OnTheFlyMC") { + } else if (datastr.starts_with("OnTheFlyMC")) { return kOnTheFly; } else { LOGF(fatal, "DptDptCorrelations::getDataType(). Wrong type of dat: %d", datastr.c_str()); diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 3977682397c..6ceaaa6c815 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -590,6 +590,9 @@ struct MultiplicitySelector { if (doprocessFT0CVariant1) { enabledFunctions++; } + if (doprocessFT0CVariant2) { + enabledFunctions++; + } if (doprocessFT0A) { enabledFunctions++; } @@ -635,6 +638,14 @@ struct MultiplicitySelector { } PROCESS_SWITCH(MultiplicitySelector, processFT0CVariant1, "Select FT0CVariant1 centrality as multiplicity", false); + void processFT0CVariant2(aod::CentFT0CVariant2s const& centralities) + { + for (auto& c : centralities) { + output(c.centFT0CVariant2()); + } + } + PROCESS_SWITCH(MultiplicitySelector, processFT0CVariant2, "Select FT0CVariant2 centrality as multiplicity", false); + void processFT0A(aod::CentFT0As const& centralities) { for (auto& c : centralities) { diff --git a/PWGCF/Tasks/correlations.cxx b/PWGCF/Tasks/correlations.cxx index aef81415c26..6044510a562 100644 --- a/PWGCF/Tasks/correlations.cxx +++ b/PWGCF/Tasks/correlations.cxx @@ -86,6 +86,7 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgTwoTrackCut, float, -1, "Two track cut: -1 = off; >0 otherwise distance value (suggested: 0.02)"); O2_DEFINE_CONFIGURABLE(cfgTwoTrackCutMinRadius, float, 0.8f, "Two track cut: radius in m from which two track cuts are applied"); O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, int, 0, "0 = OFF and 1 = ON for local efficiency"); + O2_DEFINE_CONFIGURABLE(cfgDropStepRECO, bool, false, "choice to drop step RECO if efficiency correction is used") O2_DEFINE_CONFIGURABLE(cfgCentBinsForMC, int, 0, "0 = OFF and 1 = ON for data like multiplicity/centrality bins for MC steps"); O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint16_t, 0, "BitMask for track selection systematics; refer to the enum TrackSelectionCuts in filtering task"); O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.") @@ -862,10 +863,14 @@ struct CorrelationTask { else fillQA(collision, multiplicity, tracks1); - same->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f); + const bool hasEfficiency = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); + const bool fillReco = !(cfgDropStepRECO && hasEfficiency); - if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { + if (fillReco) { + same->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f); + } + if (hasEfficiency) { same->fillEvent(multiplicity, CorrelationContainer::kCFStepCorrected); fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f); } @@ -988,19 +993,28 @@ struct CorrelationTask { LOGF(info, "processMixedDerived: Mixed collisions bin: %d pair: [%d, %d] %d (%.3f, %.3f), %d (%.3f, %.3f)", bin, it.isNewWindow(), it.currentWindowNeighbours(), collision1.globalIndex(), collision1.posZ(), collision1.multiplicity(), collision2.globalIndex(), collision2.posZ(), collision2.multiplicity()); } + bool hasEfficiencyMixed = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); + bool fillRecoMixed = !(cfgDropStepRECO && hasEfficiencyMixed); + if (it.isNewWindow()) { loadEfficiency(collision1.timestamp()); + hasEfficiencyMixed = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); + fillRecoMixed = !(cfgDropStepRECO && hasEfficiencyMixed); - mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepReconstructed); + if (fillRecoMixed) { + mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepReconstructed); + } } // LOGF(info, "Tracks: %d and %d entries", tracks1.size(), tracks2.size()); registry.fill(HIST("eventcount_mixed"), bin); registry.fill(HIST("trackcount_mixed"), bin, tracks1.size(), tracks2.size()); - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); + if (fillRecoMixed) { + fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); + } - if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { + if (hasEfficiencyMixed) { if (it.isNewWindow()) { mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepCorrected); } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx b/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx index 441f35da404..6c6e7464216 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx @@ -80,6 +80,7 @@ struct CorrSparse { O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") O2_DEFINE_CONFIGURABLE(cfgZVtxCut, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgQaCheck, bool, false, "Fill QA histograms for multiplicity and zVtx for events used in the analysis") struct : ConfigurableGroup{ O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.2f, "minimum accepted track pT") @@ -99,6 +100,7 @@ struct CorrSparse { O2_DEFINE_CONFIGURABLE(processFT0A, bool, true, "Process FT0A correlations") O2_DEFINE_CONFIGURABLE(processFT0C, bool, true, "Process FT0C correlations") O2_DEFINE_CONFIGURABLE(processMFT, bool, true, "Process MFT correlations") + O2_DEFINE_CONFIGURABLE(withGain, bool, true, "Use gain for FT0A and FT0C") } cfgDetectorConfig; @@ -142,9 +144,7 @@ struct CorrSparse { O2_DEFINE_CONFIGURABLE(cfgRejectFT0CInside, bool, false, "Rejection of inner ring channels of the FT0C detector") O2_DEFINE_CONFIGURABLE(cfgRejectFT0COutside, bool, false, "Rejection of outer ring channels of the FT0C detector") O2_DEFINE_CONFIGURABLE(cfgRemapFT0ADeadChannels, bool, false, "If true, remap FT0A channels 60-63 to amplitudes from 92-95 respectively") - O2_DEFINE_CONFIGURABLE(cfgRemapFT0CDeadChannels, bool, false, "If true, remap FT0C channels 177->145, 176->144, 178->146, 179->147, 139->115") - - } cfgFITConfig; + O2_DEFINE_CONFIGURABLE(cfgRemapFT0CDeadChannels, bool, false, "If true, remap FT0C channels 177->145, 176->144, 178->146, 179->147, 139->115")} cfgFITConfig; O2_DEFINE_CONFIGURABLE(cfgMinMixEventNum, int, 5, "Minimum number of events to mix") O2_DEFINE_CONFIGURABLE(cfgMergingCut, float, 0.02, "Merging cut on track merge") @@ -188,6 +188,11 @@ struct CorrSparse { TF1* fT0AV0ASigma = nullptr; } cfgFuncParas; + Configurable cfgCutFV0{"cfgCutFV0", 50., "FV0A threshold"}; + Configurable cfgCutFT0A{"cfgCutFT0A", 150., "FT0A threshold"}; + Configurable cfgCutFT0C{"cfgCutFT0C", 50., "FT0C threshold"}; + Configurable cfgCutZDC{"cfgCutZDC", 10., "ZDC threshold"}; + SliceCache cache; SliceCache cacheNch; @@ -219,11 +224,6 @@ struct CorrSparse { ConfigurableAxis multMix{"multMix", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100}, "multiplicity / centrality axis for mixed event histograms"}; ConfigurableAxis axisSample{"axisSample", {cfgSampleSize, 0, cfgSampleSize}, "sample axis for histograms"}; - ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {80, -5, 5}, "nsigmaTPC axis"}; - ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"}; - ConfigurableAxis axisNsigmaITS{"axisNsigmaITS", {80, -5, 5}, "nsigmaITS axis"}; - ConfigurableAxis axisTpcSignal{"axisTpcSignal", {250, 0, 250}, "dEdx axis for TPC"}; - ConfigurableAxis axisVertexEfficiency{"axisVertexEfficiency", {10, -10, 10}, "vertex axis for efficiency histograms"}; ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {20, -1.0, 1.0}, "eta axis for efficiency histograms"}; ConfigurableAxis axisPtEfficiency{"axisPtEfficiency", {VARIABLE_WIDTH, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0}, "pt axis for efficiency histograms"}; @@ -239,7 +239,7 @@ struct CorrSparse { // make the filters and cuts. Filter collisionFilter = (nabs(aod::collision::posZ) < cfgZVtxCut); - Filter trackFilter = (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaCut) && (cfgTrackCuts.cfgPtCutMin < aod::track::pt) && (cfgTrackCuts.cfgPtCutMax > aod::track::pt) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgTrackCuts.cfgCutChi2prTPCcls) && (aod::track::dcaZ < cfgTrackCuts.cfgCutDCAz); + Filter trackFilter = (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaCut) && (cfgTrackCuts.cfgPtCutMin < aod::track::pt) && (cfgTrackCuts.cfgPtCutMax > aod::track::pt) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true)) && (aod::track::tpcChi2NCl < cfgTrackCuts.cfgCutChi2prTPCcls) && (aod::track::dcaZ < cfgTrackCuts.cfgCutDCAz); Filter mftTrackEtaFilter = ((aod::fwdtrack::eta < cfgMftConfig.etaMftTrackMaxFilter) && (aod::fwdtrack::eta > cfgMftConfig.etaMftTrackMinFilter)); @@ -301,20 +301,6 @@ struct CorrSparse { kNEventCuts }; - enum MftTrackAmbiguityStep { - AllMftTracks = 0, - AfterTrackSelection, - NumberOfAmbiguousTracks, - NumberOfNonAmbiguousTracks, - NMftAmbiguitySteps - }; - - enum ReassociationMftTracks { - NotReassociatedMftTracks = 0, - ReassociatedMftTracks, - NReassociationMftTracksSteps - }; - enum EventType { SameEvent = 1, MixedEvent = 3 @@ -357,7 +343,7 @@ struct CorrSparse { LOGF(info, "Starting init"); // Event Counter - if ((doprocessSameTpcFIT || doprocessSameTpcMft || doprocessSameTPC || doprocessSameMFTFIT || doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D) && cfgUseAdditionalEventCut) { + if ((doprocessSameTpcFIT || doprocessSameTpcMft || doprocessSameTPC || doprocessSameMFTFIT || doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D || doprocessSameMftReassociated2DFIT) && cfgUseAdditionalEventCut) { registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{13, 0, 13}}}); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); @@ -374,26 +360,25 @@ struct CorrSparse { registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(13, "cfgEvSelV0AT0ACut"); } - if (doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D) { - registry.add("hEventCountMftReassoc", "Number of Event;; Count", {HistType::kTH1D, {{5, 0, 5}}}); + if (doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D || doprocessSameMftReassociated2DFIT) { + registry.add("hEventCountMftReassoc", "Number of Events;; Count", {HistType::kTH1D, {{4, 0, 4}}}); registry.get(HIST("hEventCountMftReassoc"))->GetXaxis()->SetBinLabel(1, "all MFT tracks"); registry.get(HIST("hEventCountMftReassoc"))->GetXaxis()->SetBinLabel(2, "MFT tracks after selection"); registry.get(HIST("hEventCountMftReassoc"))->GetXaxis()->SetBinLabel(3, "ambiguous MFT tracks"); registry.get(HIST("hEventCountMftReassoc"))->GetXaxis()->SetBinLabel(4, "non-ambiguous MFT tracks"); - registry.get(HIST("hEventCountMftReassoc"))->GetXaxis()->SetBinLabel(5, "Reassociated MFT tracks"); - registry.add("ReassociatedMftTracks", "Reassociated MFT tracks", {HistType::kTH1D, {{3, 0, 3}}}); + registry.add("ReassociatedMftTracks", "Reassociated MFT tracks", {HistType::kTH1D, {{2, 0, 2}}}); registry.get(HIST("ReassociatedMftTracks"))->GetXaxis()->SetBinLabel(1, "Not Reassociated MFT tracks"); registry.get(HIST("ReassociatedMftTracks"))->GetXaxis()->SetBinLabel(2, "Reassociated MFT tracks"); } // Make histograms to check the distributions after cuts - if (doprocessSameTpcFIT || doprocessSameTpcMft || doprocessSameTPC || doprocessSameMFTFIT || doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D) { + if (doprocessSameTpcFIT || doprocessSameTpcMft || doprocessSameTPC || doprocessSameMFTFIT || doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D || doprocessSameMftReassociated2DFIT) { registry.add("Phi", "Phi", {HistType::kTH1D, {axisPhi}}); if (doprocessSameMFTFIT) { registry.add("Eta", "EtaMFT", {HistType::kTH1D, {axisEtaMft}}); } - if (doprocessSameTpcFIT || doprocessSameTPC || doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D) { + if (doprocessSameTpcFIT || doprocessSameTpcMft || doprocessSameTPC || doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D) { registry.add("Eta", "Eta", {HistType::kTH1D, {axisEta}}); } registry.add("EtaCorrected", "EtaCorrected", {HistType::kTH1D, {axisEta}}); @@ -404,7 +389,7 @@ struct CorrSparse { registry.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); registry.add("zVtx_used", "zVtx_used", {HistType::kTH1D, {axisVertex}}); - if (doprocessSameTpcFIT || doprocessSameMFTFIT) { + if (doprocessSameTpcFIT || doprocessSameMFTFIT || doprocessSameMftReassociated2DFIT) { registry.add("FT0Amp", "", {HistType::kTH2F, {axisChID, axisFit}}); registry.add("FV0Amp", "", {HistType::kTH2F, {axisChID, axisFit}}); registry.add("FT0AmpCorrect", "", {HistType::kTH2F, {axisChID, axisFit}}); @@ -417,26 +402,26 @@ struct CorrSparse { if (cfgDetectorConfig.processFT0A) { registry.add("deltaEta_deltaPhi_same_TPC_FT0A", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0a}}); // check to see the delta eta and delta phi distribution registry.add("deltaEta_deltaPhi_mixed_TPC_FT0A", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0a}}); - registry.add("Assoc_amp_same_TPC_FT0A", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); - registry.add("Assoc_amp_mixed_TPC_FT0A", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); - registry.add("Trig_hist_TPC_FT0A", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + registry.add("Assoc_amp_same", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Assoc_amp_mixed", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); } if (cfgDetectorConfig.processFT0C) { registry.add("deltaEta_deltaPhi_same_TPC_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0c}}); // check to see the delta eta and delta phi distribution registry.add("deltaEta_deltaPhi_mixed_TPC_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0c}}); - registry.add("Assoc_amp_same_TPC_FT0C", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); - registry.add("Assoc_amp_mixed_TPC_FT0C", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); - registry.add("Trig_hist_TPC_FT0C", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + registry.add("Assoc_amp_same", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Assoc_amp_mixed", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); } if (cfgDetectorConfig.processFV0) { registry.add("deltaEta_deltaPhi_same_TPC_FV0", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFv0}}); // check to see the delta eta and delta phi distribution registry.add("deltaEta_deltaPhi_same_TPC_FV0", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFv0}}); // check to see the delta eta and delta phi distribution registry.add("deltaEta_deltaPhi_mixed_TPC_FV0", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFv0}}); - registry.add("Trig_hist_FT0A_FT0C", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); } } - if (doprocessSameMFTFIT) { + if (doprocessSameMFTFIT || doprocessSameMftReassociated2DFIT) { if (cfgDetectorConfig.processFT0A) { registry.add("deltaEta_deltaPhi_same_MFT_FT0A", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaMftFt0a}}); // check to see the delta eta and delta phi distribution @@ -464,13 +449,13 @@ struct CorrSparse { if (doprocessSameTpcMft || doprocessSameTpcMftReassociated2D || doprocessSameTpcMftReassociated3D) { registry.add("deltaEta_deltaPhi_same_TPC_MFT", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcMft}}); // check to see the delta eta and delta phi distribution registry.add("deltaEta_deltaPhi_mixed_TPC_MFT", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcMft}}); - registry.add("Trig_hist_TPC_MFT", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); } if (doprocessSameTPC) { registry.add("deltaEta_deltaPhi_same_TPC_TPC", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // check to see the delta eta and delta phi distribution registry.add("deltaEta_deltaPhi_mixed_TPC_TPC", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); - registry.add("Trig_hist_TPC_TPC", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); } registry.add("eventcount", "bin", {HistType::kTH1F, {{4, 0, 4, "bin"}}}); // histogram to see how many events are in the same and mixed event @@ -483,6 +468,7 @@ struct CorrSparse { {axisPtAssoc, "p_{T} (GeV/c)"}, {axisDeltaPhi, "#Delta#varphi (rad)"}, {axisDeltaEtaTpcFt0c, "#Delta#eta"}}; + std::vector effAxis = { {axisEtaEfficiency, "#eta"}, {axisPtEfficiency, "p_{T} (GeV/c)"}, @@ -572,6 +558,21 @@ struct CorrSparse { } } + if (doprocessSameMftReassociated2DFIT) { + if (cfgDetectorConfig.processFT0A) { + same.setObject(new CorrelationContainer("sameEvent_MFT_Reassociated2D_FT0A", "sameEvent_MFT_Reassociated2D_FT0A", corrAxisMftFt0a, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_MFT_Reassociated2D_FT0A", "mixedEvent_MFT_Reassociated2D_FT0A", corrAxisMftFt0a, effAxis, userAxis)); + } + if (cfgDetectorConfig.processFT0C) { + same.setObject(new CorrelationContainer("sameEvent_MFT_Reassociated2D_FT0C", "sameEvent_MFT_Reassociated2D_FT0C", corrAxisMftFt0c, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_MFT_Reassociated2D_FT0C", "mixedEvent_MFT_Reassociated2D_FT0C", corrAxisMftFt0c, effAxis, userAxis)); + } + if (cfgDetectorConfig.processFV0) { + same.setObject(new CorrelationContainer("sameEvent_MFT_Reassociated2D_FV0", "sameEvent_MFT_Reassociated2D_FV0", corrAxisMftFv0, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_MFT_Reassociated2D_FV0", "mixedEvent_MFT_Reassociated2D_FV0", corrAxisMftFv0, effAxis, userAxis)); + } + } + if (doprocessSameTPC) { same.setObject(new CorrelationContainer("sameEvent_TPC_TPC", "sameEvent_TPC_TPC", corrAxisTpcTpc, effAxis, userAxis)); mixed.setObject(new CorrelationContainer("mixedEvent_TPC_TPC", "mixedEvent_TPC_TPC", corrAxisTpcTpc, effAxis, userAxis)); @@ -770,7 +771,7 @@ struct CorrSparse { auto theta = std::atan2(r, z); return -std::log(std::tan(0.5 * theta)); } - + // checks if it is an accepted mft track template bool isAcceptedMftTrack(TTrack const& mftTrack) { @@ -842,6 +843,27 @@ struct CorrSparse { } } + template + void getChannelWithGain(TFT0s const& ft0, std::size_t const& iCh, int& id, float& ampl, int fitType) + { + if (fitType == kFT0C) { + id = ft0.channelC()[iCh]; + id = id + Ft0IndexA; + ampl = ft0.amplitudeC()[iCh]; + registry.fill(HIST("FT0Amp"), id, ampl); + ampl = ampl / cstFT0RelGain[id]; + registry.fill(HIST("FT0AmpCorrect"), id, ampl); + } else if (fitType == kFT0A) { + id = ft0.channelA()[iCh]; + ampl = ft0.amplitudeA()[iCh]; + registry.fill(HIST("FT0Amp"), id, ampl); + ampl = ampl / cstFT0RelGain[id]; + registry.fill(HIST("FT0AmpCorrect"), id, ampl); + } else { + LOGF(fatal, "Cor Index %d out of range", fitType); + } + } + void loadCorrection(uint64_t timestamp) { if (correctionsLoaded) { @@ -1001,9 +1023,12 @@ struct CorrSparse { float triggerWeight = 1.0f; // loop over all tracks + if (cfgQaCheck) { - if (system == SameEvent) { - registry.fill(HIST("Nch_used"), multiplicity); + if (system == SameEvent) { + registry.fill(HIST("Nch_used"), multiplicity); + registry.fill(HIST("zVtx_used"), posZ); + } } for (auto const& track1 : tracks1) { @@ -1043,13 +1068,23 @@ struct CorrSparse { float deltaEta = track1.eta() - eta; if (system == SameEvent) { + if (cfgDetectorConfig.processMFT) { + registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FV0"), deltaPhi, deltaEta, amplitude * triggerWeight); + } else { + registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FV0"), deltaPhi, deltaEta, amplitude * triggerWeight); + } + registry.fill(HIST("Assoc_amp_same"), channelID, amplitude); same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, amplitude * triggerWeight); - registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FV0"), deltaPhi, deltaEta, amplitude * triggerWeight); + } else if (system == MixedEvent) { + if (cfgDetectorConfig.processMFT) { + registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FV0"), deltaPhi, deltaEta, amplitude); + } else { + registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FV0"), deltaPhi, deltaEta, amplitude); + } registry.fill(HIST("Assoc_amp_mixed"), channelID, amplitude); mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, amplitude); - registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FV0"), deltaPhi, deltaEta, amplitude); } } } @@ -1069,7 +1104,11 @@ struct CorrSparse { for (std::size_t iCh = 0; iCh < channelSize; iCh++) { int channelID = 0; float amplitude = 0.; - getChannelFT0(tracks2, iCh, channelID, amplitude, corType); + if (cfgDetectorConfig.withGain) { + getChannelWithGain(tracks2, iCh, channelID, amplitude, corType); + } else { + getChannelFT0(tracks2, iCh, channelID, amplitude, corType); + } // reject depending on FT0C/FT0A rings if (corType == kFT0C) { @@ -1089,25 +1128,41 @@ struct CorrSparse { if (system == SameEvent) { if (corType == kFT0A) { + if (cfgDetectorConfig.processMFT) { + registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FT0A"), deltaPhi, deltaEta, amplitude * triggerWeight); + } else { + registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FT0A"), deltaPhi, deltaEta, amplitude * triggerWeight); + } registry.fill(HIST("Assoc_amp_same"), channelID, amplitude); same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, amplitude * triggerWeight); - registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FT0A"), deltaPhi, deltaEta, amplitude * triggerWeight); } if (corType == kFT0C) { + if (cfgDetectorConfig.processMFT) { + registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FT0C"), deltaPhi, deltaEta, amplitude * triggerWeight); + } else { + registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FT0C"), deltaPhi, deltaEta, amplitude * triggerWeight); + } registry.fill(HIST("Assoc_amp_same"), channelID, amplitude); same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, amplitude * triggerWeight); - registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FT0C"), deltaPhi, deltaEta, amplitude * triggerWeight); } } else if (system == MixedEvent) { if (corType == kFT0A) { + if (cfgDetectorConfig.processMFT) { + registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FT0A"), deltaPhi, deltaEta, amplitude); + } else { + registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FT0A"), deltaPhi, deltaEta, amplitude); + } registry.fill(HIST("Assoc_amp_mixed"), channelID, amplitude); mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, amplitude); - registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FT0A"), deltaPhi, deltaEta, amplitude); } if (corType == kFT0C) { + if (cfgDetectorConfig.processMFT) { + registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FT0C"), deltaPhi, deltaEta, amplitude); + } else { + registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FT0C"), deltaPhi, deltaEta, amplitude); + } registry.fill(HIST("Assoc_amp_mixed"), channelID, amplitude); mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, amplitude); - registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FT0C"), deltaPhi, deltaEta, amplitude); } } } @@ -1115,73 +1170,126 @@ struct CorrSparse { } } ////////////////////////// - //////////TPC-MFT///////// + //////////MFT-Reassociated///////// ////////////////////////// - template - void fillCorrelationsMFT(TTracks tracks1, TTracksAssoc tracks2, float posZ, int system, int magneticField) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms - { + template + void fillCorrelationsMftReassociatedFIT(TTracks tracks1, TTracksAssociated tracks2, FITs const&, float posZ, int system, int corType, float multiplicity, bool cutAmbiguousTracks) + { int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); float triggerWeight = 1.0f; - if (system == SameEvent) { - registry.fill(HIST("Nch_used"), tracks1.size()); - } // loop over all tracks + if (cfgQaCheck) { + + if (system == SameEvent) { + registry.fill(HIST("Nch_used"), multiplicity); + registry.fill(HIST("zVtx_used"), posZ); + } + } + for (auto const& track1 : tracks1) { - if (!trackSelected(track1)) - continue; + auto reassociatedMftTrack = track1.template mfttrack_as(); - if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) + if (!isAcceptedMftTrack(reassociatedMftTrack)) { continue; + } + + if (isAmbiguousMftTrack(track1, false)) { + if (cutAmbiguousTracks) { + continue; + } + } if (system == SameEvent) { - registry.fill(HIST("Trig_hist_TPC_MFT"), fSampleIndex, posZ, track1.pt(), triggerWeight); + + registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, reassociatedMftTrack.pt(), triggerWeight); } - for (auto const& track2 : tracks2) { - if constexpr (std::is_same_v) - continue; + if constexpr (std::is_same_v) { - if (!isAcceptedMftTrack(track2)) { - continue; - } + std::size_t channelSize = tracks2.channel().size(); + for (std::size_t iCh = 0; iCh < channelSize; iCh++) { + int channelID = 0; + float amplitude = 0.; - float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); - float deltaEta = track1.eta() - track2.eta(); + getChannelFV0(tracks2, iCh, channelID, amplitude); - if (cfgApplyTwoTrackEfficiency && std::abs(deltaEta) < cfgMergingCut) { + auto phi = getPhiFV0(channelID); + auto eta = getEtaFV0(channelID); - double dPhiStarHigh = getDPhiStar(track1, track2, cfgRadiusHigh, magneticField); - double dPhiStarLow = getDPhiStar(track1, track2, cfgRadiusLow, magneticField); + float deltaPhi = RecoDecay::constrainAngle(reassociatedMftTrack.phi() - phi, -PIHalf); + float deltaEta = reassociatedMftTrack.eta() - eta; - const double kLimit = 3.0 * cfgMergingCut; + if (system == SameEvent) { + registry.fill(HIST("Assoc_amp_same"), channelID, amplitude); + same->getPairHist()->Fill(step, fSampleIndex, posZ, reassociatedMftTrack.pt(), reassociatedMftTrack.pt(), deltaPhi, deltaEta, amplitude * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FV0"), deltaPhi, deltaEta, amplitude * triggerWeight); + } else if (system == MixedEvent) { + registry.fill(HIST("Assoc_amp_mixed"), channelID, amplitude); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, reassociatedMftTrack.pt(), reassociatedMftTrack.pt(), deltaPhi, deltaEta, amplitude); + registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FV0"), deltaPhi, deltaEta, amplitude); + } + } + } - bool bIsBelow = false; + // if using FT0A and FT0C for correlations / using FT0A and FT0C as associated particles + if constexpr (std::is_same_v) { - if (std::abs(dPhiStarLow) < kLimit || std::abs(dPhiStarHigh) < kLimit || dPhiStarLow * dPhiStarHigh < 0) { - for (double rad(cfgRadiusLow); rad < cfgRadiusHigh; rad += 0.01) { - double dPhiStar = getDPhiStar(track1, track2, rad, magneticField); - if (std::abs(dPhiStar) < kLimit) { - bIsBelow = true; - break; - } - } - if (bIsBelow) + std::size_t channelSize = 0; + if (corType == kFT0C) { + channelSize = tracks2.channelC().size(); + } else if (corType == kFT0A) { + channelSize = tracks2.channelA().size(); + } else { + LOGF(fatal, "Cor Index %d out of range", corType); + } + + for (std::size_t iCh = 0; iCh < channelSize; iCh++) { + int channelID = 0; + float amplitude = 0.; + getChannelWithGain(tracks2, iCh, channelID, amplitude, corType); + + // reject depending on FT0C/FT0A rings + if (corType == kFT0C) { + if ((cfgFITConfig.cfgRejectFT0CInside && (channelID >= kFT0CInnerRingMin && channelID <= kFT0CInnerRingMax)) || (cfgFITConfig.cfgRejectFT0COutside && (channelID >= kFT0COuterRingMin && channelID <= kFT0COuterRingMax))) + continue; + } + if (corType == kFT0A) { + if ((cfgFITConfig.cfgRejectFT0AInside && (channelID >= kFT0AInnerRingMin && channelID <= kFT0AInnerRingMax)) || (cfgFITConfig.cfgRejectFT0AOutside && (channelID >= kFT0AOuterRingMin && channelID <= kFT0AOuterRingMax))) continue; } - } - // fill the right sparse and histograms - if (system == SameEvent) { + auto phi = getPhiFT0(channelID, corType); + auto eta = getEtaFT0(channelID, corType); - same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta); - registry.fill(HIST("deltaEta_deltaPhi_same_TPC_MFT"), deltaPhi, deltaEta); - } else if (system == MixedEvent) { + float deltaPhi = RecoDecay::constrainAngle(reassociatedMftTrack.phi() - phi, -PIHalf); + float deltaEta = reassociatedMftTrack.eta() - eta; - mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta); - registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_MFT"), deltaPhi, deltaEta); + if (system == SameEvent) { + if (corType == kFT0A) { + registry.fill(HIST("Assoc_amp_same"), channelID, amplitude); + same->getPairHist()->Fill(step, fSampleIndex, posZ, reassociatedMftTrack.pt(), reassociatedMftTrack.pt(), deltaPhi, deltaEta, amplitude * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FT0A"), deltaPhi, deltaEta, amplitude * triggerWeight); + } + if (corType == kFT0C) { + registry.fill(HIST("Assoc_amp_same"), channelID, amplitude); + same->getPairHist()->Fill(step, fSampleIndex, posZ, reassociatedMftTrack.pt(), reassociatedMftTrack.pt(), deltaPhi, deltaEta, amplitude * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_MFT_FT0C"), deltaPhi, deltaEta, amplitude * triggerWeight); + } + } else if (system == MixedEvent) { + if (corType == kFT0A) { + registry.fill(HIST("Assoc_amp_mixed"), channelID, amplitude); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, reassociatedMftTrack.pt(), reassociatedMftTrack.pt(), deltaPhi, deltaEta, amplitude); + registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FT0A"), deltaPhi, deltaEta, amplitude); + } + if (corType == kFT0C) { + registry.fill(HIST("Assoc_amp_mixed"), channelID, amplitude); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, reassociatedMftTrack.pt(), reassociatedMftTrack.pt(), deltaPhi, deltaEta, amplitude); + registry.fill(HIST("deltaEta_deltaPhi_mixed_MFT_FT0C"), deltaPhi, deltaEta, amplitude); + } + } } } } @@ -1195,11 +1303,13 @@ struct CorrSparse { float triggerWeight = 1.0f; auto loopCounter = 0; + if (cfgQaCheck) { - if (system == SameEvent) { - registry.fill(HIST("Nch_used"), multiplicity); + if (system == SameEvent) { + registry.fill(HIST("Nch_used"), multiplicity); + registry.fill(HIST("zVtx_used"), posZ); + } } - // loop over all tracks for (auto const& track1 : tracks1) { @@ -1212,17 +1322,17 @@ struct CorrSparse { continue; if (system == SameEvent) { - registry.fill(HIST("Trig_hist_TPC_MFT"), fSampleIndex, posZ, track1.pt(), triggerWeight); + registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, track1.pt(), triggerWeight); } for (auto const& track2 : tracks2) { - auto reassociatedMftTrack = track2.template mfttrack_as(); - if (!cutAmbiguousTracks && system == SameEvent && (loopCounter == 1)) { registry.fill(HIST("hEventCountMftReassoc"), 0.5); // fill histogram for events with at least one reassociated track); } + auto reassociatedMftTrack = track2.template mfttrack_as(); + if (!isAcceptedMftTrack(reassociatedMftTrack)) { continue; } @@ -1290,34 +1400,43 @@ struct CorrSparse { //////////TPC-TPC and TPC-MFT///////// ///////////////////////////////////// template - void fillCorrelationsTpc(TTracks tracks1, TTracksAssoc tracks2, float posZ, int system, int magneticField) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + void fillCorrelations(TTracks tracks1, TTracksAssoc tracks2, float posZ, float multiplicity, int system, int magneticField) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms { int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); float triggerWeight = 1.0f; + if (cfgQaCheck) { + if (system == SameEvent) { + registry.fill(HIST("Nch_used"), multiplicity); + registry.fill(HIST("zVtx_used"), posZ); + } + } // loop over all tracks for (auto const& track1 : tracks1) { - if (!trackSelected(track1)) - continue; + if constexpr (std::is_same_v) { + if (!isAcceptedMftTrack(track1)) { + continue; + } + } else { + if (!trackSelected(track1)) + continue; - if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) - continue; + if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) + continue; + } if (system == SameEvent) { - registry.fill(HIST("Nch_used"), tracks1.size()); - registry.fill(HIST("Trig_hist_TPC_TPC"), fSampleIndex, posZ, track1.pt(), triggerWeight); + registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, track1.pt(), triggerWeight); } for (auto const& track2 : tracks2) { - if (cfgDetectorConfig.processMFT) { - if constexpr (std::is_same_v) { - if (!isAcceptedMftTrack(track2)) { - continue; - } + if constexpr (std::is_same_v) { + if (!isAcceptedMftTrack(track2)) { + continue; } } else { if (!trackSelected(track2)) @@ -1387,6 +1506,7 @@ struct CorrSparse { if (!collision.sel8()) return; + auto bc = collision.bc_as(); if (cfgUseAdditionalEventCut && !eventSelected(collision, tpctracks.size(), true)) @@ -1395,12 +1515,18 @@ struct CorrSparse { if (!collision.has_foundFT0()) return; loadAlignParam(bc.timestamp()); - // loadGain(bc); + if (cfgDetectorConfig.withGain) { + loadGain(bc); + } + loadCorrection(bc.timestamp()); if ((tpctracks.size() < cfgEventSelection.cfgMinMult || tpctracks.size() >= cfgEventSelection.cfgMaxMult)) { return; } + if (mfts.size() == 0) { + return; + } registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin fillYield(collision, mfts); @@ -1430,6 +1556,59 @@ struct CorrSparse { } PROCESS_SWITCH(CorrSparse, processSameMFTFIT, "Process same event for MFT-FIT correlation", true); + void processSameMftReassociated2DFIT(AodCollisions::iterator const& collision, AodTracks const& tpctracks, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&, + aod::FT0s const& ft0as, aod::FV0As const& fv0as, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) + return; + + auto bc = collision.bc_as(); + + if (cfgUseAdditionalEventCut && !eventSelected(collision, tpctracks.size(), true)) + return; + + if (!collision.has_foundFT0()) + return; + loadAlignParam(bc.timestamp()); + loadGain(bc); + loadCorrection(bc.timestamp()); + + if ((tpctracks.size() < cfgEventSelection.cfgMinMult || tpctracks.size() >= cfgEventSelection.cfgMaxMult)) { + return; + } + if (reassociatedMftTracks.size() == 0) { + return; + } + + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + const auto& multiplicity = tpctracks.size(); + + if (cfgDetectorConfig.processFV0) { + if (collision.has_foundFV0()) { + same->fillEvent(reassociatedMftTracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& fv0 = collision.foundFV0(); + fillCorrelationsMftReassociatedFIT(reassociatedMftTracks, fv0, fv0as, collision.posZ(), SameEvent, kFV0, multiplicity, false); + } + } + if (cfgDetectorConfig.processFT0C) { + if (collision.has_foundFT0()) { + same->fillEvent(reassociatedMftTracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& ft0 = collision.foundFT0(); + fillCorrelationsMftReassociatedFIT(reassociatedMftTracks, ft0, ft0as, collision.posZ(), SameEvent, kFT0C, multiplicity, false); + } + } + if (cfgDetectorConfig.processFT0A) { + if (collision.has_foundFT0()) { + same->fillEvent(reassociatedMftTracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& ft0 = collision.foundFT0(); + fillCorrelationsMftReassociatedFIT(reassociatedMftTracks, ft0, ft0as, collision.posZ(), SameEvent, kFT0A, multiplicity, false); + } + } + } + PROCESS_SWITCH(CorrSparse, processSameMftReassociated2DFIT, "Process same event for MFT-FIT correlation with reassociated tracks", false); + ///////////////////////// ////////Mid-Mid////////// //////////////////////// @@ -1445,16 +1624,17 @@ struct CorrSparse { if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), true)) return; - registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + loadCorrection(bc.timestamp()); + + fillYield(collision, tracks); if (tracks.size() < cfgEventSelection.cfgMinMult || tracks.size() >= cfgEventSelection.cfgMaxMult) { return; } - loadCorrection(bc.timestamp()); - fillYield(collision, tracks); + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin - fillCorrelationsTpc(tracks, tracks, collision.posZ(), SameEvent, getMagneticField(bc.timestamp())); + fillCorrelations(tracks, tracks, collision.posZ(), tracks.size(), SameEvent, getMagneticField(bc.timestamp())); } PROCESS_SWITCH(CorrSparse, processSameTPC, "Process same event for TPC-TPC correlation", false); @@ -1480,7 +1660,10 @@ struct CorrSparse { } loadAlignParam(bc.timestamp()); - // loadGain(bc); + if (cfgDetectorConfig.withGain) { + loadGain(bc); + } + loadCorrection(bc.timestamp()); registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin @@ -1510,12 +1693,14 @@ struct CorrSparse { { if (!collision.sel8()) return; + auto bc = collision.bc_as(); if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), true)) return; loadCorrection(bc.timestamp()); + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin fillYield(collision, tracks); @@ -1524,7 +1709,7 @@ struct CorrSparse { return; } - fillCorrelationsMFT(tracks, mfts, collision.posZ(), SameEvent, getMagneticField(bc.timestamp())); + fillCorrelations(tracks, mfts, collision.posZ(), tracks.size(), SameEvent, getMagneticField(bc.timestamp())); } PROCESS_SWITCH(CorrSparse, processSameTpcMft, "Process same event for TPC-MFT correlation", false); @@ -1535,21 +1720,23 @@ struct CorrSparse { { if (!collision.sel8()) return; + auto bc = collision.bc_as(); if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), true)) return; + loadCorrection(bc.timestamp()); + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin - loadCorrection(bc.timestamp()); fillYield(collision, tracks); if (tracks.size() < cfgEventSelection.cfgMinMult || tracks.size() >= cfgEventSelection.cfgMaxMult) { return; } - fillCorrelationsMftReassociatedTracks(tracks, reassociatedMftTracks, collision.posZ(), tracks.size(), SameEvent, getMagneticField(bc.timestamp()), true); + fillCorrelationsMftReassociatedTracks(tracks, reassociatedMftTracks, tracks.size(), collision.posZ(), SameEvent, getMagneticField(bc.timestamp()), false); } PROCESS_SWITCH(CorrSparse, processSameTpcMftReassociated2D, "Process same event for TPC-MFT correlation with reassociated tracks", false); @@ -1572,7 +1759,7 @@ struct CorrSparse { return; } - fillCorrelationsMftReassociatedTracks(tracks, reassociatedMftTracks, collision.posZ(), tracks.size(), SameEvent, getMagneticField(bc.timestamp()), true); + fillCorrelationsMftReassociatedTracks(tracks, reassociatedMftTracks, tracks.size(), collision.posZ(), SameEvent, getMagneticField(bc.timestamp()), false); } PROCESS_SWITCH(CorrSparse, processSameTpcMftReassociated3D, "Process same event for TPC-MFT correlation with reassociated tracks", false); @@ -1692,7 +1879,7 @@ struct CorrSparse { if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), false)) continue; - fillCorrelationsTpc(tracks1, tracks2, collision1.posZ(), MixedEvent, getMagneticField(bc.timestamp())); + fillCorrelations(tracks1, tracks2, collision1.posZ(), tracks1.size(), MixedEvent, getMagneticField(bc.timestamp())); } } PROCESS_SWITCH(CorrSparse, processMixedTpcTpc, "Process mixed events for TPC-TPC correlation", false); @@ -1792,7 +1979,7 @@ struct CorrSparse { if ((tracks1.size() < cfgEventSelection.cfgMinMult || tracks1.size() >= cfgEventSelection.cfgMaxMult)) continue; - fillCorrelationsMFT(tracks1, tracks2, collision1.posZ(), MixedEvent, getMagneticField(bc.timestamp())); + fillCorrelations(tracks1, tracks2, collision1.posZ(), tracks1.size(), MixedEvent, getMagneticField(bc.timestamp())); } } PROCESS_SWITCH(CorrSparse, processMixedTpcMFT, "Process mixed events for TPC-MFT correlation", false); diff --git a/PWGCF/TwoParticleCorrelations/Tasks/flowDecorrelation.cxx b/PWGCF/TwoParticleCorrelations/Tasks/flowDecorrelation.cxx index efdf665692b..a2b7422f9f4 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/flowDecorrelation.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/flowDecorrelation.cxx @@ -51,6 +51,7 @@ #include #include +#include #include using namespace o2; @@ -143,7 +144,9 @@ struct FlowDecorrelation { ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; ConfigurableAxis axisDeltaEtaTpcFt0a{"axisDeltaEtaTpcFt0a", {32, -5.8, -2.6}, "delta eta axis, -5.8~-2.6 for TPC-FT0A,"}; ConfigurableAxis axisDeltaEtaTpcFt0c{"axisDeltaEtaTpcFt0c", {32, 1.2, 4.2}, "delta eta axis, 1.2~4.2 for TPC-FT0C"}; + ConfigurableAxis axisDeltaEtaFt0aFt0c{"axisDeltaEtaFt0aFt0c", {32, 4.2, 8.2}, "delta eta axis, 4.2~8.2 for FT0A-FT0C"}; ConfigurableAxis axisDeltaEtaTpcMft{"axisDeltaEtaTpcMft", {32, 1.3, 4.8}, "delta eta axis, 1.3~4.8 for TPC-MFT"}; + ConfigurableAxis axisDeltaEtaTpcFv0{"axisDeltaEtaTpcFv0", {32, -1.2, -6.1}, "delta eta axis for TPC-FV0 histograms"}; ConfigurableAxis axisEtaTrigger{"axisEtaTrigger", {VARIABLE_WIDTH, -3.3, -2.1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 3.5, 4.9}, "eta trigger axis for histograms"}; ConfigurableAxis axisEtaAssoc{"axisEtaAssoc", {VARIABLE_WIDTH, -3.3, -2.1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 3.5, 4.9}, "eta associated axis for histograms"}; ConfigurableAxis axisVtxMix{"axisVtxMix", {VARIABLE_WIDTH, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "vertex axis for mixed event histograms"}; @@ -169,8 +172,10 @@ struct FlowDecorrelation { // FT0 geometry o2::ft0::Geometry ft0Det; + o2::fv0::Geometry* fv0Det{}; static constexpr uint64_t Ft0IndexA = 96; std::vector* offsetFT0; + std::vector* offsetFV0; std::vector cstFT0RelGain{}; // Corrections @@ -179,12 +184,8 @@ struct FlowDecorrelation { bool correctionsLoaded = false; // Define the outputs - OutputObj sameTpcFt0a{"sameEvent_TPC_FT0A"}; - OutputObj mixedTpcFt0a{"mixedEvent_TPC_FT0A"}; - OutputObj sameTpcFt0c{"sameEvent_TPC_FT0C"}; - OutputObj mixedTpcFt0c{"mixedEvent_TPC_FT0C"}; - OutputObj sameTpcMft{"sameEvent_TPC_MFT"}; - OutputObj mixedTpcMft{"mixedEvent_TPC_MFT"}; + OutputObj same{"sameEvent"}; + OutputObj mixed{"mixedEvent"}; HistogramRegistry registry{"registry"}; // define global variables @@ -203,7 +204,8 @@ struct FlowDecorrelation { }; enum FITIndex { kFT0A = 0, - kFT0C = 1 + kFT0C = 1, + kFV0 = 2 }; enum ParticleNsigma { kPionUp = 0, @@ -245,10 +247,11 @@ struct FlowDecorrelation { ccdb->setCaching(true); auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); ccdb->setCreatedNotAfter(now); + fv0Det = o2::fv0::Geometry::instance(o2::fv0::Geometry::eUninitialized); LOGF(info, "Starting init"); // Event Counter - if ((doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameTpcMft) && cfgUseAdditionalEventCut) { + if ((doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameFt0aFt0c || doprocessSameTpcMft || doprocessSameTpcFv0) && cfgUseAdditionalEventCut) { registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{12, 0, 12}}}); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); @@ -297,7 +300,7 @@ struct FlowDecorrelation { std::string hCentTitle = "Centrality distribution, Estimator " + std::to_string(cfgCentEstimator); // Make histograms to check the distributions after cuts - if (doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameTpcMft) { + if (doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameFt0aFt0c || doprocessSameTpcMft || doprocessSameTpcFv0) { registry.add("Phi", "Phi", {HistType::kTH1D, {axisPhi}}); registry.add("Eta", "Eta", {HistType::kTH1D, {axisEta}}); registry.add("EtaCorrected", "EtaCorrected", {HistType::kTH1D, {axisEta}}); @@ -330,27 +333,44 @@ struct FlowDecorrelation { registry.add("Assoc_amp_mixed_TPC_FT0C", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); registry.add("Trig_hist_TPC_FT0C", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisEtaTrigger}}}); } + if (doprocessSameFt0aFt0c) { + registry.add("deltaEta_deltaPhi_same_FT0A_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaFt0aFt0c}}); // check to see the delta eta and delta phi distribution + registry.add("deltaEta_deltaPhi_mixed_FT0A_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaFt0aFt0c}}); + registry.add("Assoc_amp_same_FT0A_FT0C", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Assoc_amp_mixed_FT0A_FT0C", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Trig_hist_FT0A_FT0C", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisEtaTrigger}}}); + } if (doprocessSameTpcMft) { registry.add("deltaEta_deltaPhi_same_TPC_MFT", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcMft}}); // check to see the delta eta and delta phi distribution registry.add("deltaEta_deltaPhi_mixed_TPC_MFT", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcMft}}); registry.add("Trig_hist_TPC_MFT", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisEtaTrigger}}}); } + if (doprocessSameTpcFv0) { + registry.add("deltaEta_deltaPhi_same_TPC_FV0", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFv0}}); // check to see the delta eta and delta phi distribution + registry.add("deltaEta_deltaPhi_mixed_TPC_FV0", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFv0}}); + registry.add("Assoc_amp_same_TPC_FV0", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Assoc_amp_mixed_TPC_FV0", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Trig_hist_TPC_FV0", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisEtaTrigger}}}); + registry.add("FV0Amp", "", {HistType::kTH2F, {axisChID, axisFit}}); + } registry.add("eventcount", "bin", {HistType::kTH1F, {{4, 0, 4, "bin"}}}); // histogram to see how many events are in the same and mixed event LOGF(info, "Initializing correlation container"); - std::vector corrAxisTpcFt0a = {{axisSample, "Sample"}, - {axisVertex, "z-vtx (cm)"}, - {axisEtaTrigger, "#eta"}, - {axisEtaAssoc, "#eta"}, - {axisDeltaPhi, "#Delta#varphi (rad)"}, - {axisDeltaEtaTpcFt0a, "#Delta#eta"}}; std::vector effAxis = { {axisEtaEfficiency, "#eta"}, {axisPtEfficiency, "p_{T} (GeV/c)"}, {axisVertexEfficiency, "z-vtx (cm)"}, }; std::vector userAxis; + + std::vector corrAxisTpcFt0a = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisEtaTrigger, "#eta"}, + {axisEtaAssoc, "#eta"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEtaTpcFt0a, "#Delta#eta"}}; + std::vector corrAxisTpcFt0c = {{axisSample, "Sample"}, {axisVertex, "z-vtx (cm)"}, {axisEtaTrigger, "#eta"}, @@ -358,6 +378,13 @@ struct FlowDecorrelation { {axisDeltaPhi, "#Delta#varphi (rad)"}, {axisDeltaEtaTpcFt0c, "#Delta#eta"}}; + std::vector corrAxisFt0aFt0c = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisEtaTrigger, "#eta"}, + {axisEtaAssoc, "#eta"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEtaFt0aFt0c, "#Delta#eta"}}; + std::vector corrAxisTpcMft = {{axisSample, "Sample"}, {axisVertex, "z-vtx (cm)"}, {axisEtaTrigger, "#eta"}, @@ -365,17 +392,32 @@ struct FlowDecorrelation { {axisDeltaPhi, "#Delta#varphi (rad)"}, {axisDeltaEtaTpcMft, "#Delta#eta"}}; + std::vector corrAxisTpcFv0 = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisEtaTrigger, "#eta"}, + {axisEtaAssoc, "#eta"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEtaTpcFv0, "#Delta#eta"}}; + if (doprocessSameTpcFt0a) { - sameTpcFt0a.setObject(new CorrelationContainer("sameEvent_TPC_FT0A", "sameEvent_TPC_FT0A", corrAxisTpcFt0a, effAxis, userAxis)); - mixedTpcFt0a.setObject(new CorrelationContainer("mixedEvent_TPC_FT0A", "mixedEvent_TPC_FT0A", corrAxisTpcFt0a, effAxis, userAxis)); + same.setObject(new CorrelationContainer("sameEvent_TPC_FT0A", "sameEvent_TPC_FT0A", corrAxisTpcFt0a, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_TPC_FT0A", "mixedEvent_TPC_FT0A", corrAxisTpcFt0a, effAxis, userAxis)); } if (doprocessSameTpcFt0c) { - sameTpcFt0c.setObject(new CorrelationContainer("sameEvent_TPC_FT0C", "sameEvent_TPC_FT0C", corrAxisTpcFt0c, effAxis, userAxis)); - mixedTpcFt0c.setObject(new CorrelationContainer("mixedEvent_TPC_FT0C", "mixedEvent_TPC_FT0C", corrAxisTpcFt0c, effAxis, userAxis)); + same.setObject(new CorrelationContainer("sameEvent_TPC_FT0C", "sameEvent_TPC_FT0C", corrAxisTpcFt0c, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_TPC_FT0C", "mixedEvent_TPC_FT0C", corrAxisTpcFt0c, effAxis, userAxis)); + } + if (doprocessSameFt0aFt0c) { + same.setObject(new CorrelationContainer("sameEvent_FT0A_FT0C", "sameEvent_FT0A_FT0C", corrAxisFt0aFt0c, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_FT0A_FT0C", "mixedEvent_FT0A_FT0C", corrAxisFt0aFt0c, effAxis, userAxis)); } if (doprocessSameTpcMft) { - sameTpcMft.setObject(new CorrelationContainer("sameEvent_TPC_MFT", "sameEvent_TPC_MFT", corrAxisTpcMft, effAxis, userAxis)); - mixedTpcMft.setObject(new CorrelationContainer("mixedEvent_TPC_MFT", "mixedEvent_TPC_MFT", corrAxisTpcMft, effAxis, userAxis)); + same.setObject(new CorrelationContainer("sameEvent_TPC_MFT", "sameEvent_TPC_MFT", corrAxisTpcMft, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_TPC_MFT", "mixedEvent_TPC_MFT", corrAxisTpcMft, effAxis, userAxis)); + } + if (doprocessSameTpcFv0) { + same.setObject(new CorrelationContainer("sameEvent_TPC_FV0", "sameEvent_TPC_FV0", corrAxisTpcFv0, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent_TPC_FV0", "mixedEvent_TPC_FV0", corrAxisTpcFv0, effAxis, userAxis)); } LOGF(info, "End of init"); } @@ -396,6 +438,52 @@ struct FlowDecorrelation { return true; } + double getPhiFV0(uint64_t chno) + { + o2::fv0::Point3Dsimple chPos{}; + int const cellsInLeft[] = {0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 32, 40, 33, 41, 34, 42, 35, 43}; + bool const isChnoInLeft = std::find(std::begin(cellsInLeft), std::end(cellsInLeft), chno) != std::end(cellsInLeft); + + if (isChnoInLeft) { + chPos = fv0Det->getReadoutCenter(chno); + return RecoDecay::phi(chPos.x + (*offsetFV0)[0].getX(), chPos.y + (*offsetFV0)[0].getY()); + } else { + chPos = fv0Det->getReadoutCenter(chno); + return RecoDecay::phi(chPos.x + (*offsetFV0)[1].getX(), chPos.y + (*offsetFV0)[1].getY()); + } + } + + double getEtaFV0(uint64_t chno) + { + + int const cellsInLeft[] = {0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 32, 40, 33, 41, 34, 42, 35, 43}; + bool const isChnoInLeft = std::find(std::begin(cellsInLeft), std::end(cellsInLeft), chno) != std::end(cellsInLeft); + + o2::fv0::Point3Dsimple chPos{}; + chPos = fv0Det->getReadoutCenter(chno); + + float offsetX, offsetY, offsetZ; + + if (isChnoInLeft) { + offsetX = (*offsetFV0)[0].getX(); + offsetY = (*offsetFV0)[0].getY(); + offsetZ = (*offsetFV0)[0].getZ(); + } else { + offsetX = (*offsetFV0)[1].getX(); + offsetY = (*offsetFV0)[1].getY(); + offsetZ = (*offsetFV0)[1].getZ(); + } + + auto x = chPos.x + offsetX; + auto y = chPos.y + offsetY; + auto z = chPos.z + offsetZ; + + auto r = std::sqrt(x * x + y * y); + auto theta = std::atan2(r, z); + + return -std::log(std::tan(0.5 * theta)); + } + double getPhiFT0(uint64_t chno, int i) { // offsetFT0[0]: FT0A, offsetFT0[1]: FT0C @@ -458,9 +546,13 @@ struct FlowDecorrelation { void loadAlignParam(uint64_t timestamp) { offsetFT0 = ccdb->getForTimeStamp>("FT0/Calib/Align", timestamp); + offsetFV0 = ccdb->getForTimeStamp>("FV0/Calib/Align", timestamp); if (offsetFT0 == nullptr) { LOGF(fatal, "Could not load FT0/Calib/Align for timestamp %d", timestamp); } + if (offsetFV0 == nullptr) { + LOGF(fatal, "Could not load FV0/Calib/Align for timestamp %d", timestamp); + } } void loadGain(aod::BCsWithTimestamps::iterator const& bc) @@ -573,21 +665,29 @@ struct FlowDecorrelation { id = id + Ft0IndexA; ampl = ft0.amplitudeC()[iCh]; registry.fill(HIST("FT0Amp"), id, ampl); - ampl = ampl / cstFT0RelGain[iCh]; + ampl = ampl / cstFT0RelGain[id]; registry.fill(HIST("FT0AmpCorrect"), id, ampl); } else if (fitType == kFT0A) { id = ft0.channelA()[iCh]; ampl = ft0.amplitudeA()[iCh]; registry.fill(HIST("FT0Amp"), id, ampl); - ampl = ampl / cstFT0RelGain[iCh]; + ampl = ampl / cstFT0RelGain[id]; registry.fill(HIST("FT0AmpCorrect"), id, ampl); } else { LOGF(fatal, "Cor Index %d out of range", fitType); } } + template + void getChannelFV0(TFT0s const& fv0, std::size_t const& iCh, int& id, float& ampl) + { + id = fv0.channel()[iCh]; + ampl = fv0.amplitude()[iCh]; + registry.fill(HIST("FV0Amp"), id, ampl); + } + template - void fillCorrelationsTPCFT0(TTracks tracks1, TFT0s const& ft0, float posZ, int system, int corType, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + void fillCorrelationsTPCFIT(TTracks tracks1, TFT0s const& ft0, float posZ, int system, int corType, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms { if (system == SameEvent) { if (!cfgCentTableUnavailable) @@ -606,24 +706,22 @@ struct FlowDecorrelation { if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) continue; if (system == SameEvent) { - if (corType == kFT0C) { + if (corType == kFT0C) registry.fill(HIST("Trig_hist_TPC_FT0C"), fSampleIndex, posZ, track1.eta(), eventWeight * triggerWeight); - } else if (corType == kFT0A) { + else if (corType == kFT0A) registry.fill(HIST("Trig_hist_TPC_FT0A"), fSampleIndex, posZ, track1.eta(), eventWeight * triggerWeight); - } - if (cfgDrawEtaPhiDis && corType == kFT0A) { + if (cfgDrawEtaPhiDis && corType == kFT0A) registry.fill(HIST("EtaPhi"), track1.eta(), track1.phi(), eventWeight * triggerWeight); - } } std::size_t channelSize = 0; - if (corType == kFT0C) { - channelSize = ft0.channelC().size(); - } else if (corType == kFT0A) { + if (corType == kFT0A) channelSize = ft0.channelA().size(); - } else { + else if (corType == kFT0C) + channelSize = ft0.channelC().size(); + else LOGF(fatal, "Cor Index %d out of range", corType); - } + for (std::size_t iCh = 0; iCh < channelSize; iCh++) { int chanelid = 0; float ampl = 0.; @@ -637,8 +735,9 @@ struct FlowDecorrelation { continue; } } - auto phi = getPhiFT0(chanelid, corType); - auto eta = getEtaFT0(chanelid, corType); + double phi = getPhiFT0(chanelid, corType); + double eta = getEtaFT0(chanelid, corType); + if (cfgDrawEtaPhiDis && system == SameEvent) { registry.fill(HIST("EtaPhi"), eta, phi, ampl * eventWeight); } @@ -648,21 +747,21 @@ struct FlowDecorrelation { if (system == SameEvent) { if (corType == kFT0A) { registry.fill(HIST("Assoc_amp_same_TPC_FT0A"), chanelid, ampl); - sameTpcFt0a->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FT0A"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); } else if (corType == kFT0C) { registry.fill(HIST("Assoc_amp_same_TPC_FT0C"), chanelid, ampl); - sameTpcFt0c->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FT0C"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); } } else if (system == MixedEvent) { if (corType == kFT0A) { registry.fill(HIST("Assoc_amp_mixed_TPC_FT0A"), chanelid, ampl); - mixedTpcFt0a->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FT0A"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); } else if (corType == kFT0C) { registry.fill(HIST("Assoc_amp_mixed_TPC_FT0C"), chanelid, ampl); - mixedTpcFt0c->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FT0C"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); } } @@ -670,6 +769,113 @@ struct FlowDecorrelation { } } + template + void fillCorrelationsFT0AFT0C(TFT0s const& ft0Trig, TFT0s const& ft0Assoc, float posZ, int multTrk, int system, float cent, float eventWeight) + { + if (system == SameEvent) { + if (!cfgCentTableUnavailable) + registry.fill(HIST("Centrality_used"), cent); + registry.fill(HIST("Nch_used"), multTrk); + } + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + for (std::size_t iChA = 0; iChA < ft0Trig.channelA().size(); iChA++) { + int channelIdA = 0; + float amplA = 0.f; + getChannel(ft0Trig, iChA, channelIdA, amplA, kFT0A); + if ((cfgRejectFT0AInside && (channelIdA >= kFT0AInnerRingMin && channelIdA <= kFT0AInnerRingMax)) || (cfgRejectFT0AOutside && (channelIdA >= kFT0AOuterRingMin && channelIdA <= kFT0AOuterRingMax))) { + continue; + } + + const double phiA = getPhiFT0(channelIdA, kFT0A); + const double etaA = getEtaFT0(channelIdA, kFT0A); + + if (system == SameEvent) { + registry.fill(HIST("Trig_hist_FT0A_FT0C"), fSampleIndex, posZ, etaA, eventWeight * amplA); + } + + for (std::size_t iChC = 0; iChC < ft0Assoc.channelC().size(); iChC++) { + int channelIdC = 0; + float amplC = 0.f; + getChannel(ft0Assoc, iChC, channelIdC, amplC, kFT0C); + if ((cfgRejectFT0CInside && (channelIdC >= kFT0CInnerRingMin && channelIdC <= kFT0CInnerRingMax)) || (cfgRejectFT0COutside && (channelIdC >= kFT0COuterRingMin && channelIdC <= kFT0COuterRingMax))) { + continue; + } + + const double phiC = getPhiFT0(channelIdC, kFT0C); + const double etaC = getEtaFT0(channelIdC, kFT0C); + + const float deltaPhi = RecoDecay::constrainAngle(phiA - phiC, -PIHalf); + const float deltaEta = etaA - etaC; + const float pairWeight = amplA * amplC * eventWeight; + + if (system == SameEvent) { + registry.fill(HIST("Assoc_amp_same_FT0A_FT0C"), channelIdC, amplC); + same->getPairHist()->Fill(step, fSampleIndex, posZ, etaA, etaC, deltaPhi, deltaEta, pairWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_FT0A_FT0C"), deltaPhi, deltaEta, pairWeight); + } else if (system == MixedEvent) { + registry.fill(HIST("Assoc_amp_mixed_FT0A_FT0C"), channelIdC, amplC); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, etaA, etaC, deltaPhi, deltaEta, pairWeight); + registry.fill(HIST("deltaEta_deltaPhi_mixed_FT0A_FT0C"), deltaPhi, deltaEta, pairWeight); + } + } + } + } + + template + void fillCorrelationsTPCFV0(TTracks tracks1, TFT0s const& fv0, float posZ, int system, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + if (system == SameEvent) { + if (!cfgCentTableUnavailable) + registry.fill(HIST("Centrality_used"), cent); + registry.fill(HIST("Nch_used"), tracks1.size()); + } + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + // loop over all tracks + for (auto const& track1 : tracks1) { + + if (!trackSelected(track1)) + continue; + if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) + continue; + if (system == SameEvent) { + registry.fill(HIST("Trig_hist_TPC_FV0"), fSampleIndex, posZ, track1.eta(), eventWeight * triggerWeight); + } + + std::size_t channelSize = 0; + channelSize = fv0.channel().size(); + + for (std::size_t iCh = 0; iCh < channelSize; iCh++) { + int chanelid = 0; + float ampl = 0.; + getChannelFV0(fv0, iCh, chanelid, ampl); + + double phi = getPhiFV0(chanelid); + double eta = getEtaFV0(chanelid); + + if (cfgDrawEtaPhiDis && system == SameEvent) { + registry.fill(HIST("EtaPhi"), eta, phi, ampl * eventWeight); + } + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - phi, -PIHalf); + float deltaEta = track1.eta() - eta; + // fill the right sparse and histograms + if (system == SameEvent) { + registry.fill(HIST("Assoc_amp_same_TPC_FV0"), chanelid, ampl); + same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FV0"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + } else if (system == MixedEvent) { + registry.fill(HIST("Assoc_amp_mixed_TPC_FV0"), chanelid, ampl); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), eta, deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FV0"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + } + } + } + } + template bool eventSelected(TCollision collision, const int multTrk, const float centrality, const bool fillCounter) { @@ -804,9 +1010,9 @@ struct FlowDecorrelation { registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin fillYield(collision, tracks); - sameTpcFt0a->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); const auto& ft0 = collision.foundFT0(); - fillCorrelationsTPCFT0(tracks, ft0, collision.posZ(), SameEvent, kFT0A, cent, weightCent); + fillCorrelationsTPCFIT(tracks, ft0, collision.posZ(), SameEvent, kFT0A, cent, weightCent); } PROCESS_SWITCH(FlowDecorrelation, processSameTpcFt0a, "Process same event for TPC-FT0 correlation", true); @@ -869,7 +1075,7 @@ struct FlowDecorrelation { if (!cfgCentTableUnavailable) getCentralityWeight(weightCent, cent1); const auto& ft0 = collision2.foundFT0(); - fillCorrelationsTPCFT0(tracks1, ft0, collision1.posZ(), MixedEvent, kFT0A, cent1, eventWeight * weightCent); + fillCorrelationsTPCFIT(tracks1, ft0, collision1.posZ(), MixedEvent, kFT0A, cent1, eventWeight * weightCent); } } PROCESS_SWITCH(FlowDecorrelation, processMixedTpcFt0a, "Process mixed events for TPC-FT0A correlation", true); @@ -909,9 +1115,9 @@ struct FlowDecorrelation { registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin fillYield(collision, tracks); - sameTpcFt0c->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); const auto& ft0 = collision.foundFT0(); - fillCorrelationsTPCFT0(tracks, ft0, collision.posZ(), SameEvent, kFT0C, cent, weightCent); + fillCorrelationsTPCFIT(tracks, ft0, collision.posZ(), SameEvent, kFT0C, cent, weightCent); } PROCESS_SWITCH(FlowDecorrelation, processSameTpcFt0c, "Process same event for TPC-FT0C correlation", false); @@ -974,11 +1180,115 @@ struct FlowDecorrelation { if (!cfgCentTableUnavailable) getCentralityWeight(weightCent, cent1); const auto& ft0 = collision2.foundFT0(); - fillCorrelationsTPCFT0(tracks1, ft0, collision1.posZ(), MixedEvent, kFT0C, cent1, eventWeight * weightCent); + fillCorrelationsTPCFIT(tracks1, ft0, collision1.posZ(), MixedEvent, kFT0C, cent1, eventWeight * weightCent); } } PROCESS_SWITCH(FlowDecorrelation, processMixedTpcFt0c, "Process mixed events for TPC-FT0C correlation", false); + void processSameFt0aFt0c(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) + return; + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) { + cent = getCentrality(collision); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent, true)) + return; + if (!collision.has_foundFT0()) + return; + loadAlignParam(bc.timestamp()); + loadGain(bc); + loadCorrection(bc.timestamp()); + if (!cfgCentTableUnavailable) { + getCentralityWeight(weightCent, cent); + registry.fill(HIST("Centrality"), cent); + registry.fill(HIST("CentralityWeighted"), cent, weightCent); + } + registry.fill(HIST("Nch"), tracks.size()); + registry.fill(HIST("zVtx"), collision.posZ()); + + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + registry.fill(HIST("eventcount"), SameEvent); + + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& ft0 = collision.foundFT0(); + fillCorrelationsFT0AFT0C(ft0, ft0, collision.posZ(), tracks.size(), SameEvent, cent, weightCent); + } + PROCESS_SWITCH(FlowDecorrelation, processSameFt0aFt0c, "Process same event for FT0A-FT0C correlation", false); + + void processMixedFt0aFt0c(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -1, collisions, tracksTuple, &cache}; + for (auto it = pairs.begin(); it != pairs.end(); it++) { + auto& [collision1, tracks1, collision2, tracks2] = *it; + if (!collision1.sel8() || !collision2.sel8()) + continue; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), cent2, false)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) + continue; + + registry.fill(HIST("eventcount"), MixedEvent); + auto bc = collision1.bc_as(); + loadAlignParam(bc.timestamp()); + loadCorrection(bc.timestamp()); + loadGain(bc); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + const auto& ft0Trig = collision1.foundFT0(); + const auto& ft0Assoc = collision2.foundFT0(); + fillCorrelationsFT0AFT0C(ft0Trig, ft0Assoc, collision1.posZ(), tracks1.size(), MixedEvent, cent1, eventWeight * weightCent); + } + } + PROCESS_SWITCH(FlowDecorrelation, processMixedFt0aFt0c, "Process mixed events for FT0A-FT0C correlation", false); + template void fillCorrelationsTPCMFT(TTracks tracks1, TTracksAssoc tracks2, float posZ, int system, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms { @@ -1012,10 +1322,10 @@ struct FlowDecorrelation { float deltaEta = track1.eta() - track2.eta(); if (system == SameEvent) { - sameTpcMft->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), track2.eta(), deltaPhi, deltaEta, eventWeight * triggerWeight); + same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), track2.eta(), deltaPhi, deltaEta, eventWeight * triggerWeight); registry.fill(HIST("deltaEta_deltaPhi_same_TPC_MFT"), deltaPhi, deltaEta, eventWeight * triggerWeight); } else if (system == MixedEvent) { - mixedTpcMft->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), track2.eta(), deltaPhi, deltaEta, eventWeight * triggerWeight); + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.eta(), track2.eta(), deltaPhi, deltaEta, eventWeight * triggerWeight); registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_MFT"), deltaPhi, deltaEta, eventWeight * triggerWeight); } } @@ -1062,7 +1372,7 @@ struct FlowDecorrelation { fillYield(collision, tracks); fillCorrelationsTPCMFT(tracks, mfts, collision.posZ(), SameEvent, cent, weightCent); - sameTpcMft->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); } PROCESS_SWITCH(FlowDecorrelation, processSameTpcMft, "Process same events for TPC-MFT correlation", false); @@ -1134,6 +1444,112 @@ struct FlowDecorrelation { } } PROCESS_SWITCH(FlowDecorrelation, processMixedTpcMft, "Process same events for TPC-MFT correlation", false); + + void processSameTpcFv0(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::FV0As const&, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) + return; + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) { + cent = getCentrality(collision); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent, true)) + return; + if (!collision.has_foundFV0()) + return; + loadAlignParam(bc.timestamp()); + loadGain(bc); + loadCorrection(bc.timestamp()); + + if (!cfgCentTableUnavailable) { + getCentralityWeight(weightCent, cent); + registry.fill(HIST("Centrality"), cent); + registry.fill(HIST("CentralityWeighted"), cent, weightCent); + } + registry.fill(HIST("Nch"), tracks.size()); + registry.fill(HIST("zVtx"), collision.posZ()); + + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + fillYield(collision, tracks); + + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& fv0 = collision.foundFV0(); + fillCorrelationsTPCFV0(tracks, fv0, collision.posZ(), SameEvent, cent, weightCent); + } + PROCESS_SWITCH(FlowDecorrelation, processSameTpcFv0, "Process same events for TPC-FV0 correlation", false); + + void processMixedTpcFv0(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::FV0As const&, aod::BCsWithTimestamps const&) + { + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + for (auto it = pairs.begin(); it != pairs.end(); it++) { + auto& [collision1, tracks1, collision2, tracks2] = *it; + if (!collision1.sel8() || !collision2.sel8()) + continue; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), cent2, false)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + if (!(collision1.has_foundFV0() && collision2.has_foundFV0())) + continue; + + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + loadAlignParam(bc.timestamp()); + loadCorrection(bc.timestamp()); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + const auto& fv0 = collision2.foundFV0(); + fillCorrelationsTPCFV0(tracks1, fv0, collision1.posZ(), MixedEvent, cent1, eventWeight * weightCent); + } + } + PROCESS_SWITCH(FlowDecorrelation, processMixedTpcFv0, "Process mixed events for TPC-FV0 correlation", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/TwoParticleCorrelations/Tasks/longRangeDihadronCor.cxx b/PWGCF/TwoParticleCorrelations/Tasks/longRangeDihadronCor.cxx index f50d8f15e6c..b95075d694e 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/longRangeDihadronCor.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/longRangeDihadronCor.cxx @@ -98,6 +98,7 @@ struct LongRangeDihadronCor { O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodZvtxFT0vsPV, bool, false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference, use this cut at low multiplicities with caution") O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInTimeRangeStandard, bool, false, "no collisions in specified time range") O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayersAll, bool, true, "cut time intervals with dead ITS staves") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayer0123, bool, false, "cut time intervals with dead ITS staves (layers 0-3 only, for pp)") O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInRofStandard, bool, false, "no other collisions in this Readout Frame with per-collision multiplicity above threshold") O2_DEFINE_CONFIGURABLE(cfgEvSelkNoHighMultCollInPrevRof, bool, false, "veto an event if FT0C amplitude in previous ITS ROF is above threshold") O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") @@ -312,7 +313,7 @@ struct LongRangeDihadronCor { // Event Counter if ((doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameFt0aFt0c) && cfgUseAdditionalEventCut) { - registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{12, 0, 12}}}); + registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{13, 0, 13}}}); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(3, "kNoITSROFrameBorder"); @@ -320,11 +321,12 @@ struct LongRangeDihadronCor { registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(5, "kIsGoodZvtxFT0vsPV"); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(6, "kNoCollInTimeRangeStandard"); registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(7, "kIsGoodITSLayersAll"); - registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "kNoCollInRofStandard"); - registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(9, "kNoHighMultCollInPrevRof"); - registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(10, "occupancy"); - registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(11, "MultCorrelation"); - registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(12, "cfgEvSelV0AT0ACut"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "kIsGoodITSLayer0123"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(9, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(10, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(11, "occupancy"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(12, "MultCorrelation"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(13, "cfgEvSelV0AT0ACut"); } if (cfgEvSelMultCorrelation) { @@ -930,23 +932,29 @@ struct LongRangeDihadronCor { } if (fillCounter && cfgEvSelkIsGoodITSLayersAll) registry.fill(HIST("hEventCountSpecific"), 6.5); + if (cfgEvSelkIsGoodITSLayer0123 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + // for pp: cut time intervals with dead ITS staves on layers 0-3 only + return 0; + } + if (fillCounter && cfgEvSelkIsGoodITSLayer0123) + registry.fill(HIST("hEventCountSpecific"), 7.5); if (cfgEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { // no other collisions in this Readout Frame with per-collision multiplicity above threshold return 0; } if (fillCounter && cfgEvSelkNoCollInRofStandard) - registry.fill(HIST("hEventCountSpecific"), 7.5); + registry.fill(HIST("hEventCountSpecific"), 8.5); if (cfgEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { // veto an event if FT0C amplitude in previous ITS ROF is above threshold return 0; } if (fillCounter && cfgEvSelkNoHighMultCollInPrevRof) - registry.fill(HIST("hEventCountSpecific"), 8.5); + registry.fill(HIST("hEventCountSpecific"), 9.5); auto occupancy = collision.trackOccupancyInTimeRange(); if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) return 0; if (fillCounter && cfgEvSelOccupancy) - registry.fill(HIST("hEventCountSpecific"), 9.5); + registry.fill(HIST("hEventCountSpecific"), 10.5); auto multNTracksPV = collision.multNTracksPV(); if (cfgEvSelMultCorrelation) { @@ -976,14 +984,14 @@ struct LongRangeDihadronCor { } } if (fillCounter && cfgEvSelMultCorrelation) - registry.fill(HIST("hEventCountSpecific"), 10.5); + registry.fill(HIST("hEventCountSpecific"), 11.5); // V0A T0A 5 sigma cut float sigma = 5.0; if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) return 0; if (fillCounter && cfgEvSelV0AT0ACut) - registry.fill(HIST("hEventCountSpecific"), 11.5); + registry.fill(HIST("hEventCountSpecific"), 12.5); return 1; } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx b/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx index 6eb1425355d..c905bda396d 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx @@ -24,18 +24,18 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "CCDB/BasicCCDBManager.h" -#include "CommonConstants/MathConstants.h" -#include "CommonConstants/PhysicsConstants.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/StepTHn.h" -#include "Framework/runDataProcessing.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -1707,7 +1707,8 @@ struct Lambdastarproxy { Configurable lstarMixZvtxMax{"lstarMixZvtxMax", float{MixZvtxMaxDefault}, "Max |Δzvtx| (cm) for event mixing"}; Configurable lstarMixMultMax{"lstarMixMultMax", float{MixMultMaxDefault}, "Max |Δmult| for event mixing"}; Configurable lstarEnablePidQA{"lstarEnablePidQA", 0, "Enable PID QA histograms (dE/dx, TOF #beta, proxy invariant-mass QA, etc.): 1 = ON, 0 = OFF"}; - Configurable lstarEnableSparse{"lstarEnableSparse", 0, "Enable THnSparse invariant-mass histograms (#Lambda^{*} pK and proxy); 1 = ON, 0 = OFF"}; + Configurable lstarEnableSparse{"lstarEnableSparse", 1, "Enable THnSparse invariant-mass histograms (#Lambda^{*} pK and proxy); 1 = ON, 0 = OFF"}; + Configurable lstarLambdaAbsYMax{"lstarLambdaAbsYMax", 0.5f, "Max |y_{pK}| (or y_{proxy K}) for #Lambda^{*} candidates"}; struct KaonCand { float px, py, pz; @@ -1719,6 +1720,11 @@ struct Lambdastarproxy { int charge; int tid; }; + struct ProtonCand { + float px, py, pz; + int charge; + int tid; + }; // Helpers for invariant-mass kinematics static float phiFromPxPy(float px, float py) @@ -2004,7 +2010,7 @@ struct Lambdastarproxy { // Deuteron-proxy invariant mass (p_{proxy} from d/2 combined with K) histos.add("hDeuteronProxyMass", - "#Lambda^{*} proxy invariant mass from (d/2 + K);M_{pK} (GeV/c^{2});Counts", + "#Lambda^{*} proxy invariant mass from (d/2 + K);M_{p_{proxy}K} (GeV/c^{2});Counts", HistType::kTH1F, {massAxis}); // TPC dE/dx vs total momentum @@ -2405,8 +2411,10 @@ struct Lambdastarproxy { std::vector kaonCands; std::vector proxyCands; + std::vector protonCands; kaonCands.reserve(128); proxyCands.reserve(32); + protonCands.reserve(128); float eventMultFallback = 0.f; // fallback mixing variable: number of selected charged tracks (after quality cuts) @@ -2507,7 +2515,9 @@ struct Lambdastarproxy { // PID for deuteron candidates const float nsTPCDe = trkD.tpcNSigmaDe(); const float nsTOFDe = trkD.tofNSigmaDe(); - const bool isDeuteron = (std::abs(nsTPCDe) < lstarCutNsigmaTPCDe.value) && (std::abs(nsTOFDe) < lstarCutNsigmaTOFDe.value); + const bool hasTofDe = hasTOFMatch(trkD); + const bool isDeuteron = (std::abs(nsTPCDe) < lstarCutNsigmaTPCDe.value) && + (!hasTofDe || (std::abs(nsTOFDe) < lstarCutNsigmaTOFDe.value)); if (!isDeuteron) { continue; } @@ -2537,6 +2547,38 @@ struct Lambdastarproxy { proxyCands.push_back(ProxyCand{pxProxy, pyProxy, pzProxy, static_cast(trkD.sign()), static_cast(trkD.globalIndex())}); } + // Proton candidates (for genuine pK #Lambda^{*} reconstruction) + for (auto const& trkP : tracks) { + if (trkP.pt() < lstarCutPtMin.value || std::abs(trkP.eta()) > lstarCutEtaMax.value) { + continue; + } + if (!passTrackQuality(trkP)) { + continue; + } + if (trkP.sign() == 0) { + continue; + } + + const float nsTPCPr = trkP.tpcNSigmaPr(); + const float nsTOFPr = trkP.tofNSigmaPr(); + const bool hasTofPr = hasTOFMatch(trkP); + const bool isProton = (std::abs(nsTPCPr) < lstarCutNsigmaTPCPr.value) && + (!hasTofPr || (std::abs(nsTOFPr) < lstarCutNsigmaTOFPr.value)); + if (!isProton) { + continue; + } + + const float ptP = trkP.pt(); + const float etaP = trkP.eta(); + const float phiP = trkP.phi(); + + const float pxP = ptP * std::cos(phiP); + const float pyP = ptP * std::sin(phiP); + const float pzP = ptP * std::sinh(etaP); + + protonCands.push_back(ProtonCand{pxP, pyP, pzP, static_cast(trkP.sign()), static_cast(trkP.globalIndex())}); + } + // Kaon candidates for (auto const& trkK : tracks) { if (trkK.pt() < lstarCutPtMin.value || std::abs(trkK.eta()) > lstarCutEtaMax.value) { @@ -2552,7 +2594,9 @@ struct Lambdastarproxy { // PID for kaon candidates const float nsTPCK = trkK.tpcNSigmaKa(); const float nsTOFK = trkK.tofNSigmaKa(); - const bool isKaon = (std::abs(nsTPCK) < lstarCutNsigmaTPCKaon.value) && (std::abs(nsTOFK) < lstarCutNsigmaTOFKaon.value); + const bool hasTofK = hasTOFMatch(trkK); + const bool isKaon = (std::abs(nsTPCK) < lstarCutNsigmaTPCKaon.value) && + (!hasTofK || (std::abs(nsTOFK) < lstarCutNsigmaTOFKaon.value)); if (!isKaon) { continue; } @@ -2595,12 +2639,14 @@ struct Lambdastarproxy { return; } - // --- SAME-EVENT: proxy (d/2) + K --- - for (auto const& pr : proxyCands) { + // --- SAME-EVENT: genuine pK #Lambda^{*} candidates --- + for (auto const& pr : protonCands) { for (auto const& k : kaonCands) { - if (pr.tid == k.tid) - continue; // sanity check: should never match, but just in case of bug in candidate-building logic - const double mass = invariantMass(pr.px, pr.py, pr.pz, MassProton, k.px, k.py, k.pz, MassKaonCharged); + if (pr.tid == k.tid) { + continue; + } + const double mass = invariantMass(pr.px, pr.py, pr.pz, MassProton, + k.px, k.py, k.pz, MassKaonCharged); const float pxTot = pr.px + k.px; const float pyTot = pr.py + k.py; @@ -2608,17 +2654,16 @@ struct Lambdastarproxy { const float ptPair = std::sqrt(pxTot * pxTot + pyTot * pyTot); const float phiPair = phiFromPxPy(pxTot, pyTot); - const double eTot = std::sqrt(mass * mass + static_cast(pxTot) * pxTot + static_cast(pyTot) * pyTot + static_cast(pzTot) * pzTot); + const double eTot = std::sqrt(mass * mass + static_cast(pxTot) * pxTot + + static_cast(pyTot) * pyTot + static_cast(pzTot) * pzTot); const float yPair = rapidityFromEPz(eTot, pzTot); - // Inclusive invariant-mass spectrum for the #Lambda^{*} proxy - histos.fill(HIST("hDeuteronProxyMass"), mass); - if (lstarEnableSparse.value != 0) { - histos.fill(HIST("hLambdaStarProxySparse"), mass, ptPair, yPair, phiPair, eventMult); + if (std::abs(yPair) > lstarLambdaAbsYMax.value) { + continue; } - const bool unlikeSign = (pr.charge * k.charge) < 0; - if (unlikeSign) { + const bool unlikeSignPK = (pr.charge * k.charge) < 0; + if (unlikeSignPK) { histos.fill(HIST("hInvMassPKUnlike"), mass); histos.fill(HIST("hInvMassPKUnlikeVsPt"), mass, ptPair); if (lstarEnableSparse.value != 0) { @@ -2634,6 +2679,30 @@ struct Lambdastarproxy { } } + // --- SAME-EVENT: proxy (d/2) + K --- + for (auto const& pr : proxyCands) { + for (auto const& k : kaonCands) { + if (pr.tid == k.tid) + continue; // sanity check: should never match, but just in case of bug in candidate-building logic + const double mass = invariantMass(pr.px, pr.py, pr.pz, MassProton, k.px, k.py, k.pz, MassKaonCharged); + + const float pxTot = pr.px + k.px; + const float pyTot = pr.py + k.py; + const float pzTot = pr.pz + k.pz; + const float ptPair = std::sqrt(pxTot * pxTot + pyTot * pyTot); + const float phiPair = phiFromPxPy(pxTot, pyTot); + + const double eTot = std::sqrt(mass * mass + static_cast(pxTot) * pxTot + static_cast(pyTot) * pyTot + static_cast(pzTot) * pzTot); + const float yPair = rapidityFromEPz(eTot, pzTot); + + // Inclusive invariant-mass spectrum for the #Lambda^{*} proxy (d/2 + K) + histos.fill(HIST("hDeuteronProxyMass"), mass); + if (lstarEnableSparse.value != 0) { + histos.fill(HIST("hLambdaStarProxySparse"), mass, ptPair, yPair, phiPair, eventMult); + } + } + } + // --- MIXED-EVENT: current proxies + previous-event kaons --- for (auto const& prev : mLStarMixEvents) { if (std::abs(prev.zvtx - collision.posZ()) > lstarMixZvtxMax.value) @@ -2664,9 +2733,8 @@ struct Lambdastarproxy { const double eTot = std::sqrt(mass * mass + static_cast(pxTot) * pxTot + static_cast(pyTot) * pyTot + static_cast(pzTot) * pzTot); const float yPair = rapidityFromEPz(eTot, pzTot); - // Fill mixed-event THnSparse + // Fill mixed-event THnSparse (proxy only) if (lstarEnableSparse.value != 0) { - histos.fill(HIST("hLambdaStarPKMixedSparse"), mass, ptPair, yPair, phiPair, eventMult); histos.fill(HIST("hLambdaStarProxyMixedSparse"), mass, ptPair, yPair, phiPair, eventMult); } } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/pidDiHadron.cxx b/PWGCF/TwoParticleCorrelations/Tasks/pidDiHadron.cxx index 58e5162ba1e..2ae92312225 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/pidDiHadron.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/pidDiHadron.cxx @@ -120,7 +120,7 @@ struct PidDiHadron { O2_DEFINE_CONFIGURABLE(cfgGetNsigmaQA, bool, true, "Get QA histograms for selection of pions, kaons, and protons") O2_DEFINE_CONFIGURABLE(cfgGetdEdx, bool, true, "Get dEdx histograms for pions, kaons, and protons") O2_DEFINE_CONFIGURABLE(cfgUseAntiLambda, bool, true, "Use AntiLambda candidates for analysis") - O2_DEFINE_CONFIGURABLE(cfgPIDUseRejection, bool, true, "Turn off and on the exclusion criteria for PID determination") + O2_DEFINE_CONFIGURABLE(cfgPIDUseRejection, bool, true, "True: use exclusion exclusion criteria for PID determination, false: don't use exclusion") struct : ConfigurableGroup { O2_DEFINE_CONFIGURABLE(cfgMultCentHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); @@ -504,6 +504,10 @@ struct PidDiHadron { histos.add("TpcdEdx_ptwise", "", {HistType::kTHnSparseD, {{axisPt, axisTpcSignal, axisNsigmaTOF}}}); histos.add("ExpTpcdEdx_ptwise", "", {HistType::kTHnSparseD, {{axisPt, axisTpcSignal, axisNsigmaTOF}}}); histos.add("ExpSigma_ptwise", "", {HistType::kTHnSparseD, {{axisPt, axisSigma, axisNsigmaTOF}}}); + + histos.add("TpcdEdx_ptwise_afterCut", "", {HistType::kTHnSparseD, {{axisPt, axisTpcSignal, axisNsigmaTOF}}}); + histos.add("ExpTpcdEdx_ptwise_afterCut", "", {HistType::kTHnSparseD, {{axisPt, axisTpcSignal, axisNsigmaTOF}}}); + histos.add("ExpSigma_ptwise_afterCut", "", {HistType::kTHnSparseD, {{axisPt, axisSigma, axisNsigmaTOF}}}); } } // TPC-TOF PID QA hists if (cfgUseItsPID) { @@ -792,20 +796,44 @@ struct PidDiHadron { { switch (pid) { case 1: // For Pions - if (!cfgUseItsPID) + if (!cfgUseItsPID) { + if (cfgGetdEdx) { + double tpcExpSignalPi = track1.tpcSignal() - (track1.tpcNSigmaPi() * track1.tpcExpSigmaPi()); + + histos.fill(HIST("TpcdEdx_ptwise_afterCut"), track1.pt(), track1.tpcSignal(), track1.tofNSigmaPi()); + histos.fill(HIST("ExpTpcdEdx_ptwise_afterCut"), track1.pt(), tpcExpSignalPi, track1.tofNSigmaPi()); + histos.fill(HIST("ExpSigma_ptwise_afterCut"), track1.pt(), track1.tpcExpSigmaPi(), track1.tofNSigmaPi()); + } histos.fill(HIST("TofTpcNsigma_after"), track1.tpcNSigmaPi(), track1.tofNSigmaPi(), track1.pt()); + } if (cfgUseItsPID) histos.fill(HIST("TofItsNsigma_after"), itsResponse.nSigmaITS(track1), track1.tofNSigmaPi(), track1.pt()); break; case 2: // For Kaons - if (!cfgUseItsPID) + if (!cfgUseItsPID) { + if (cfgGetdEdx) { + double tpcExpSignalKa = track1.tpcSignal() - (track1.tpcNSigmaKa() * track1.tpcExpSigmaKa()); + + histos.fill(HIST("TpcdEdx_ptwise_afterCut"), track1.pt(), track1.tpcSignal(), track1.tofNSigmaKa()); + histos.fill(HIST("ExpTpcdEdx_ptwise_afterCut"), track1.pt(), tpcExpSignalKa, track1.tofNSigmaKa()); + histos.fill(HIST("ExpSigma_ptwise_afterCut"), track1.pt(), track1.tpcExpSigmaKa(), track1.tofNSigmaKa()); + } histos.fill(HIST("TofTpcNsigma_after"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + } if (cfgUseItsPID) histos.fill(HIST("TofItsNsigma_after"), itsResponse.nSigmaITS(track1), track1.tofNSigmaKa(), track1.pt()); break; case 3: // For Protons - if (!cfgUseItsPID) + if (!cfgUseItsPID) { + if (cfgGetdEdx) { + double tpcExpSignalPr = track1.tpcSignal() - (track1.tpcNSigmaPr() * track1.tpcExpSigmaPr()); + + histos.fill(HIST("TpcdEdx_ptwise_afterCut"), track1.pt(), track1.tpcSignal(), track1.tofNSigmaPr()); + histos.fill(HIST("ExpTpcdEdx_ptwise_afterCut"), track1.pt(), tpcExpSignalPr, track1.tofNSigmaPr()); + histos.fill(HIST("ExpSigma_ptwise_afterCut"), track1.pt(), track1.tpcExpSigmaPr(), track1.tofNSigmaPr()); + } histos.fill(HIST("TofTpcNsigma_after"), track1.tpcNSigmaPr(), track1.tofNSigmaPr(), track1.pt()); + } if (cfgUseItsPID) histos.fill(HIST("TofItsNsigma_after"), itsResponse.nSigmaITS(track1), track1.tofNSigmaPr(), track1.pt()); break; diff --git a/PWGDQ/Core/CutsLibrary.cxx b/PWGDQ/Core/CutsLibrary.cxx index c4fa96705ac..cb9c124d418 100644 --- a/PWGDQ/Core/CutsLibrary.cxx +++ b/PWGDQ/Core/CutsLibrary.cxx @@ -3529,6 +3529,11 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("pairD0")) { + cut->AddCut(GetAnalysisCut("pairD0")); + return cut; + } + if (!nameStr.compare("pairD0HighPt1")) { cut->AddCut(GetAnalysisCut("pairLxyzProjected3sigma")); cut->AddCut(GetAnalysisCut("pairPtLow5")); @@ -3881,7 +3886,49 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) } if (!nameStr.compare("alice3DielectronPID")) { - cut->AddCut(GetAnalysisCut("alice3StandardKine")); + cut->AddCut(GetAnalysisCut("alice3JpsiKine")); + cut->AddCut(GetAnalysisCut("alice3TrackQuality")); + cut->AddCut(GetAnalysisCut("alice3iTOFPIDEl")); + cut->AddCut(GetAnalysisCut("alice3oTOFPIDEl")); + cut->AddCut(GetAnalysisCut("alice3RICHPIDEl")); + return cut; + } + + if (!nameStr.compare("alice3DielectronPIDTOFOnly")) { + cut->AddCut(GetAnalysisCut("alice3JpsiKineTOFAcceptance")); + cut->AddCut(GetAnalysisCut("alice3TrackQuality")); + cut->AddCut(GetAnalysisCut("alice3iTOFPIDEl")); + cut->AddCut(GetAnalysisCut("alice3oTOFPIDEl")); + return cut; + } + + if (!nameStr.compare("alice3DielectronPIDRICHOnly")) { + cut->AddCut(GetAnalysisCut("alice3JpsiKineTOFAcceptance")); + cut->AddCut(GetAnalysisCut("alice3TrackQuality")); + cut->AddCut(GetAnalysisCut("alice3iTOFPIDEl")); + cut->AddCut(GetAnalysisCut("alice3oTOFPIDEl")); + return cut; + } + + if (!nameStr.compare("alice3DielectronPIDTOFOnly")) { + cut->AddCut(GetAnalysisCut("alice3JpsiKine")); + cut->AddCut(GetAnalysisCut("alice3TrackQuality")); + cut->AddCut(GetAnalysisCut("alice3iTOFPIDEl")); + cut->AddCut(GetAnalysisCut("alice3oTOFPIDEl")); + return cut; + } + + if (!nameStr.compare("alice3DielectronPIDTOFAcceptance")) { + cut->AddCut(GetAnalysisCut("alice3JpsiKineTOFAcceptance")); + cut->AddCut(GetAnalysisCut("alice3TrackQuality")); + cut->AddCut(GetAnalysisCut("alice3iTOFPIDEl")); + cut->AddCut(GetAnalysisCut("alice3oTOFPIDEl")); + cut->AddCut(GetAnalysisCut("alice3RICHPIDEl")); + return cut; + } + + if (!nameStr.compare("alice3DielectronPIDRICHAcceptance")) { + cut->AddCut(GetAnalysisCut("alice3JpsiKineRICHAcceptance")); cut->AddCut(GetAnalysisCut("alice3TrackQuality")); cut->AddCut(GetAnalysisCut("alice3iTOFPIDEl")); cut->AddCut(GetAnalysisCut("alice3oTOFPIDEl")); @@ -6732,6 +6779,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("pairD0")) { + cut->AddCut(VarManager::kMass, 1.814, 1.914); + return cut; + } + if (!nameStr.compare("pairJpsi")) { cut->AddCut(VarManager::kMass, 2.8, 3.3); return cut; @@ -6975,13 +7027,35 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("alice3JpsiKine")) { + cut->AddCut(VarManager::kPt, 1.0, 1000.0); + cut->AddCut(VarManager::kEta, -2.5, 2.5); // Total tracker acceptance in v3b geomety + return cut; + } + + if (!nameStr.compare("alice3JpsiKineTOFAcceptance")) { + cut->AddCut(VarManager::kPt, 1.0, 1000.0); + cut->AddCut(VarManager::kEta, -2.0, 2.0); // TOF acceptance in v3b geomety + return cut; + } + + if (!nameStr.compare("alice3JpsiKineRICHAcceptance")) { + cut->AddCut(VarManager::kPt, 1.0, 1000.0); + cut->AddCut(VarManager::kEta, -0.8, 0.8); // RICH acceptance in v3b geomety + return cut; + } + if (!nameStr.compare("alice3TrackQuality")) { + cut->AddCut(VarManager::kIsReconstructed, 0.5, 1.5); + cut->AddCut(VarManager::kNSiliconHits, 6.0, 12.0); cut->AddCut(VarManager::kTrackDCAxy, -3.0, 3.0); cut->AddCut(VarManager::kTrackDCAz, -3.0, 3.0); return cut; } if (!nameStr.compare("alice3TrackQualityTightDCA")) { + cut->AddCut(VarManager::kIsReconstructed, 0.5, 1.5); + cut->AddCut(VarManager::kNSiliconHits, 6.0, 12.0); cut->AddCut(VarManager::kTrackDCAxy, -1.0, 1.0); cut->AddCut(VarManager::kTrackDCAz, -1.0, 1.0); return cut; diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index d40e5dc9847..9d12b892322 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -42,7 +42,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "TF_NMFTs", "Number of MFT tracks per TF", false, 1000, 0.0, 200000.0, VarManager::kTFNMFTs); } if (!groupStr.CompareTo("event")) { - if (!subGroupStr.Contains("generator")) { + if (!subGroupStr.Contains("generator") && !subGroupStr.Contains("pairing")) { hm->AddHistogram(histClass, "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); hm->AddHistogram(histClass, "VtxZ_Run", "Vtx Z", true, 1, -0.5, 0.5, VarManager::kRunNo, 60, -15.0, 15.0, VarManager::kVtxZ, 1, 0, 1, VarManager::kNothing, "", "", "", VarManager::kNothing, VarManager::kNothing, false, true); hm->AddHistogram(histClass, "BC", "Event per BC", false, 3564, 0.0, 3564.0, VarManager::kBCOrbit); @@ -583,6 +583,14 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "FracAbove500um_NTracksTRD", "Fraction of tracks with DCAz > 500 um vs number of tracks with TRD", false, 100, 0.0, 1000.0, VarManager::kMultNTracksHasTRD, 100, 0.0, 1.0, VarManager::kDCAzFracAbove500um); hm->AddHistogram(histClass, "FracAbove5mm_NTracksTRD", "Fraction of tracks with DCAz > 5 mm vs number of tracks with TRD", false, 100, 0.0, 1000.0, VarManager::kMultNTracksHasTRD, 100, 0.0, 1.0, VarManager::kDCAzFracAbove5mm); } + if (subGroupStr.Contains("pairing")) { + if (subGroupStr.Contains("sameevent")) { + hm->AddHistogram(histClass, "NPairsPerEvent", "Number of track pairs per event", false, 100, 0.0, 100.0, VarManager::kNPairsPerEvent); + } + if (subGroupStr.Contains("mixedevent")) { + hm->AddHistogram(histClass, "NPairsPerEvent", "Number of track pairs per event", false, 500, 0.0, 500.0, VarManager::kNPairsPerEvent); + } + } } // end "event" if (!groupStr.CompareTo("two-collisions")) { @@ -1041,19 +1049,21 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kRap); } if (subGroupStr.Contains("alice3tracks")) { - hm->AddHistogram(histClass, "Pt_vs_PtMC", "pT vs MC pT", false, 200, 0.0, 20.0, VarManager::kPt, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "IsReconstructed", "IsReconstructed", false, 2, 0.5, 1.5, VarManager::kIsReconstructed); + hm->AddHistogram(histClass, "nSiliconHits", "Num silicon hits", false, 12, 0.0, 12.0, VarManager::kNSiliconHits); + hm->AddHistogram(histClass, "Pt_vs_PtMC", "pT vs MC pT", false, 200, 0.0, 100.0, VarManager::kPt, 200, 0.0, 20.0, VarManager::kMCPt); hm->AddHistogram(histClass, "Eta_vs_EtaMC", "#eta vs MC #eta", false, 150, -4.0, 4.0, VarManager::kEta, 150, -4.0, 4.0, VarManager::kMCEta); hm->AddHistogram(histClass, "Phi_vs_PhiMC", "#varphi vs MC #varphi", false, 50, 0.0, 2. * o2::constants::math::PI, VarManager::kPhi, 50, 0.0, 2. * o2::constants::math::PI, VarManager::kMCPhi); hm->AddHistogram(histClass, "Eta_DCAxy", "#eta vs DCA_{xy}", false, 80, -4.0, 4.0, VarManager::kEta, 400, -2.0, 2.0, VarManager::kTrackDCAxy); hm->AddHistogram(histClass, "Eta_DCAz", "#eta vs DCA_{z}", false, 80, -4.0, 4.0, VarManager::kEta, 800, -4.0, 4.0, VarManager::kTrackDCAz); } if (subGroupStr.Contains("resolutions")) { - hm->AddHistogram(histClass, "PtMC_vs_DeltaPt", "MC pT vs DeltaPt", false, 200, 0.0, 20.0, VarManager::kMCPt, 2000, -1.0, 1.0, VarManager::kDeltaPt); - hm->AddHistogram(histClass, "Pt_vs_DeltaPt", "pT vs pTRes", false, 200, 0.0, 20.0, VarManager::kPt, 2000, -1.0, 1.0, VarManager::kDeltaPt); + hm->AddHistogram(histClass, "PtMC_vs_DeltaPt", "MC pT vs DeltaPt", false, 200, 0.0, 100.0, VarManager::kMCPt, 2000, -1.0, 1.0, VarManager::kDeltaPt); + hm->AddHistogram(histClass, "Pt_vs_DeltaPt", "pT vs pTRes", false, 200, 0.0, 100.0, VarManager::kPt, 2000, -1.0, 1.0, VarManager::kDeltaPt); hm->AddHistogram(histClass, "EtaMC_vs_DeltaPt", "MC Eta vs DeltaPt", false, 200, -6.0, 6.0, VarManager::kMCEta, 2000, -1.0, 1.0, VarManager::kDeltaPt); hm->AddHistogram(histClass, "Eta_vs_DeltaPt", "MC Eta vs DeltaPt", false, 200, -6.0, 6.0, VarManager::kEta, 2000, -1.0, 1.0, VarManager::kDeltaPt); - hm->AddHistogram(histClass, "PtMC_vs_Res", "MC pT vs DeltaPt", false, 200, 0.0, 20.0, VarManager::kMCPt, 2000, -1.0, 1.0, VarManager::kPtResolution); - hm->AddHistogram(histClass, "Pt_vs_Res", "pT vs pTRes", false, 200, 0.0, 20.0, VarManager::kPt, 2000, -1.0, 1.0, VarManager::kPtResolution); + hm->AddHistogram(histClass, "PtMC_vs_Res", "MC pT vs DeltaPt", false, 200, 0.0, 100.0, VarManager::kMCPt, 2000, -1.0, 1.0, VarManager::kPtResolution); + hm->AddHistogram(histClass, "Pt_vs_Res", "pT vs pTRes", false, 200, 0.0, 100.0, VarManager::kPt, 2000, -1.0, 1.0, VarManager::kPtResolution); hm->AddHistogram(histClass, "EtaMC_vs_Res", "MC Eta vs pTRes", false, 200, -6.0, 6.0, VarManager::kMCEta, 2000, -1.0, 1.0, VarManager::kPtResolution); hm->AddHistogram(histClass, "Eta_vs_Res", "MC Eta vs pTRes", false, 200, -6.0, 6.0, VarManager::kEta, 2000, -1.0, 1.0, VarManager::kPtResolution); hm->AddHistogram(histClass, "PtRes", "pT Resolution", false, 2000, -1.0, 1.0, VarManager::kPtResolution); @@ -1168,6 +1178,14 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Weight", "", false, 50, 0.0, 5.0, VarManager::kMCParticleWeight); hm->AddHistogram(histClass, "MCImpPar_CentFT0CMC", "MC impact param vs MC Cent. FT0C", false, 20, 0.0, 20.0, VarManager::kMCEventImpParam, 100, 0.0, 100.0, VarManager::kMCEventCentrFT0C); } + if (!groupStr.CompareTo("mctruth_mult")) { + hm->AddHistogram(histClass, "PtMC_MultEta05", "MC pT vs mult |#eta| < 0.5", false, 200, 0.0, 20.0, VarManager::kMCPt, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta05); + hm->AddHistogram(histClass, "PtMC_MultEta08", "MC pT vs mult |#eta| < 0.8", false, 200, 0.0, 20.0, VarManager::kMCPt, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta08); + hm->AddHistogram(histClass, "PtMC_MultEta10", "MC pT vs mult |#eta| < 1.0", false, 200, 0.0, 20.0, VarManager::kMCPt, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta10); + hm->AddHistogram(histClass, "EtaMC_MultEta05", "MC Eta vs mult |#eta| < 0.5", false, 40, -2.0, 2.0, VarManager::kMCEta, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta05); + hm->AddHistogram(histClass, "EtaMC_MultEta08", "MC Eta vs mult |#eta| < 0.8", false, 40, -2.0, 2.0, VarManager::kMCEta, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta08); + hm->AddHistogram(histClass, "EtaMC_MultEta10", "MC Eta vs mult |#eta| < 1.0", false, 40, -2.0, 2.0, VarManager::kMCEta, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta10); + } if (!groupStr.CompareTo("energy-correlator-gen")) { double coschiBins[26]; @@ -1207,6 +1225,29 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Mass_MultFDDA", "Mass vs MultFDDA", false, 200, 2.0, 5.0, VarManager::kMass, 1000, 0, 25000.0, VarManager::kMultFDDA); hm->AddHistogram(histClass, "Mass_MultFDDC", "Mass vs MultFDDC", false, 200, 2.0, 5.0, VarManager::kMass, 1000, 0, 25000.0, VarManager::kMultFDDC); } + if (subGroupStr.Contains("mass_mult_pv")) { + double multAnalysisBins[4] = {0.0, 4.0, 8.0, 1000.0}; + + double multAnalsisMassBins[201] = {0.0}; + for (int i = 0; i <= 200; i++) { + multAnalsisMassBins[i] = 2.0 + i * 0.015; + } + + double multAnalysisPVBins[151] = {0.0}; + for (int i = 0; i <= 150; i++) { + multAnalysisPVBins[i] = i * 1.0; + } + + double multAnalysisFV0ABins[1001] = {0.0}; + for (int i = 0; i <= 1000; i++) { + multAnalysisFV0ABins[i] = i * 1.0; + } + + hm->AddHistogram(histClass, "Mass_VtxNcontribReal_Pt", "Mass vs VtxNcontribReal vs Pt", false, 200, multAnalsisMassBins, VarManager::kMass, 150, multAnalysisPVBins, VarManager::kVtxNcontribReal, 3, multAnalysisBins, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_MultFV0A_Pt", "Mass vs MultFV0A vs Pt", false, 200, multAnalsisMassBins, VarManager::kMass, 1000, multAnalysisFV0ABins, VarManager::kMultFV0A, 3, multAnalysisBins, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_MultFT0A_Pt", "Mass vs MultFT0A vs Pt", false, 200, multAnalsisMassBins, VarManager::kMass, 1000, multAnalysisFV0ABins, VarManager::kMultFT0A, 3, multAnalysisBins, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_MultFT0C_Pt", "Mass vs MultFT0C vs Pt", false, 200, multAnalsisMassBins, VarManager::kMass, 1000, multAnalysisFV0ABins, VarManager::kMultFT0C, 3, multAnalysisBins, VarManager::kPt); + } if (subGroupStr.Contains("barrel")) { hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 5.0, VarManager::kMass); hm->AddHistogram(histClass, "Mass_HighRange", "", false, 375, 0.0, 15.0, VarManager::kMass); @@ -1241,6 +1282,18 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Mass_VtxNcontribReal_VtxZ", "Mass vs VtxNcontribReal vs VtxZ", false, 200, 2.0, 5.0, VarManager::kMass, 150, 0, 150.0, VarManager::kVtxNcontribReal, 20, -10.0, 10.0, VarManager::kVtxZ); hm->AddHistogram(histClass, "VtxZ_VtxNcontribReal", "VtxZ vs VtxNcontribReal", false, 240, -12.0, 12.0, VarManager::kVtxZ, 200, 0, 200.0, VarManager::kVtxNcontribReal); } + if (subGroupStr.Contains("alice3barrel")) { + double pTBins[21] = { + 0.1, 0.5, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0, + 4.0, 5.0, 6.5, 8.0, 10.0, 12.0, 15.0, 20.0, + 30.0, 40.0, 60.0, 80.0, 100.0}; + + double massBins[501]; + for (int i = 0; i < 501; i++) { + massBins[i] = 0.01 * (i); + } + hm->AddHistogram(histClass, "Mass_PtLong", "", false, 500, massBins, VarManager::kMass, 20, pTBins, VarManager::kPt); + } if (subGroupStr.Contains("dielectron-polarization-he-pbpb")) { int varsHEpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaHE, VarManager::kPhiHE}; int binspT[5] = {100, 30, 10, 10, 10}; diff --git a/PWGDQ/Core/MixingLibrary.cxx b/PWGDQ/Core/MixingLibrary.cxx index 37278b90971..90fd639464a 100644 --- a/PWGDQ/Core/MixingLibrary.cxx +++ b/PWGDQ/Core/MixingLibrary.cxx @@ -200,3 +200,46 @@ void o2::aod::dqmixing::SetUpMixing(MixingHandler* mh, const char* mixingVarible mh->AddMixingVariable(VarManager::kNTPCcontribLongA, fPileUpLimsHashing.size(), fPileUpLimsHashing); } } + +// Set up mixing hashing by json +void o2::aod::dqmixing::SetUpMixingFromJSON(MixingHandler* mh, const char* json) +{ + rapidjson::Document document; + + rapidjson::ParseResult ok = document.Parse(json); + if (!ok) { + LOG(fatal) << "JSON parse error"; + return; + } + + for (auto it = document.MemberBegin(); it != document.MemberEnd(); ++it) { + std::string nameStr = it->name.GetString(); + const auto& obj = it->value; + + LOG(info) << "Configuring mixing variable: " << nameStr; + + if (!obj.HasMember("var") || !obj.HasMember("LimsHashing")) { + LOG(fatal) << "Missing 'var' or 'LimsHashing' in " << nameStr; + continue; + } + + // read var + std::string varStr = obj["var"].GetString(); + + // read limits + const auto& lims = obj["LimsHashing"]; + std::vector limits; + limits.reserve(lims.Size()); + for (auto& v : lims.GetArray()) { + limits.push_back(v.GetFloat()); + } + + if (VarManager::fgVarNamesMap.find(varStr) == VarManager::fgVarNamesMap.end()) { + LOG(fatal) << "Bad variable (" << varStr << ") specified for this mixing setting"; + return; + } + + // set up mixing variable + mh->AddMixingVariable(VarManager::fgVarNamesMap[varStr], limits.size(), limits); + } +} diff --git a/PWGDQ/Core/MixingLibrary.h b/PWGDQ/Core/MixingLibrary.h index db7f92583df..c6de5b9ecd3 100644 --- a/PWGDQ/Core/MixingLibrary.h +++ b/PWGDQ/Core/MixingLibrary.h @@ -11,16 +11,27 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#include + +#ifndef PWGDQ_CORE_MIXINGLIBRARY_H_ +#define PWGDQ_CORE_MIXINGLIBRARY_H_ + #include "PWGDQ/Core/MixingHandler.h" #include "PWGDQ/Core/VarManager.h" +#include + +#include "rapidjson/document.h" + namespace o2::aod { namespace dqmixing { void SetUpMixing(MixingHandler* mh, const char* mixingVarible); +void SetUpMixingFromJSON(MixingHandler* mh, const char* json); } // namespace dqmixing } // namespace o2::aod void o2::aod::dqmixing::SetUpMixing(MixingHandler* mh, const char* mixingVarible); +void o2::aod::dqmixing::SetUpMixingFromJSON(MixingHandler* mh, const char* json); + +#endif // PWGDQ_CORE_MIXINGLIBRARY_H_ diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index b058531989f..ac2902c0f3a 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -1435,6 +1435,8 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kR3SP] = ""; fgVariableNames[kR3EP] = "R_{3}^{EP} "; fgVariableUnits[kR3EP] = ""; + fgVariableNames[kNPairsPerEvent] = "number of pairs per event"; + fgVariableUnits[kNPairsPerEvent] = ""; fgVariableNames[kPairMass] = "mass"; fgVariableUnits[kPairMass] = "GeV/c2"; fgVariableNames[kPairMassDau] = "mass dilepton"; @@ -2065,6 +2067,7 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kTwoR2SP2"] = kTwoR2SP2; fgVarNamesMap["kTwoR2EP1"] = kTwoR2EP1; fgVarNamesMap["kTwoR2EP2"] = kTwoR2EP2; + fgVarNamesMap["kNPairsPerEvent"] = kNPairsPerEvent; fgVarNamesMap["kNEventWiseVariables"] = kNEventWiseVariables; fgVarNamesMap["kX"] = kX; fgVarNamesMap["kY"] = kY; diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 389050980e2..fa0f694d227 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include @@ -479,10 +480,11 @@ class VarManager : public TObject kV2ME_EP, kWV2ME_SP, kWV2ME_EP, - kTwoR2SP1, // Scalar product resolution of event1 for ME technique - kTwoR2SP2, // Scalar product resolution of event2 for ME technique - kTwoR2EP1, // Event plane resolution of event2 for ME technique - kTwoR2EP2, // Event plane resolution of event2 for ME technique + kTwoR2SP1, // Scalar product resolution of event1 for ME technique + kTwoR2SP2, // Scalar product resolution of event2 for ME technique + kTwoR2EP1, // Event plane resolution of event2 for ME technique + kTwoR2EP2, // Event plane resolution of event2 for ME technique + kNPairsPerEvent, // number of pairs per event in same-event or mixed-event pairing // Variables for event mixing with cumulant kV22m, @@ -1328,8 +1330,6 @@ class VarManager : public TObject static void FillTrackMC(const U& mcStack, T const& track, float* values = nullptr); template static void FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* values = nullptr, float Translow = 1. / 3, float Transhigh = 2. / 3); - template - static void FillEnergyCorrelatorsMCUnfolding(T1 const& dilepton, T2 const& hadron, T const& track, T3 const& t1, float* values = nullptr); template static void FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values = nullptr); template @@ -1362,8 +1362,10 @@ class VarManager : public TObject static void FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values); template static void FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = nullptr, float hadronMass = 0.0f); - template - static void FillEnergyCorrelator(T1 const& dilepton, T2 const& hadron, float* values = nullptr, float Translow = 1. / 3, float Transhigh = 2. / 3, bool applyFitMass = false, float sidebandMass = 0.0f); + template + static void FillEnergyCorrelatorTriple(T1 const& lepton1, T2 const& lepton2, T3 const& hadron, float* values = nullptr, float Translow = 1. / 3, float Transhigh = 2. / 3, bool applyFitMass = false, float sidebandMass = 0.0f); + template + static void FillEnergyCorrelatorsUnfoldingTriple(T1 const& lepton1, T2 const& lepton2, T3 const& hadron, T4 const& track, T5 const& t1, float* values = nullptr, bool applyFitMass = false); template static void FillDileptonPhoton(T1 const& dilepton, T2 const& photon, float* values = nullptr); template @@ -2320,6 +2322,9 @@ void VarManager::FillEvent(T const& event, float* values) values[kMCEventWeight] = event.weight(); values[kMCEventImpParam] = event.impactParameter(); values[kMCEventCentrFT0C] = event.centFT0C(); + values[kMultMCNParticlesEta05] = event.multMCNParticlesEta05(); + values[kMultMCNParticlesEta08] = event.multMCNParticlesEta08(); + values[kMultMCNParticlesEta10] = event.multMCNParticlesEta10(); } if constexpr ((fillMap & EventFilter) > 0 || (fillMap & RapidityGapFilter) > 0) { @@ -2448,7 +2453,7 @@ void VarManager::FillEventTracks(T const& tracks, float* values) values[kDCAzBimodalityCoefficientBinned] = -9999.0; } values[kDCAzNPeaks] = nPeaksBin; - cout << "Bimodality coefficient binned: " << bimodalityCoefficientBin << ", mean: " << mean << ", stddev: " << stddev << ", skewness: " << skewness << ", kurtosis: " << kurtosis << ", nPeaks: " << nPeaksBin << endl; + // cout << "Bimodality coefficient binned: " << bimodalityCoefficientBin << ", mean: " << mean << ", stddev: " << stddev << ", skewness: " << skewness << ", kurtosis: " << kurtosis << ", nPeaks: " << nPeaksBin << endl; // compute the binned bimodality coefficient and related statistics with a bin width of 50um and different trimming versions // more then 3 counts per bin auto [bimodalityCoefficientBinTrimmed1, meanBinTrimmed1, stddevBinTrimmed1, skewnessBinTrimmed1, kurtosisBinTrimmed1, nPeaksBinTrimmed1] = BimodalityCoefficientAndNPeaks(dcazValues, 0.005, 4); @@ -2462,7 +2467,7 @@ void VarManager::FillEventTracks(T const& tracks, float* values) values[kDCAzRMSBinnedTrimmed1] = -9999.0; } values[kDCAzNPeaksTrimmed1] = nPeaksBinTrimmed1; - cout << "Bimodality coefficient (trimmed 1): " << bimodalityCoefficientBinTrimmed1 << ", mean: " << meanBinTrimmed1 << ", stddev: " << stddevBinTrimmed1 << ", skewness: " << skewnessBinTrimmed1 << ", kurtosis: " << kurtosisBinTrimmed1 << ", nPeaks: " << nPeaksBinTrimmed1 << endl; + // cout << "Bimodality coefficient (trimmed 1): " << bimodalityCoefficientBinTrimmed1 << ", mean: " << meanBinTrimmed1 << ", stddev: " << stddevBinTrimmed1 << ", skewness: " << skewnessBinTrimmed1 << ", kurtosis: " << kurtosisBinTrimmed1 << ", nPeaks: " << nPeaksBinTrimmed1 << endl; // more than 3% of the entries per peak auto [bimodalityCoefficientBinTrimmed2, meanBinTrimmed2, stddevBinTrimmed2, skewnessBinTrimmed2, kurtosisBinTrimmed2, nPeaksBinTrimmed2] = BimodalityCoefficientAndNPeaks(dcazValues, 0.005, -100); if (stddevBinTrimmed2 > -1.0) { @@ -2475,7 +2480,7 @@ void VarManager::FillEventTracks(T const& tracks, float* values) values[kDCAzRMSBinnedTrimmed2] = -9999.0; } values[kDCAzNPeaksTrimmed2] = nPeaksBinTrimmed2; - cout << "Bimodality coefficient (trimmed 2): " << bimodalityCoefficientBinTrimmed2 << ", mean: " << meanBinTrimmed2 << ", stddev: " << stddevBinTrimmed2 << ", skewness: " << skewnessBinTrimmed2 << ", kurtosis: " << kurtosisBinTrimmed2 << ", nPeaks: " << nPeaksBinTrimmed2 << endl; + // cout << "Bimodality coefficient (trimmed 2): " << bimodalityCoefficientBinTrimmed2 << ", mean: " << meanBinTrimmed2 << ", stddev: " << stddevBinTrimmed2 << ", skewness: " << skewnessBinTrimmed2 << ", kurtosis: " << kurtosisBinTrimmed2 << ", nPeaks: " << nPeaksBinTrimmed2 << endl; // more than 5% of the entries per peak auto [bimodalityCoefficientBinTrimmed3, meanBinTrimmed3, stddevBinTrimmed3, skewnessBinTrimmed3, kurtosisBinTrimmed3, nPeaksBinTrimmed3] = BimodalityCoefficientAndNPeaks(dcazValues, 0.005, -20); if (stddevBinTrimmed3 > -1.0) { @@ -2488,7 +2493,7 @@ void VarManager::FillEventTracks(T const& tracks, float* values) values[kDCAzRMSBinnedTrimmed3] = -9999.0; } values[kDCAzNPeaksTrimmed3] = nPeaksBinTrimmed3; - cout << "Bimodality coefficient (trimmed 3): " << bimodalityCoefficientBinTrimmed3 << ", mean: " << meanBinTrimmed3 << ", stddev: " << stddevBinTrimmed3 << ", skewness: " << skewnessBinTrimmed3 << ", kurtosis: " << kurtosisBinTrimmed3 << ", nPeaks: " << nPeaksBinTrimmed3 << endl; + // cout << "Bimodality coefficient (trimmed 3): " << bimodalityCoefficientBinTrimmed3 << ", mean: " << meanBinTrimmed3 << ", stddev: " << stddevBinTrimmed3 << ", skewness: " << skewnessBinTrimmed3 << ", kurtosis: " << kurtosisBinTrimmed3 << ", nPeaks: " << nPeaksBinTrimmed3 << endl; // compute fraction of tracks with |DCAz| > 100um, 200um, 500um, 1mm, 2mm, 5mm, 10mm // make a loop over the DCAz values and count how many are above each threshold @@ -3355,35 +3360,6 @@ void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* va } } -template -void VarManager::FillEnergyCorrelatorsMCUnfolding(T1 const& dilepton, T2 const& hadron, T const& track, T3 const& t1, float* values) -{ - if (fgUsedVars[kMCCosChi_gen] || fgUsedVars[kMCWeight_gen] || fgUsedVars[kMCdeltaeta_gen] || fgUsedVars[kMCCosChi_rec] || fgUsedVars[kMCWeight_rec] || fgUsedVars[kMCdeltaeta_rec]) { - // energy correlators - float MassHadron; - if constexpr (pairType == kJpsiHadronMass) { - MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); - } - if constexpr (pairType == kJpsiPionMass) { - MassHadron = o2::constants::physics::MassPionCharged; - } - ROOT::Math::PtEtaPhiMVector v1_gen(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); - ROOT::Math::PtEtaPhiMVector v2_gen(t1.pt(), t1.eta(), t1.phi(), MassHadron); - float E_boost_gen = LorentzTransformJpsihadroncosChi("weight_boost", v1_gen, v2_gen); - float CosChi_gen = LorentzTransformJpsihadroncosChi("coschi", v1_gen, v2_gen); - values[kMCCosChi_gen] = CosChi_gen; - values[kMCWeight_gen] = E_boost_gen / o2::constants::physics::MassJPsi; - values[kMCdeltaeta_gen] = track.eta() - t1.eta(); - - ROOT::Math::PtEtaPhiMVector v1_rec(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); - ROOT::Math::PtEtaPhiMVector v2_rec(hadron.pt(), hadron.eta(), hadron.phi(), o2::constants::physics::MassPionCharged); - values[kMCCosChi_rec] = LorentzTransformJpsihadroncosChi("coschi", v1_rec, v2_rec); - float E_boost_rec = LorentzTransformJpsihadroncosChi("weight_boost", v1_rec, v2_rec); - values[kMCWeight_rec] = E_boost_rec / v1_rec.M(); - values[kMCdeltaeta_rec] = dilepton.eta() - hadron.eta(); - } -} - template void VarManager::FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values) { @@ -5812,9 +5788,16 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* } } -template -void VarManager::FillEnergyCorrelator(T1 const& dilepton, T2 const& hadron, float* values, float Translow, float Transhigh, bool applyFitMass, float sidebandMass) +template +void VarManager::FillEnergyCorrelatorTriple(T1 const& lepton1, T2 const& lepton2, T3 const& hadron, float* values, float Translow, float Transhigh, bool applyFitMass, float sidebandMass) { + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + + ROOT::Math::PtEtaPhiMVector v_lepton1(lepton1.pt(), lepton1.eta(), lepton1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v_lepton2(lepton2.pt(), lepton2.eta(), lepton2.phi(), m2); + ROOT::Math::PtEtaPhiMVector dilepton = v_lepton1 + v_lepton2; + float dileptonmass = o2::constants::physics::MassJPsi; if (applyFitMass) { dileptonmass = dilepton.mass(); @@ -5837,6 +5820,8 @@ void VarManager::FillEnergyCorrelator(T1 const& dilepton, T2 const& hadron, floa values[kPhiDau] = RecoDecay::constrainAngle(v2.phi(), -o2::constants::math::PIHalf); float deltaphi = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PI); + values[kDeltaPhi] = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PIHalf); + values[kDeltaEta] = v1.eta() - v2.eta(); values[kCosChi_randomPhi_trans] = -999.9f; values[kCosChi_randomPhi_toward] = -999.9f; values[kCosChi_randomPhi_away] = -999.9f; @@ -5872,6 +5857,49 @@ void VarManager::FillEnergyCorrelator(T1 const& dilepton, T2 const& hadron, floa } } } + +template +void VarManager::FillEnergyCorrelatorsUnfoldingTriple(T1 const& lepton1, T2 const& lepton2, T3 const& hadron, T4 const& track, T5 const& t1, float* values, bool applyFitMass) +{ + if (fgUsedVars[kMCCosChi_gen] || fgUsedVars[kMCWeight_gen] || fgUsedVars[kMCdeltaeta_gen] || fgUsedVars[kMCCosChi_rec] || fgUsedVars[kMCWeight_rec] || fgUsedVars[kMCdeltaeta_rec]) { + // energy correlators + + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + + ROOT::Math::PtEtaPhiMVector v_lepton1(lepton1.pt(), lepton1.eta(), lepton1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v_lepton2(lepton2.pt(), lepton2.eta(), lepton2.phi(), m2); + ROOT::Math::PtEtaPhiMVector dilepton = v_lepton1 + v_lepton2; + + float dileptonmass = o2::constants::physics::MassJPsi; + if (applyFitMass) { + dileptonmass = dilepton.mass(); + } + + float MassHadron; + if constexpr (pairType == kJpsiHadronMass) { + MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); + } + if constexpr (pairType == kJpsiPionMass) { + MassHadron = o2::constants::physics::MassPionCharged; + } + ROOT::Math::PtEtaPhiMVector v1_gen(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); + ROOT::Math::PtEtaPhiMVector v2_gen(t1.pt(), t1.eta(), t1.phi(), MassHadron); + float E_boost_gen = LorentzTransformJpsihadroncosChi("weight_boost", v1_gen, v2_gen); + float CosChi_gen = LorentzTransformJpsihadroncosChi("coschi", v1_gen, v2_gen); + values[kMCCosChi_gen] = CosChi_gen; + values[kMCWeight_gen] = E_boost_gen / o2::constants::physics::MassJPsi; + values[kMCdeltaeta_gen] = track.eta() - t1.eta(); + + ROOT::Math::PtEtaPhiMVector v1_rec(dilepton.pt(), dilepton.eta(), dilepton.phi(), dileptonmass); + ROOT::Math::PtEtaPhiMVector v2_rec(hadron.pt(), hadron.eta(), hadron.phi(), o2::constants::physics::MassPionCharged); + values[kMCCosChi_rec] = LorentzTransformJpsihadroncosChi("coschi", v1_rec, v2_rec); + float E_boost_rec = LorentzTransformJpsihadroncosChi("weight_boost", v1_rec, v2_rec); + values[kMCWeight_rec] = E_boost_rec / v1_rec.M(); + values[kMCdeltaeta_rec] = dilepton.eta() - hadron.eta(); + } +} + template void VarManager::FillDileptonPhoton(T1 const& dilepton, T2 const& photon, float* values) { @@ -6618,6 +6646,8 @@ void VarManager::FillTrackAlice3(T const& track, float* values) values[kITSClusterMap] = track.itsClusterMap(); } + values[kIsReconstructed] = track.isReconstructed(); + values[kNSiliconHits] = track.nSiliconHits(); values[kITSchi2] = track.itsChi2NCl(); } diff --git a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx index 235632d9bff..7993444ad80 100644 --- a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx @@ -861,20 +861,15 @@ struct TableMaker { // Function to compute the mu for pileup estimation, taken from EM code double calculateMu(const auto& bc) { - auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); - uint64_t timeStamp = bc.timestamp(); - std::map metadata; - mLHCIFdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); - auto bfilling = mLHCIFdata->getBunchFilling(); double nbc = bfilling.getFilledBCs().size(); double tvxRate; if (fConfigHistOutput.fConfigIrEstimator.value.empty()) { - tvxRate = mRateFetcher.fetch(&ccdbMgr, timeStamp, bc.runNumber(), "T0VTX"); + tvxRate = mRateFetcher.fetch(fCCDB.service, timeStamp, bc.runNumber(), "T0VTX"); } else { - tvxRate = mRateFetcher.fetch(&ccdbMgr, timeStamp, bc.runNumber(), fConfigHistOutput.fConfigIrEstimator.value); + tvxRate = mRateFetcher.fetch(fCCDB.service, timeStamp, bc.runNumber(), fConfigHistOutput.fConfigIrEstimator.value); } double nTriggersPerFilledBC = tvxRate / nbc / o2::constants::lhc::LHCRevFreq; @@ -1700,6 +1695,9 @@ struct TableMaker { } else { VarManager::SetZShift(fConfigCCDB.fManualZShift.value); } + if (fConfigHistOutput.fConfigFillBcStat) { + mLHCIFdata = fCCDB->getSpecific("GLO/Config/GRPLHCIF", bcs.begin().timestamp()); + } if (fConfigVariousOptions.fPropMuon) { VarManager::SetupMuonMagField(); } diff --git a/PWGDQ/Tasks/CMakeLists.txt b/PWGDQ/Tasks/CMakeLists.txt index cc660b53202..4bb0cf6d714 100644 --- a/PWGDQ/Tasks/CMakeLists.txt +++ b/PWGDQ/Tasks/CMakeLists.txt @@ -39,6 +39,11 @@ o2physics_add_dpl_workflow(efficiency-with-assoc-direct PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2::DetectorsVertexing COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(energy-correlator-direct + SOURCES dqEnergyCorrelator_direct.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(filter-pp SOURCES filterPP.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 96b4cf1ab4d..9fe021663bd 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -2176,7 +2176,6 @@ struct AnalysisSameEventPairing { template void runMCGen(MyEventsVtxCovSelected const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { - cout << "AnalysisSameEventPairing::runMCGen() called" << endl; uint32_t mcDecision = 0; int isig = 0; diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx index 948493f9cf4..4585a894098 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx @@ -19,8 +19,6 @@ #include "PWGDQ/Core/HistogramsLibrary.h" #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" -#include "PWGDQ/Core/MixingHandler.h" -#include "PWGDQ/Core/MixingLibrary.h" #include "PWGDQ/Core/VarManager.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" @@ -77,7 +75,6 @@ namespace o2::aod { namespace dqanalysisflags { -DECLARE_SOA_COLUMN(MixingHash, mixingHash, int); //! Hash used in event mixing //need to understand DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 32); //! Event decision DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelected, isBarrelSelected, 32); //! Barrel track decisions DECLARE_SOA_COLUMN(BarrelAmbiguityInBunch, barrelAmbiguityInBunch, int8_t); //! Barrel track in-bunch ambiguity @@ -186,8 +183,7 @@ DECLARE_SOA_COLUMN(OniaVz, oniaVz, float); DECLARE_SOA_COLUMN(OniaVtxZ, oniaVtxZ, float); } // namespace dqanalysisflags -DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents -DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", dqanalysisflags::MixingHash); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents //! joinable to ReducedEvents DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMB", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTER", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to ReducedTracksAssoc @@ -246,7 +242,6 @@ using MyMuonTracksWithCovWithAmbiguities = soa::Join; using MyEvents = soa::Join; using MyEventsSelected = soa::Join; -using MyEventsHashSelected = soa::Join; using MyBarrelTracksWithCov = soa::Join eventSel; - Produces hash; OutputObj fOutputList{"output"}; - Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; @@ -309,7 +302,6 @@ struct AnalysisEventSelection { Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; HistogramManager* fHistMan = nullptr; - MixingHandler* fMixHandler = nullptr; AnalysisCompositeCut* fEventCut; @@ -361,16 +353,6 @@ struct AnalysisEventSelection { fOutputList.setObject(fHistMan->GetMainHistogramList()); } - TString mixVarsString = fConfigMixingVariables.value; - std::unique_ptr objArray(mixVarsString.Tokenize(",")); - if (objArray->GetEntries() > 0) { - fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); - fMixHandler->Init(); - for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { - dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); - } - } - fCurrentRun = -1; fCCDB->setURL(fConfigCcdbUrl.value); fCCDB->setCaching(true); @@ -442,10 +424,6 @@ struct AnalysisEventSelection { auto& evIndices = fBCCollMap[bc.globalBC()]; evIndices.push_back(event.globalIndex()); } - if (fMixHandler != nullptr) { - int hh = fMixHandler->FindEventCategory(VarManager::fgValues); - hash(hh); - } } for (auto& event : mcEvents) { @@ -2143,15 +2121,9 @@ struct AnalysisDileptonTrack { Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; Configurable fConfigPublishTripletTable{"cfgPublishTripletTable", false, "Publish the triplet tables, BmesonCandidates"}; - Configurable fConfigApplyMassEC{"cfgApplyMassEC", false, "Apply fit mass for sideband for the energy correlator study"}; - Configurable> fConfigSavelessevents{"cfgSavelessevents", std::vector{1, 0}, "Save less events for the energy correlator study"}; - Configurable> fConfigTransRange{"cfgTransRange", std::vector{0.333333, 0.666667}, "Transverse region for the energy correlstor analysis"}; - Configurable fConfigEnergycorrelator{"cfgEnergycorrelator", false, "Add some hist for energy correlator study"}; } fConfigOptions; struct : ConfigurableGroup { @@ -2212,19 +2184,14 @@ struct AnalysisDileptonTrack { MCSignal* fDileptonLegSignal; MCSignal* fHadronSignal; - NoBinningPolicy fHashBin; - void init(o2::framework::InitContext& context) { cout << "AnalysisDileptonTrack::init() called" << endl; bool isBarrel = context.mOptions.get("processBarrel"); - bool isBarrelME = context.mOptions.get("processBarrelMixedEvent"); // bool isBarrelAsymmetric = context.mOptions.get("processDstarToD0Pi"); // bool isMuon = context.mOptions.get("processMuonSkimmed"); bool isMCGen = context.mOptions.get("processMCGen"); bool isDummy = context.mOptions.get("processDummy"); - bool isMCGen_energycorrelators = context.mOptions.get("processMCGenEnergyCorrelators") || context.mOptions.get("processMCGenEnergyCorrelatorsPion"); - bool isMCGen_energycorrelatorsME = context.mOptions.get("processMCGenEnergyCorrelatorsME") || context.mOptions.get("processMCGenEnergyCorrelatorsPionME"); if (isDummy) { if (isBarrel || isMCGen /*|| isBarrelAsymmetric*/ /*|| isMuon*/) { @@ -2469,11 +2436,8 @@ struct AnalysisDileptonTrack { fLegCutNames.push_back(pairLegCutName); // define dilepton histograms - if (!fConfigOptions.fConfigEnergycorrelator) { - DefineHistograms(fHistMan, Form("DileptonsSelected_%s", pairLegCutName.Data()), "barrel,vertexing"); - } else { - DefineHistograms(fHistMan, Form("DileptonsSelected_%s", pairLegCutName.Data()), ""); - } + DefineHistograms(fHistMan, Form("DileptonsSelected_%s", pairLegCutName.Data()), "barrel,vertexing"); + // loop over track cuts and create dilepton - track histogram directories for (int iCutTrack = 0; iCutTrack < fNCuts; iCutTrack++) { @@ -2485,9 +2449,6 @@ struct AnalysisDileptonTrack { DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), fConfigOptions.fConfigHistogramSubgroups.value.data()); for (auto& sig : fRecMCSignals) { DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigOptions.fConfigHistogramSubgroups.value.data()); - if (isBarrelME) { - DefineHistograms(fHistMan, Form("DileptonTrackMCMatchedME_%s_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigOptions.fConfigHistogramSubgroups.value.data()); - } } if (!cfgPairing_strCommonTrackCuts.IsNull()) { @@ -2537,18 +2498,6 @@ struct AnalysisDileptonTrack { } } - if (isMCGen_energycorrelators) { - for (auto& sig : fGenMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelators_%s", sig->GetName()), ""); - } - } - - if (isMCGen_energycorrelatorsME) { - for (auto& sig : fGenMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), ""); - } - } - TString addHistsStr = fConfigOptions.fConfigAddJSONHistograms.value; if (addHistsStr != "") { dqhistograms::AddHistogramsFromJSON(fHistMan, addHistsStr.Data()); @@ -2616,11 +2565,6 @@ struct AnalysisDileptonTrack { if (dilepton.sign() != 0) { continue; } - // dilepton rap cut - float rap = dilepton.rap(); - if (fConfigMCOptions.fConfigUseMCRapcut && abs(rap) > fConfigOptions.fConfigDileptonRapCutAbs) { - continue; - } VarManager::FillTrack(dilepton, fValuesDilepton); @@ -2679,11 +2623,6 @@ struct AnalysisDileptonTrack { continue; } auto trackMC = track.mcParticle(); - // for the energy correlator analysis - auto motherParticle = lepton1MC.template mothers_first_as(); - std::vector fTransRange = fConfigOptions.fConfigTransRange; - VarManager::FillEnergyCorrelator(dilepton, track, fValuesHadron, fTransRange[0], fTransRange[1], fConfigOptions.fConfigApplyMassEC); - VarManager::FillEnergyCorrelatorsMCUnfolding(dilepton, track, motherParticle, trackMC, fValuesHadron); mcDecision = 0; isig = 0; for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { @@ -2885,10 +2824,6 @@ struct AnalysisDileptonTrack { if (!event.isEventSelected_bit(0)) { continue; } - std::vector fSavelessevents = fConfigOptions.fConfigSavelessevents; - if (fSavelessevents[0] > 1 && event.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { - continue; - } auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); // groupedBarrelAssocs.bindInternalIndicesTo(&assocs); auto groupedDielectrons = dileptons.sliceBy(dielectronsPerCollision, event.globalIndex()); @@ -2898,114 +2833,6 @@ struct AnalysisDileptonTrack { cout << "AnalysisDileptonTrack::processBarrel() completed" << endl; } - void processBarrelMixedEvent(soa::Filtered& events, - BCsWithTimestamps const& bcs, - soa::Join const& assocs, - MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons, - McCollisions const& /*mcEvents*/, McParticles const& /*mcTracks*/) - { - if (events.size() == 0) { - return; - } - if (fCurrentRun != bcs.begin().runNumber()) { // start: runNumber - initParamsFromCCDB(bcs.begin().timestamp()); - fCurrentRun = bcs.begin().runNumber(); - } // end: runNumber - // loop over two event comibnations - for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigOptions.fConfigMixingDepth.value, -1, events, events)) { - // fill event quantities - if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { - continue; - } - std::vector fSavelessevents = fConfigOptions.fConfigSavelessevents; - if (fSavelessevents[0] > 1 && event1.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { - continue; - } - // get the dilepton slice for event1 - auto evDileptons = dileptons.sliceBy(dielectronsPerCollision, event1.globalIndex()); - evDileptons.bindExternalIndices(&events); - - // get the track associations slice for event2 - auto evAssocs = assocs.sliceBy(trackAssocsPerCollision, event2.globalIndex()); - evAssocs.bindExternalIndices(&events); - - uint32_t mcDecision = static_cast(0); - size_t isig = 0; - - // loop over dileptons - for (auto dilepton : evDileptons) { - // get full track info of tracks based on the index - auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); - auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); - if (!lepton1.has_mcParticle() || !lepton2.has_mcParticle()) { - continue; - } - auto lepton1MC = lepton1.mcParticle(); - auto lepton2MC = lepton2.mcParticle(); - // Check that the dilepton has zero charge - if (dilepton.sign() != 0) { - continue; - } - // dilepton rap cut - float rap = dilepton.rap(); - if (fConfigMCOptions.fConfigUseMCRapcut && abs(rap) > fConfigOptions.fConfigDileptonRapCutAbs) { - continue; - } - - // loop over associations - for (auto& assoc : evAssocs) { - - // check that this track fulfills at least one of the specified cuts - uint32_t trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); - if (!trackSelection) { - continue; - } - - // get the track from this association - // auto track = assoc.template track_as(); - auto track = tracks.rawIteratorAt(assoc.trackId()); - // check that this track is not included in the current dilepton - if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { - continue; - } - - if (!track.has_mcParticle()) { - continue; - } - auto trackMC = track.mcParticle(); - // for the energy correlator analysis - auto motherParticle = lepton1MC.template mothers_first_as(); - std::vector fTransRange = fConfigOptions.fConfigTransRange; - VarManager::FillEnergyCorrelator(dilepton, track, VarManager::fgValues, fTransRange[0], fTransRange[1], fConfigOptions.fConfigApplyMassEC); - VarManager::FillEnergyCorrelatorsMCUnfolding(dilepton, track, motherParticle, trackMC, VarManager::fgValues); - mcDecision = 0; - isig = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { - mcDecision |= (static_cast(1) << isig); - } - } - - // loop over dilepton leg cuts and track cuts and fill histograms separately for each combination - for (int icut = 0; icut < fNCuts; icut++) { - if (!dilepton.filterMap_bit(icut)) { - continue; - } - for (uint32_t iTrackCut = 0; iTrackCut < fTrackCutNames.size(); iTrackCut++) { - if (trackSelection & (static_cast(1) << iTrackCut)) { - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatchedME_%s_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), VarManager::fgValues); - } - } - } - } - } - } // end for (assocs) - } // end for (dileptons) - } // end event loop - } - /* void processDstarToD0Pi(soa::Filtered const& events, BCsWithTimestamps const& bcs, soa::Filtered> const& assocs, MyBarrelTracksWithCov const& tracks, soa::Filtered const& ditracks, @@ -3144,183 +2971,15 @@ struct AnalysisDileptonTrack { cout << "AnalysisDileptonTrack::processMCGen() completed" << endl; } - template - void runEnergyCorrelators(TEvent const& event, McParticles const& mcTracks) - { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.mcCollisionId()); - groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& t1 : groupedMCTracks) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - // apply kinematic cuts for signal - if ((t1_raw.pt() < fConfigOptions.fConfigDileptonLowpTCut || t1_raw.pt() > fConfigOptions.fConfigDileptonHighpTCut)) - continue; - if (abs(t1_raw.y()) > fConfigOptions.fConfigDileptonRapCutAbs) - continue; - // for the energy correlators - for (auto& t2 : groupedMCTracks) { - auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); - if (!t2_raw.isPhysicalPrimary()) { - continue; - } - - if (t2_raw.has_mothers()) { - auto mother_raw = t2_raw.template mothers_first_as(); - if (mother_raw.globalIndex() == t1_raw.globalIndex()) { - continue; - } - } - - if (t2_raw.pt() < fConfigMCOptions.fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCOptions.fConfigMCGenHadronEtaAbs.value) { - continue; - } - - std::vector fTransRange = fConfigOptions.fConfigTransRange; - VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues, fTransRange[0], fTransRange[1]); - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, t1_raw)) { - fHistMan->FillHistClass(Form("MCTruthEenergyCorrelators_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - - void processMCGenEnergyCorrelators(soa::Filtered const& events, - McCollisions const& /*mcEvents*/, McParticles const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_mcCollision()) { - continue; - } - std::vector fSavelessevents = fConfigOptions.fConfigSavelessevents; - if (fSavelessevents[0] > 1 && event.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { - continue; - } - runEnergyCorrelators(event, mcTracks); - } - } - - void processMCGenEnergyCorrelatorsPion(soa::Filtered const& events, - McCollisions const& /*mcEvents*/, McParticles const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_mcCollision()) { - continue; - } - runEnergyCorrelators(event, mcTracks); - } - } - - template - void runEnergyCorrelatorsMixedEvent(TEvent const& event1, TEvent const& event2, McParticles const& mcTracks) - { - auto groupedMCTracks1 = mcTracks.sliceBy(perReducedMcEvent, event1.mcCollisionId()); - auto groupedMCTracks2 = mcTracks.sliceBy(perReducedMcEvent, event2.mcCollisionId()); - groupedMCTracks1.bindInternalIndicesTo(&mcTracks); - groupedMCTracks2.bindInternalIndicesTo(&mcTracks); - for (auto& t1 : groupedMCTracks1) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - // apply kinematic cuts for signal - if ((t1_raw.pt() < fConfigOptions.fConfigDileptonLowpTCut || t1_raw.pt() > fConfigOptions.fConfigDileptonHighpTCut)) { - continue; - } - if (abs(t1_raw.y()) > fConfigOptions.fConfigDileptonRapCutAbs) { - continue; - } - // for the energy correlators - for (auto& t2 : groupedMCTracks2) { - auto t2_raw = groupedMCTracks2.rawIteratorAt(t2.globalIndex()); - if (!t2_raw.isPhysicalPrimary()) { - continue; - } - - if (t2_raw.has_mothers()) { - auto mother_raw = t2_raw.template mothers_first_as(); - if (mother_raw.globalIndex() == t1_raw.globalIndex()) { - continue; - } - } - - if (t2_raw.pt() < fConfigMCOptions.fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCOptions.fConfigMCGenHadronEtaAbs.value) { - continue; - } - - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, t1_raw)) { - VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); - fHistMan->FillHistClass(Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - - void processMCGenEnergyCorrelatorsME(soa::Filtered const& events, - McCollisions const& /*mcEvents*/, McParticles const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - // loop over two event comibnations - for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigOptions.fConfigMixingDepth.value, -1, events, events)) { - if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { - continue; - } - if (!event1.has_mcCollision() || !event2.has_mcCollision()) { - continue; - } - runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); - } - } - - void processMCGenEnergyCorrelatorsPionME(soa::Filtered const& events, - McCollisions const& /*mcEvents*/, McParticles const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - // loop over two event comibnations - for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigOptions.fConfigMixingDepth.value, -1, events, events)) { - if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { - continue; - } - if (!event1.has_mcCollision() || !event2.has_mcCollision()) { - continue; - } - runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); - } - } - void processDummy(MyEvents&) { // do nothing } PROCESS_SWITCH(AnalysisDileptonTrack, processBarrel, "Run barrel dilepton-track pairing, using skimmed data", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processBarrelMixedEvent, "Run barrel dilepton-hadron mixed event pairing", false); // PROCESS_SWITCH(AnalysisDileptonTrack, processDstarToD0Pi, "Run barrel pairing of D0 daughters with pion candidate, using skimmed data", false); // PROCESS_SWITCH(AnalysisDileptonTrack, processMuonSkimmed, "Run muon dilepton-track pairing, using skimmed data", false); PROCESS_SWITCH(AnalysisDileptonTrack, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelators, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPion, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPionME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", true); }; @@ -3431,9 +3090,5 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("DileptonHadronCorrelation")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); } - - if (classStr.Contains("MCTruthEenergyCorrelators")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy-correlator-gen"); - } } // end loop over histogram classes } diff --git a/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx b/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx new file mode 100644 index 00000000000..50eef8685c5 --- /dev/null +++ b/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx @@ -0,0 +1,1030 @@ +// 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. +// +// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no +// Configurable workflow for running several DQ or other PWG analyses + +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MCSignal.h" +#include "PWGDQ/Core/MCSignalLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/Core/PID/PIDTOFParamService.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TGeoGlobalMagField.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using std::cout; +using std::endl; +using std::string; + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +using MyEvents = soa::Join; +using MyBarrelTracksWithCov = soa::Join; + +// bit maps used for the Fill functions of the VarManager +constexpr static uint32_t gkEventFillMapWithMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra; +constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; + +// Forward declarations +void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks + +struct AnalysisEnergyCorrelator { + OutputObj fOutputList{"output"}; + + struct : ConfigurableGroup { // Event selection configurables + Configurable> fConfigZBins{"cfgZBins", std::vector{-10.0, -5.0, 0.0, 5.0, 10.0}, "Z vertex bins for mixing"}; + Configurable> fConfigMultBins{"cfgMultBins", std::vector{0.0, 20.0, 40.0, 60.0, 100.0}, "Multiplicity bins for mixing"}; + Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts in JSON"}; + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Event histograms"}; + Configurable fConfigAddEventMCHistogram{"cfgAddEventMCHistogram", "generator", "MC Event histograms"}; + Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; + Configurable fConfigEventfilterVtz{"cfgEventfilterVtz", 10.0, "Event filter Vtz"}; + Configurable fConfigEventQA{"cfgEventQA", false, "If true, fill Event QA histograms"}; + } fConfigEventOptions; + + struct : ConfigurableGroup { // Track selection configurables + Configurable fConfigTrackCuts{"cfgTrackCuts", "electronSelection1_ionut", "Comma separated list of barrel track cuts for electrons"}; + Configurable fConfigTrackCutsJSON{"cfgTrackCutsJSON", "", "Additional track cuts in JSON"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Track histograms"}; + Configurable fConfigTrackQA{"cfgTrackQA", false, "If true, fill Track QA histograms"}; + } fConfigTrackOptions; + + struct : ConfigurableGroup { // Pair selection configurables + Configurable fConfigJpsiMassMin{"cfgJpsiMassMin", 2.8, "J/psi mass minimum"}; + Configurable fConfigJpsiMassMax{"cfgJpsiMassMax", 3.3, "J/psi mass maximum"}; + Configurable fConfigJpsiPtMin{"cfgJpsiPtMin", 0.0, "J/psi pt minimum"}; + Configurable fConfigJpsiPtMax{"cfgJpsiPtMax", 100.0, "J/psi pt maximum"}; + Configurable fConfigJpsiRapMax{"cfgJpsiRapMax", 0.9, "J/psi rapidity maximum"}; + Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + Configurable recSignals{"cfgMCRecSignals", "eeFromJpsi", "Comma separated list of MC signals (reconstructed)"}; + Configurable recSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; + } fConfigPairOptions; + + struct : ConfigurableGroup { // Dilepton selection configurables + Configurable fConfigHadronCuts{"cfgHadronCuts", "NoPID", "Comma separated list of hadron track cuts"}; + Configurable fConfigHadronCutsJSON{"cfgHadronCutsJSON", "", "Additional hadron cuts in JSON"}; + Configurable fConfigApplyMassEC{"cfgApplyMassEC", false, "Apply fit mass for sideband for the energy correlator study"}; + Configurable> fConfigSavelessevents{"cfgSavelessevents", std::vector{1, 0}, "Save less events for the energy correlator study"}; + Configurable> fConfigTransRange{"cfgTransRange", std::vector{0.333333, 0.666667}, "Transverse region for the energy correlstor analysis"}; + Configurable fConfigAddDileptonHadronHistogram{"cfgAddDileptonHadronHistogram", "", "Dilepton-hadron histograms"}; + Configurable fConfigMCRecSignals{"cfgMCRecDileptonHadronSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable fConfigMCGenSignals{"cfgMCGenDileptonHadronSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignalsJSON{"cfgMCRecDileptonHadronSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; + Configurable fConfigMCGenSignalsJSON{"cfgMCGenDileptonHadronSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; + Configurable fConfigMCGenHadronEtaAbs{"cfgMCGenHadronEtaAbs", 0.9f, "eta abs range for the hadron"}; + Configurable fConfigMCGenHadronPtMin{"cfgMCGenHadronPtMin", 0.1f, "minimum pt for the hadron"}; + Configurable fConfigContainlepton{"cfgContainlepton", false, "If true, require the hadron to contain the lepton in its decay tree for the energy correlator study"}; + } fConfigDileptonHadronOptions; + + // Histogram configurables + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON"}; + + // CCDB configurables + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "CCDB url"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "CCDB timestamp"}; + + // Member variables + HistogramManager* fHistMan = nullptr; + MixingHandler* fMixHandler = nullptr; + + AnalysisCompositeCut* fEventCut = nullptr; + std::vector fTrackCuts; // Electron cuts + std::vector fHadronCuts; // Hadron cuts + + std::vector fTrackCutNames; + std::vector fHadronCutNames; + std::vector fHistNamesReco; + + std::map> fTrackHistNames; + std::map> fBarrelHistNamesMCmatched; + std::map fSelMap; + + std::vector fRecMCSignals; // MC signals for reconstructed pairs + std::vector fGenMCSignals; + std::vector fRecMCTripleSignals; // MC signals for reconstructed triples + + Service fCCDB; + int fCurrentRun = -1; + + // Preslice for association table + Preslice preslice = aod::track_association::collisionId; + + using MixingBinning = ColumnBinningPolicy; + std::unique_ptr fMixingBinning; + + void init(o2::framework::InitContext& context) + { + std::vector zBins = fConfigEventOptions.fConfigZBins.value; + zBins.insert(zBins.begin(), VARIABLE_WIDTH); + + std::vector multBins = fConfigEventOptions.fConfigMultBins.value; + multBins.insert(multBins.begin(), VARIABLE_WIDTH); + + fMixingBinning = std::make_unique(std::array, 2>{zBins, multBins}, true); + + bool isBarrelME = context.mOptions.get("processBarrelMixedEvent"); + bool isMCGen_energycorrelators = context.mOptions.get("processMCGenEnergyCorrelators") || context.mOptions.get("processMCGenEnergyCorrelatorsPion"); + bool isMCGen_energycorrelatorsME = context.mOptions.get("processMCGenEnergyCorrelatorsME") || context.mOptions.get("processMCGenEnergyCorrelatorsPionME"); + + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + // Setup Event Cuts + fEventCut = new AnalysisCompositeCut(true); + TString eventCutStr = fConfigEventOptions.fConfigEventCuts.value; + if (eventCutStr != "") { + AnalysisCut* cut = dqcuts::GetAnalysisCut(eventCutStr.Data()); + if (cut != nullptr) { + fEventCut->AddCut(cut); + } + } + // Additional cuts via JSON + TString eventCutJSONStr = fConfigEventOptions.fConfigEventCutsJSON.value; + if (eventCutJSONStr != "") { + std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); + for (auto& cutIt : jsonCuts) { + fEventCut->AddCut(cutIt); + } + } + + // Setup Electron Track Cuts + TString trackCutStr = fConfigTrackOptions.fConfigTrackCuts.value; + if (!trackCutStr.IsNull()) { + std::unique_ptr objArrayTrack(trackCutStr.Tokenize(",")); + for (int icut = 0; icut < objArrayTrack->GetEntries(); ++icut) { + fTrackCuts.push_back(dqcuts::GetCompositeCut(objArrayTrack->At(icut)->GetName())); + fTrackCutNames.push_back(objArrayTrack->At(icut)->GetName()); + } + } + + TString trackCutsJSON = fConfigTrackOptions.fConfigTrackCutsJSON.value; + if (trackCutsJSON != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(trackCutsJSON.Data()); + for (auto& t : addTrackCuts) { + fTrackCuts.push_back(reinterpret_cast(t)); + fTrackCutNames.push_back(t->GetName()); + trackCutStr += Form(",%s", t->GetName()); + } + } + + // Setting the MC rec signal names + TString sigNamesStr = fConfigPairOptions.recSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required + continue; + } + fRecMCSignals.push_back(sig); + } + } + + TString sigNamesHadronStr = fConfigDileptonHadronOptions.fConfigMCRecSignals.value; + std::unique_ptr objRecSigTripleArray(sigNamesHadronStr.Tokenize(",")); + if (!sigNamesHadronStr.IsNull()) { + for (int isig = 0; isig < objRecSigTripleArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigTripleArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << sig->GetName() << ") " << "does not have 3 prongs! Fix it"; + } + fRecMCTripleSignals.push_back(sig); + } else { + LOG(fatal) << "Signal at reconstructed level requested (" << objRecSigTripleArray->At(isig)->GetName() << ") " << "could not be retrieved from the library! -> skipped"; + } + } + } + + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigPairOptions.recSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 2) { // NOTE: only 2 prong signals + continue; + } + fRecMCSignals.push_back(mcIt); + } + } + + // Add the reco MCSignals from the JSON config + TString addMCTripleSignalsStr = fConfigDileptonHadronOptions.fConfigMCRecSignalsJSON.value; + if (addMCTripleSignalsStr != "") { + std::vector addMCTripleSignals = dqmcsignals::GetMCSignalsFromJSON(addMCTripleSignalsStr.Data()); + for (auto& mcIt : addMCTripleSignals) { + if (mcIt->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 3 prongs! Fix it"; + } + fRecMCTripleSignals.push_back(mcIt); + } + } + + // Setup Hadron Cuts + TString hadronCutStr = fConfigDileptonHadronOptions.fConfigHadronCuts.value; + if (!hadronCutStr.IsNull()) { + std::unique_ptr objArrayHadron(hadronCutStr.Tokenize(",")); + for (int icut = 0; icut < objArrayHadron->GetEntries(); ++icut) { + TString cutName = objArrayHadron->At(icut)->GetName(); + fHadronCuts.push_back(dqcuts::GetCompositeCut(cutName.Data())); + fHadronCutNames.push_back(cutName); + } + } + TString hadronCutsJSON = fConfigDileptonHadronOptions.fConfigHadronCutsJSON.value; + if (hadronCutsJSON != "") { + std::vector addHadronCuts = dqcuts::GetCutsFromJSON(hadronCutsJSON.Data()); + for (auto& t : addHadronCuts) { + fHadronCuts.push_back(reinterpret_cast(t)); + fHadronCutNames.push_back(t->GetName()); + hadronCutStr += Form(",%s", t->GetName()); + } + } + + // Add histogram classes for each specified MCsignal at the generator level + // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function + TString sigGenNamesStr = fConfigDileptonHadronOptions.fConfigMCGenSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + fGenMCSignals.push_back(sig); + } + } + + // Add the MCSignals from the JSON config + TString addMCSignalsGenStr = fConfigDileptonHadronOptions.fConfigMCGenSignalsJSON.value; + if (addMCSignalsGenStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsGenStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() > 2) { // NOTE: only 2 prong signals + continue; + } + fGenMCSignals.push_back(mcIt); + } + } + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); + + fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(true); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Setup Histograms + if (fConfigEventOptions.fConfigEventQA) { + DefineHistograms(fHistMan, "TimeFrameStats;Event_BeforeCuts;Event_AfterCuts;", fConfigEventOptions.fConfigAddEventHistogram.value.data()); + DefineHistograms(fHistMan, "EventsMC", fConfigEventOptions.fConfigAddEventMCHistogram.value.data()); // mc + } + + if (fConfigTrackOptions.fConfigTrackQA) { + TString histClasses = "AssocsBarrel_BeforeCuts;"; + // Configure histogram classes for each track cut; + // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) + for (auto& cut : fTrackCuts) { + TString nameStr = Form("AssocsBarrel_%s", cut->GetName()); + fHistNamesReco.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + } + DefineHistograms(fHistMan, histClasses.Data(), fConfigTrackOptions.fConfigAddTrackHistogram.value.data()); + } + TString histNames = ""; + // check that the barrel track cuts array required in this task is not empty + if (!trackCutStr.IsNull()) { + // tokenize and loop over the barrel cuts produced by the barrel track selection task + std::unique_ptr objArray(trackCutStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + TString tempStr = objArray->At(icut)->GetName(); + // if the current barrel selection cut is required in this task, then switch on the corresponding bit in the mask + // and assign histogram directories + + // assign the pair hist directories for the current cut + std::vector names = { + Form("PairsBarrelSEPM_%s", objArray->At(icut)->GetName()), + Form("PairsBarrelSEPP_%s", objArray->At(icut)->GetName()), + Form("PairsBarrelSEMM_%s", objArray->At(icut)->GetName())}; + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fTrackHistNames[icut] = names; + // assign hist directories for the MC matched pairs for each (track cut,MCsignal) combination + if (!sigNamesStr.IsNull()) { + for (size_t isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + names = { + Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName())}; + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fBarrelHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); + } // end loop over MC signals + } + } + DefineHistograms(fHistMan, histNames.Data(), fConfigPairOptions.fConfigAddSEPHistogram.value.data()); + } + + for (size_t iCutTrack = 0; iCutTrack < fTrackCutNames.size(); iCutTrack++) { + for (size_t iCutHadron = 0; iCutHadron < fHadronCutNames.size(); iCutHadron++) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s", fTrackCutNames[iCutTrack].Data(), fHadronCutNames[iCutHadron].Data()), fConfigDileptonHadronOptions.fConfigAddDileptonHadronHistogram.value.data()); + for (auto& sig : fRecMCTripleSignals) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s", fTrackCutNames[iCutTrack].Data(), fHadronCutNames[iCutHadron].Data(), sig->GetName()), fConfigDileptonHadronOptions.fConfigAddDileptonHadronHistogram.value.data()); + if (isBarrelME) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatchedME_%s_%s_%s", fTrackCutNames[iCutTrack].Data(), fHadronCutNames[iCutHadron].Data(), sig->GetName()), fConfigDileptonHadronOptions.fConfigAddDileptonHadronHistogram.value.data()); + } + } + } + } + + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() == 1) { + if (isMCGen_energycorrelators) { + DefineHistograms(fHistMan, Form("MCTruthGenSel_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelators_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelators_Pion_%s", sig->GetName()), ""); + } + if (isMCGen_energycorrelatorsME) { + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelatorsME_Pion_%s", sig->GetName()), ""); + } + } + } + + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // aditional histograms via JSON + + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + } + + template + void runDileptonHadron(TTrack1 const& track1, TTrack2 const& track2, int iEleCut, + THadron const& hadron, TEvent const& event, aod::McParticles const& /*mcParticles*/) + { + VarManager::ResetValues(0, VarManager::kNVars); // reset variables before filling + VarManager::FillEvent(event); + VarManager::FillTrack(hadron); + VarManager::FillTrackCollision(hadron, event); + + // Check that hadron is not one of the dilepton legs + if (hadron.globalIndex() == track1.globalIndex() || hadron.globalIndex() == track2.globalIndex()) { + return; + } + + if (!track1.has_mcParticle() || !track2.has_mcParticle() || !hadron.has_mcParticle()) { + return; + } + auto hadronMC = hadron.mcParticle(); + auto lepton1MC = track1.mcParticle(); + auto lepton2MC = track2.mcParticle(); + uint32_t mcDecision = 0; + int isig = 0; + for (auto sig = fRecMCTripleSignals.begin(); sig != fRecMCTripleSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, hadronMC)) { + mcDecision |= (static_cast(1) << isig); + } + } + auto motherParticle = lepton1MC.template mothers_first_as(); + // Fill dilepton-hadron variables + std::vector fTransRange = fConfigDileptonHadronOptions.fConfigTransRange; + VarManager::FillEnergyCorrelatorTriple(track1, track2, hadron, VarManager::fgValues, fTransRange[0], fTransRange[1], fConfigDileptonHadronOptions.fConfigApplyMassEC.value); + VarManager::FillEnergyCorrelatorsUnfoldingTriple(track1, track2, hadron, motherParticle, hadronMC, VarManager::fgValues, fConfigDileptonHadronOptions.fConfigApplyMassEC.value); + + int iHadronCut = 0; + for (auto hCut = fHadronCuts.begin(); hCut != fHadronCuts.end(); hCut++, iHadronCut++) { + if (!(*hCut)->IsSelected(VarManager::fgValues)) { + continue; + } + // Fill the corresponding histogram + if (!MixedEvent) { + fHistMan->FillHistClass( + Form("DileptonTrack_%s_%s", fTrackCutNames[iEleCut].Data(), fHadronCutNames[iHadronCut].Data()), + VarManager::fgValues); + } + for (uint32_t isig = 0; isig < fRecMCTripleSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + if (!MixedEvent) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s", fTrackCutNames[iEleCut].Data(), fHadronCutNames[iHadronCut].Data(), fRecMCTripleSignals[isig]->GetName()), VarManager::fgValues); + } + if (MixedEvent) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatchedME_%s_%s_%s", fTrackCutNames[iEleCut].Data(), fHadronCutNames[iHadronCut].Data(), fRecMCTripleSignals[isig]->GetName()), VarManager::fgValues); + } + } // end loop over MC signals + } + } + } + + // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) + template + void runSameEventPairing(TTrack1 const& t1, TTrack2 const& t2, int iEleCut, aod::McParticles const& /*mcParticles*/) + { + std::map> histNames = fTrackHistNames; + std::map> histNamesMC = fBarrelHistNamesMCmatched; + int sign1 = t1.sign(); + int sign2 = t2.sign(); + uint32_t mcDecision = static_cast(0); + // run MC matching for this pair + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_mcParticle() && t2.has_mcParticle()) { + if ((*sig)->CheckSignal(true, t1.mcParticle(), t2.mcParticle())) { + mcDecision |= (static_cast(1) << isig); + } + } + } // end loop over MC signals + + VarManager::FillPair(t1, t2); + + if (sign1 * sign2 < 0) { // +- pairs + fHistMan->FillHistClass(histNames[iEleCut][0].Data(), VarManager::fgValues); // reconstructed, unmatched + for (size_t isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[iEleCut * fRecMCSignals.size() + isig][0].Data(), VarManager::fgValues); // matched signal + } + } + } else { + if (sign1 > 0) { // ++ pairs + fHistMan->FillHistClass(histNames[iEleCut][1].Data(), VarManager::fgValues); + for (size_t isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[iEleCut * fRecMCSignals.size() + isig][1].Data(), VarManager::fgValues); + } + } + } else { // -- pairs + fHistMan->FillHistClass(histNames[iEleCut][2].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[iEleCut * fRecMCSignals.size() + isig][2].Data(), VarManager::fgValues); + } + } + } + } + } + + void processBarrel(MyEvents const& events, aod::TrackAssoc const& assocs, MyBarrelTracksWithCov const& /*tracks*/, soa::Join const& mcEvents, aod::McParticles const& mcParticles, BCsWithTimestamps const& bcs) + { + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillTimeFrame(bcs); + VarManager::FillTimeFrame(events); + VarManager::FillTimeFrame(mcEvents); + + if (events.size() == 0) + return; + + // CCDB initialization + if (fCurrentRun != bcs.begin().runNumber()) { + fCurrentRun = bcs.begin().runNumber(); + } + + if (fConfigEventOptions.fConfigEventQA) { + fHistMan->FillHistClass("TimeFrameStats", VarManager::fgValues); + } + + for (auto& event : mcEvents) { + // Reset the fValues array and fill event observables + VarManager::FillEvent(event); + if (fConfigEventOptions.fConfigEventQA) { + fHistMan->FillHistClass("EventsMC", VarManager::fgValues); + } + } + + // Event loop + for (auto& event : events) { + // Fill event variables first + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::FillEvent(event); + + if (fConfigEventOptions.fConfigEventQA) { + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); + } + + // Event selection + if (!fEventCut->IsSelected(VarManager::fgValues)) + continue; + + if (fConfigEventOptions.fConfigEventQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + + // saveless events for the energy correlator analysis + std::vector fSavelessevents = fConfigDileptonHadronOptions.fConfigSavelessevents.value; + if (fSavelessevents[0] > 1 && event.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { + continue; + } + + // Get associated tracks for this event + auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); + + // Triple loop: track1 (electron) x track2 (electron) x hadron + for (auto& a1 : groupedAssocs) { + auto t1 = a1.template track_as(); + + uint32_t filter1 = 0; + // Fill track variables + VarManager::FillTrack(t1); + VarManager::FillTrackCollision(t1, event); + if (t1.has_mcParticle()) { + VarManager::FillTrackMC(mcParticles, t1.mcParticle()); + } + + if (fConfigTrackOptions.fConfigTrackQA) { + fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", VarManager::fgValues); + } + + // Apply electron cuts and fill histograms + int iCut1 = 0; + for (auto cut1 = fTrackCuts.begin(); cut1 != fTrackCuts.end(); cut1++, iCut1++) { + if ((*cut1)->IsSelected(VarManager::fgValues)) { + filter1 |= (static_cast(1) << iCut1); + if (fConfigTrackOptions.fConfigTrackQA) { + fHistMan->FillHistClass(fHistNamesReco[iCut1], VarManager::fgValues); + } + } + } + + // Check opposite charge with t2 + for (auto& a2 : groupedAssocs) { + auto t2 = a2.template track_as(); + + // Avoid double counting: use track globalIndex + if (t2.globalIndex() <= t1.globalIndex()) { + continue; + } + + // Fill track variables for t2 (only once per t2) + VarManager::FillTrack(t2); + VarManager::FillTrackCollision(t2, event); + + // Compute filter2: which cuts t2 passes + uint32_t filter2 = 0; + int iCut2 = 0; + for (auto cut2 = fTrackCuts.begin(); cut2 != fTrackCuts.end(); cut2++, iCut2++) { + if ((*cut2)->IsSelected(VarManager::fgValues)) { + filter2 |= (static_cast(1) << iCut2); + } + } + + // Both tracks must pass at least one common cut + uint32_t twoTrackFilter = filter1 & filter2; + if (!twoTrackFilter) { + continue; + } + + // Fill pair histograms for all cuts that both tracks pass + for (size_t iCut = 0; iCut < fTrackCuts.size(); iCut++) { + if (twoTrackFilter & (static_cast(1) << iCut)) { + runSameEventPairing(t1, t2, iCut, mcParticles); + } + } + + float mass = VarManager::fgValues[VarManager::kMass]; + float pt = VarManager::fgValues[VarManager::kPt]; + float rap = VarManager::fgValues[VarManager::kRap]; + + // Apply J/psi cuts + if (mass < fConfigPairOptions.fConfigJpsiMassMin.value || mass > fConfigPairOptions.fConfigJpsiMassMax.value || + pt < fConfigPairOptions.fConfigJpsiPtMin.value || pt > fConfigPairOptions.fConfigJpsiPtMax.value || + std::abs(rap) > fConfigPairOptions.fConfigJpsiRapMax.value) { + continue; + } + + if (t1.sign() * t2.sign() >= 0) { + continue; // Must be opposite charge + } + + // correlate J/psi with hadrons + for (auto& aHadron : groupedAssocs) { + auto hadron = aHadron.template track_as(); + // Process dilepton-hadron correlation for each common cut + for (size_t iCut = 0; iCut < fTrackCuts.size(); iCut++) { + if (twoTrackFilter & (static_cast(1) << iCut)) { + runDileptonHadron(t1, t2, iCut, hadron, event, mcParticles); + } + } + } // end hadron loop + } // end track2 loop + } // end track1 loop + } // end event loop + } + + Filter eventFilter = nabs(aod::collision::posZ) < fConfigEventOptions.fConfigEventfilterVtz && aod::evsel::sel8 == true; + void processBarrelMixedEvent(soa::Filtered& events, aod::TrackAssoc const& assocs, MyBarrelTracksWithCov const& /*tracks*/, aod::McCollisions const& /*mcCollisions*/, aod::McParticles const& mcParticles, BCsWithTimestamps const& bcs) + { + if (events.size() == 0) { + return; + } + + // CCDB initialization + if (fCurrentRun != bcs.begin().runNumber()) { + fCurrentRun = bcs.begin().runNumber(); + } + + fSelMap.clear(); + // Event loop + for (auto& event : events) { + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event); + if (event.has_mcCollision()) { + VarManager::FillEvent(event.mcCollision()); + } + bool decision = false; + if (fEventCut->IsSelected(VarManager::fgValues)) { + decision = true; + } + fSelMap[event.globalIndex()] = decision; + } + + for (auto& [event1, event2] : selfCombinations(*fMixingBinning, fConfigEventOptions.fConfigMixingDepth.value, -1, events, events)) { + VarManager::ResetValues(0, VarManager::kNVars); + if (!fSelMap[event1.globalIndex()] || !fSelMap[event2.globalIndex()]) { + continue; + } + + // save less events if configured + std::vector fSavelessevents = fConfigDileptonHadronOptions.fConfigSavelessevents.value; + if (fSavelessevents[0] > 1 && event1.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { + continue; + } + + // Get associated tracks for this event + auto groupedAssocs1 = assocs.sliceBy(preslice, event1.globalIndex()); + if (groupedAssocs1.size() < 2) { + continue; // Need at least 2 tracks for pairing + } + auto groupedAssocs2 = assocs.sliceBy(preslice, event2.globalIndex()); + + // Triple loop: track1 (electron) x track2 (electron) x hadron + for (auto& a1 : groupedAssocs1) { + auto t1 = a1.template track_as(); + + uint32_t filter1 = 0; + // Fill track variables + VarManager::FillTrack(t1); + VarManager::FillTrackCollision(t1, event1); + + // Apply electron cuts and fill histograms + int iCut1 = 0; + for (auto cut1 = fTrackCuts.begin(); cut1 != fTrackCuts.end(); cut1++, iCut1++) { + if ((*cut1)->IsSelected(VarManager::fgValues)) { + filter1 |= (static_cast(1) << iCut1); + } + } + + // Check opposite charge with t2 + for (auto& a2 : groupedAssocs1) { + auto t2 = a2.template track_as(); + + // Avoid double counting: use track globalIndex + if (t2.globalIndex() <= t1.globalIndex()) + continue; + + // Fill track variables for t2 (only once per t2) + VarManager::FillTrack(t2); + VarManager::FillTrackCollision(t2, event1); + + // Compute filter2: which cuts t2 passes + uint32_t filter2 = 0; + int iCut2 = 0; + for (auto cut2 = fTrackCuts.begin(); cut2 != fTrackCuts.end(); cut2++, iCut2++) { + if ((*cut2)->IsSelected(VarManager::fgValues)) { + filter2 |= (static_cast(1) << iCut2); + } + } + + // Both tracks must pass at least one common cut + uint32_t twoTrackFilter = filter1 & filter2; + if (!twoTrackFilter) { + continue; + } + // Fill pair variables for cut + VarManager::FillPair(t1, t2, VarManager::fgValues); + float mass = VarManager::fgValues[VarManager::kMass]; + float pt = VarManager::fgValues[VarManager::kPt]; + float rap = VarManager::fgValues[VarManager::kRap]; + // Apply J/psi cuts + if (mass < fConfigPairOptions.fConfigJpsiMassMin.value || mass > fConfigPairOptions.fConfigJpsiMassMax.value || + pt < fConfigPairOptions.fConfigJpsiPtMin.value || pt > fConfigPairOptions.fConfigJpsiPtMax.value || + std::abs(rap) > fConfigPairOptions.fConfigJpsiRapMax.value) { + continue; + } + if (t1.sign() * t2.sign() >= 0) { + continue; // Must be opposite charge + } + // correlate J/psi with hadrons from different events + for (auto& aHadron : groupedAssocs2) { + auto hadron = aHadron.template track_as(); + // Process dilepton-hadron correlation for each common cut + for (size_t iCut = 0; iCut < fTrackCuts.size(); iCut++) { + if (twoTrackFilter & (static_cast(1) << iCut)) { + runDileptonHadron(t1, t2, iCut, hadron, event2, mcParticles); + } + } + } // end hadron loop + } // end track2 loop + } // end track1 loop + } // end event loop + } + + PresliceUnsorted perReducedMcEvent = aod::mcparticle::mcCollisionId; + template + void runEnergyCorrelators(TEvent const& event1, TEvent const& event2, McParticles const& mcTracks) + { + auto groupedMCTracks1 = mcTracks.sliceBy(perReducedMcEvent, event1.mcCollisionId()); + auto groupedMCTracks2 = mcTracks.sliceBy(perReducedMcEvent, event2.mcCollisionId()); + groupedMCTracks1.bindInternalIndicesTo(&mcTracks); + groupedMCTracks2.bindInternalIndicesTo(&mcTracks); + for (auto& t1 : groupedMCTracks1) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + if (t1.mcCollisionId() != event1.mcCollisionId()) { // check that the mc track belongs to the same mc collision as the reconstructed event + continue; + } + VarManager::FillTrackMC(mcTracks, t1_raw); + if (!MixedEvent && !PionMass) { + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + } + } + } + // apply kinematic cuts for signal + if ((t1_raw.pt() < fConfigPairOptions.fConfigJpsiPtMin || t1_raw.pt() > fConfigPairOptions.fConfigJpsiPtMax)) + continue; + if (std::abs(t1_raw.y()) > fConfigPairOptions.fConfigJpsiRapMax) + continue; + // for the energy correlators + for (auto& t2 : groupedMCTracks2) { + auto t2_raw = groupedMCTracks2.rawIteratorAt(t2.globalIndex()); + if (t2.mcCollisionId() != event2.mcCollisionId()) { // check that the mc track belongs to the same mc collision as the reconstructed event + continue; + } + if (!t2_raw.isPhysicalPrimary()) { + continue; + } + if (t2_raw.has_mothers()) { + auto mother_raw = t2_raw.template mothers_first_as(); + if (mother_raw.globalIndex() == t1_raw.globalIndex()) { + continue; + } + } + if (fConfigDileptonHadronOptions.fConfigContainlepton && std::abs(t2_raw.pdgCode()) != PDG_t::kPiPlus && std::abs(t2_raw.pdgCode()) != PDG_t::kKPlus && std::abs(t2_raw.pdgCode()) != PDG_t::kProton && std::abs(t2_raw.pdgCode()) != PDG_t::kElectron && std::abs(t2_raw.pdgCode()) != PDG_t::kMuonMinus) { + continue; + } + if (!fConfigDileptonHadronOptions.fConfigContainlepton && std::abs(t2_raw.pdgCode()) != PDG_t::kPiPlus && std::abs(t2_raw.pdgCode()) != PDG_t::kKPlus && std::abs(t2_raw.pdgCode()) != PDG_t::kProton) { + continue; + } + if (t2_raw.pt() < fConfigDileptonHadronOptions.fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigDileptonHadronOptions.fConfigMCGenHadronEtaAbs.value) { + continue; + } + std::vector fTransRange = fConfigDileptonHadronOptions.fConfigTransRange; + VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues, fTransRange[0], fTransRange[1]); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + if (!MixedEvent && !PionMass) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelators_%s", sig->GetName()), VarManager::fgValues); + } + if (MixedEvent && !PionMass) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), VarManager::fgValues); + } + if (!MixedEvent && PionMass) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelators_Pion_%s", sig->GetName()), VarManager::fgValues); + } + if (MixedEvent && PionMass) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelatorsME_Pion_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + } + + void processMCGenEnergyCorrelators(soa::Filtered& events, + McCollisions const& /*mcEvents*/, McParticles const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + for (auto& event : events) { + // Fill event variables first + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event); + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } + if (!event.has_mcCollision()) { + continue; + } + // saveless events for the energy correlator analysis + std::vector fSavelessevents = fConfigDileptonHadronOptions.fConfigSavelessevents.value; + if (fSavelessevents[0] > 1 && event.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { + continue; + } + runEnergyCorrelators(event, event, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsME(soa::Filtered& events, + McCollisions const& /*mcEvents*/, McParticles const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(*fMixingBinning, fConfigEventOptions.fConfigMixingDepth.value, -1, events, events)) { + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event1); + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } + VarManager::FillEvent(event2); + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } + if (!event1.has_mcCollision() || !event2.has_mcCollision()) { + continue; + } + // saveless events for the energy correlator analysis + std::vector fSavelessevents = fConfigDileptonHadronOptions.fConfigSavelessevents.value; + if (fSavelessevents[0] > 1 && event1.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { + continue; + } + runEnergyCorrelators(event1, event2, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPion(soa::Filtered& events, + McCollisions const& /*mcEvents*/, McParticles const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + for (auto& event : events) { + // Fill event variables first + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event); + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } + if (!event.has_mcCollision()) { + continue; + } + // saveless events for the energy correlator analysis + std::vector fSavelessevents = fConfigDileptonHadronOptions.fConfigSavelessevents.value; + if (fSavelessevents[0] > 1 && event.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { + continue; + } + runEnergyCorrelators(event, event, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPionME(soa::Filtered& events, + McCollisions const& /*mcEvents*/, McParticles const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(*fMixingBinning, fConfigEventOptions.fConfigMixingDepth.value, -1, events, events)) { + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event1); + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } + VarManager::FillEvent(event2); + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } + if (!event1.has_mcCollision() || !event2.has_mcCollision()) { + continue; + } + // saveless events for the energy correlator analysis + std::vector fSavelessevents = fConfigDileptonHadronOptions.fConfigSavelessevents.value; + if (fSavelessevents[0] > 1 && event1.globalIndex() % fSavelessevents[0] == fSavelessevents[1]) { + continue; + } + runEnergyCorrelators(event1, event2, mcTracks); + } + } + + void processDummy(aod::Collisions const&) + { + // Do nothing + } + + PROCESS_SWITCH(AnalysisEnergyCorrelator, processBarrel, "Process barrel analysis", false); + PROCESS_SWITCH(AnalysisEnergyCorrelator, processBarrelMixedEvent, "Run barrel dilepton-hadron mixed event pairing", false); + PROCESS_SWITCH(AnalysisEnergyCorrelator, processMCGenEnergyCorrelators, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisEnergyCorrelator, processMCGenEnergyCorrelatorsPion, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisEnergyCorrelator, processMCGenEnergyCorrelatorsME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisEnergyCorrelator, processMCGenEnergyCorrelatorsPionME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisEnergyCorrelator, processDummy, "Dummy process function", true); +}; + +// Histogram definitions +void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +{ + std::unique_ptr objArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { + TString classStr = objArray->At(iclass)->GetName(); + histMan->AddHistClass(classStr.Data()); + TString histName = histGroups; + // NOTE: The level of detail for histogramming can be controlled via configurables + if (classStr.Contains("TimeFrameStats")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "timeframe"); + } + if (classStr.Contains("Event")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); + } + if ((classStr.Contains("Track") || classStr.Contains("Assoc")) && !classStr.Contains("Pairs")) { + if (classStr.Contains("Barrel")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + } + } + if (classStr.Contains("Pairs")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + } + if (classStr.Contains("DileptonTrack")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", histName); + } + if (classStr.Contains("MCTruthEenergyCorrelators")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy-correlator-gen"); + } + if (classStr.Contains("MCTruthGenSel")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); + } + } // end loop over histogram classes +} + +// Workflow definition +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGDQ/Tasks/mftMchMatcher.cxx b/PWGDQ/Tasks/mftMchMatcher.cxx index a3b3779a83a..efabe3b2d51 100644 --- a/PWGDQ/Tasks/mftMchMatcher.cxx +++ b/PWGDQ/Tasks/mftMchMatcher.cxx @@ -544,6 +544,10 @@ struct mftMchMatcher { auto const& mchTrack = muonTrack.template matchMCHTrack_as(); auto const& mftTrack = muonTrack.template matchMFTTrack_as(); + if (!muonTrack.has_mcParticle() || !mftTrack.has_mcParticle()) { + return result; + } + bool isPaired = isPairedMuon(mchTrack.globalIndex(), matchablePairs); std::pair matchPair{mchTrack.globalIndex(), mftTrack.globalIndex()}; bool isTrueMatch = std::find(matchablePairs.begin(), matchablePairs.end(), matchPair) != matchablePairs.end(); diff --git a/PWGDQ/Tasks/qaMatching.cxx b/PWGDQ/Tasks/qaMatching.cxx index fadcd6eb6fb..ea18c0aa9d7 100644 --- a/PWGDQ/Tasks/qaMatching.cxx +++ b/PWGDQ/Tasks/qaMatching.cxx @@ -95,6 +95,7 @@ struct qaMatching { double matchScoreProd{-1}; double matchChi2Prod{-1}; int matchRankingProd{-1}; + int mftMchMatchAttempts{0}; MuonMatchType matchType{kMatchTypeUndefined}; }; @@ -161,58 +162,107 @@ struct qaMatching { std::map mMatchingFunctionMap; ///< MFT-MCH Matching function // Chi2 matching interface - static constexpr int sChi2FunctionsNum = 3; + static constexpr int sChi2FunctionsNum = 5; struct : ConfigurableGroup { - std::array, sChi2FunctionsNum> fFunctionLabel{{ - {"cfgChi2FunctionLabel_0", std::string{"ProdAll"}, "Text label identifying this chi2 matching method"}, - {"cfgChi2FunctionLabel_1", std::string{"MatchXYPhiTanlMom"}, "Text label identifying this chi2 matching method"}, - {"cfgChi2FunctionLabel_2", std::string{"MatchXYPhiTanl"}, "Text label identifying this chi2 matching method"}, - }}; - std::array, sChi2FunctionsNum> fFunctionName{{{"cfgChi2FunctionNames_0", std::string{"prod"}, "Name of the chi2 matching function"}, - {"cfgChi2FunctionNames_1", std::string{"matchALL"}, "Name of the chi2 matching function"}, - {"cfgChi2FunctionNames_2", std::string{"matchXYPhiTanl"}, "Name of the chi2 matching function"}}}; - std::array, sChi2FunctionsNum> fMatchingScoreCut{{ - {"cfgChi2FunctionMatchingScoreCut_0", 0.f, "Minimum score value for selecting good matches"}, - {"cfgChi2FunctionMatchingScoreCut_1", 0.5f, "Minimum score value for selecting good matches"}, - {"cfgChi2FunctionMatchingScoreCut_2", 0.5f, "Minimum score value for selecting good matches"}, - }}; - std::array, sChi2FunctionsNum> fMatchingPlaneZ{{ - {"cfgChi2FunctionMatchingPlaneZ_0", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, - {"cfgChi2FunctionMatchingPlaneZ_1", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, - {"cfgChi2FunctionMatchingPlaneZ_2", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, - }}; - std::array, sChi2FunctionsNum> fMatchingExtrapMethod{{ - {"cfgMatchingExtrapMethod_0", static_cast(0), "Method for MCH track extrapolation to maching plane"}, - {"cfgMatchingExtrapMethod_1", static_cast(0), "Method for MCH track extrapolation to maching plane"}, - {"cfgMatchingExtrapMethod_2", static_cast(0), "Method for MCH track extrapolation to maching plane"}, - }}; + Configurable fFunctionLabel_1{"cfgChi2FunctionLabel_1", std::string{"ProdAll"}, "Text label identifying this chi2 matching method"}; + Configurable fFunctionLabel_2{"cfgChi2FunctionLabel_2", std::string{"MatchXYPhiTanlMom"}, "Text label identifying this chi2 matching method"}; + Configurable fFunctionLabel_3{"cfgChi2FunctionLabel_3", std::string{"MatchXYPhiTanl"}, "Text label identifying this chi2 matching method"}; + Configurable fFunctionLabel_4{"cfgChi2FunctionLabel_4", std::string{""}, "Text label identifying this chi2 matching method"}; + Configurable fFunctionLabel_5{"cfgChi2FunctionLabel_5", std::string{""}, "Text label identifying this chi2 matching method"}; + std::array*, sChi2FunctionsNum> fFunctionLabel{ + &fFunctionLabel_1, &fFunctionLabel_2, &fFunctionLabel_3, &fFunctionLabel_4, &fFunctionLabel_5}; + + Configurable fFunctionNames_1{"cfgChi2FunctionNames_1", std::string{"prod"}, "Name of the chi2 matching function"}; + Configurable fFunctionNames_2{"cfgChi2FunctionNames_2", std::string{"matchALL"}, "Name of the chi2 matching function"}; + Configurable fFunctionNames_3{"cfgChi2FunctionNames_3", std::string{"matchXYPhiTanl"}, "Name of the chi2 matching function"}; + Configurable fFunctionNames_4{"cfgChi2FunctionNames_4", std::string{""}, "Name of the chi2 matching function"}; + Configurable fFunctionNames_5{"cfgChi2FunctionNames_5", std::string{""}, "Name of the chi2 matching function"}; + std::array*, sChi2FunctionsNum> fFunctionName{ + &fFunctionNames_1, &fFunctionNames_2, &fFunctionNames_3, &fFunctionNames_4, &fFunctionNames_5}; + + Configurable fMatchingScoreCut_1{"cfgChi2FunctionMatchingScoreCut_1", 0.f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_2{"cfgChi2FunctionMatchingScoreCut_2", 0.5f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_3{"cfgChi2FunctionMatchingScoreCut_3", 0.5f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_4{"cfgChi2FunctionMatchingScoreCut_4", 0.5f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_5{"cfgChi2FunctionMatchingScoreCut_5", 0.5f, "Minimum score value for selecting good matches"}; + std::array*, sChi2FunctionsNum> fMatchingScoreCut{ + &fMatchingScoreCut_1, &fMatchingScoreCut_2, &fMatchingScoreCut_3, &fMatchingScoreCut_4, &fMatchingScoreCut_5}; + + Configurable fMatchingPlaneZ_1{"cfgChi2FunctionMatchingPlaneZ_1", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_2{"cfgChi2FunctionMatchingPlaneZ_2", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_3{"cfgChi2FunctionMatchingPlaneZ_3", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_4{"cfgChi2FunctionMatchingPlaneZ_4", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_5{"cfgChi2FunctionMatchingPlaneZ_5", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}; + std::array*, sChi2FunctionsNum> fMatchingPlaneZ{ + &fMatchingPlaneZ_1, &fMatchingPlaneZ_2, &fMatchingPlaneZ_3, &fMatchingPlaneZ_4, &fMatchingPlaneZ_5}; + + Configurable fMatchingExtrapMethod_1{"cfgChi2MatchingExtrapMethod_1", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_2{"cfgChi2MatchingExtrapMethod_2", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_3{"cfgChi2MatchingExtrapMethod_3", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_4{"cfgChi2MatchingExtrapMethod_4", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_5{"cfgChi2MatchingExtrapMethod_5", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + std::array*, sChi2FunctionsNum> fMatchingExtrapMethod{ + &fMatchingExtrapMethod_1, &fMatchingExtrapMethod_2, &fMatchingExtrapMethod_3, &fMatchingExtrapMethod_4, &fMatchingExtrapMethod_5}; } fConfigChi2MatchingOptions; // ML interface - static constexpr int sMLModelsNum = 2; + static constexpr int sMLModelsNum = 5; struct : ConfigurableGroup { - std::array, sMLModelsNum> fModelLabel{{ - {"cfgMLModelLabel_0", std::string{""}, "Text label identifying this group of ML models"}, - {"cfgMLModelLabel_1", std::string{""}, "Text label identifying this group of ML models"}, - }}; - std::array>, sMLModelsNum> fModelPathsCCDB{{{"cfgMLModelPathsCCDB_0", std::vector{"Users/m/mcoquet/MLTest"}, "Paths of models on CCDB"}, - {"cfgMLModelPathsCCDB_1", std::vector{}, "Paths of models on CCDB"}}}; - std::array>, sMLModelsNum> fInputFeatures{{{"cfgMLInputFeatures_0", std::vector{"chi2MCHMFT"}, "Names of ML model input features"}, - {"cfgMLInputFeatures_1", std::vector{}, "Names of ML model input features"}}}; - std::array>, sMLModelsNum> fModelNames{{{"cfgMLModelNames_0", std::vector{"model.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}, - {"cfgMLModelNames_1", std::vector{}, "ONNX file names for each pT bin (if not from CCDB full path)"}}}; - std::array, sMLModelsNum> fMatchingScoreCut{{ - {"cfgMLModelMatchingScoreCut_0", 0.f, "Minimum score value for selecting good matches"}, - {"cfgMLModelMatchingScoreCut_1", 0.f, "Minimum score value for selecting good matches"}, - }}; - std::array, sMLModelsNum> fMatchingPlaneZ{{ - {"cfgMLModelMatchingPlaneZ_0", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, - {"cfgMLModelMatchingPlaneZ_1", 0.f, "Z position of the matching plane"}, - }}; - std::array, sMLModelsNum> fMatchingExtrapMethod{{ - {"cfgMatchingExtrapMethod_0", static_cast(0), "Method for MCH track extrapolation to maching plane"}, - {"cfgMatchingExtrapMethod_1", static_cast(0), "Method for MCH track extrapolation to maching plane"}, - }}; + Configurable fModelLabel_1{"cfgMLModelLabel_1", std::string{""}, "Text label identifying this group of ML models"}; + Configurable fModelLabel_2{"cfgMLModelLabel_2", std::string{""}, "Text label identifying this group of ML models"}; + Configurable fModelLabel_3{"cfgMLModelLabel_3", std::string{""}, "Text label identifying this group of ML models"}; + Configurable fModelLabel_4{"cfgMLModelLabel_4", std::string{""}, "Text label identifying this group of ML models"}; + Configurable fModelLabel_5{"cfgMLModelLabel_5", std::string{""}, "Text label identifying this group of ML models"}; + std::array*, sMLModelsNum> fModelLabel{ + &fModelLabel_1, &fModelLabel_2, &fModelLabel_3, &fModelLabel_4, &fModelLabel_5}; + + Configurable fModelPathCCDB_1{"cfgMLModelPathCCDB_1", "Users/m/mcoquet/MLTest", "Paths of models on CCDB"}; + Configurable fModelPathCCDB_2{"cfgMLModelPathsCCDB_2", std::string{""}, "Paths of models on CCDB"}; + Configurable fModelPathCCDB_3{"cfgMLModelPathsCCDB_3", std::string{""}, "Paths of models on CCDB"}; + Configurable fModelPathCCDB_4{"cfgMLModelPathsCCDB_4", std::string{""}, "Paths of models on CCDB"}; + Configurable fModelPathCCDB_5{"cfgMLModelPathsCCDB_5", std::string{""}, "Paths of models on CCDB"}; + std::array*, sMLModelsNum> fModelPathCCDB{ + &fModelPathCCDB_1, &fModelPathCCDB_2, &fModelPathCCDB_3, &fModelPathCCDB_4, &fModelPathCCDB_5}; + + Configurable fModelName_1{"cfgMLModelName_1", "model.onnx", "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable fModelName_2{"cfgMLModelNames_2", std::string{""}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable fModelName_3{"cfgMLModelNames_3", std::string{""}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable fModelName_4{"cfgMLModelNames_4", std::string{""}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable fModelName_5{"cfgMLModelNames_5", std::string{""}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + std::array*, sMLModelsNum> fModelName{ + &fModelName_1, &fModelName_2, &fModelName_3, &fModelName_4, &fModelName_5}; + + Configurable fInputFeatures_1{"cfgMLInputFeatures_1", "chi2MCHMFT", "Names of ML model input features"}; + Configurable fInputFeatures_2{"cfgMLInputFeatures_2", std::string{""}, "Names of ML model input features"}; + Configurable fInputFeatures_3{"cfgMLInputFeatures_3", std::string{""}, "Names of ML model input features"}; + Configurable fInputFeatures_4{"cfgMLInputFeatures_4", std::string{""}, "Names of ML model input features"}; + Configurable fInputFeatures_5{"cfgMLInputFeatures_5", std::string{""}, "Names of ML model input features"}; + std::array*, sMLModelsNum> fInputFeatures{ + &fInputFeatures_1, &fInputFeatures_2, &fInputFeatures_3, &fInputFeatures_4, &fInputFeatures_5}; + + Configurable fMatchingScoreCut_1{"cfgMLModelMatchingScoreCut_1", 0.f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_2{"cfgMLModelMatchingScoreCut_2", 0.f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_3{"cfgMLModelMatchingScoreCut_3", 0.f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_4{"cfgMLModelMatchingScoreCut_4", 0.f, "Minimum score value for selecting good matches"}; + Configurable fMatchingScoreCut_5{"cfgMLModelMatchingScoreCut_5", 0.f, "Minimum score value for selecting good matches"}; + std::array*, sMLModelsNum> fMatchingScoreCut{ + &fMatchingScoreCut_1, &fMatchingScoreCut_2, &fMatchingScoreCut_3, &fMatchingScoreCut_4, &fMatchingScoreCut_5}; + + Configurable fMatchingPlaneZ_1{"cfgMLModelMatchingPlaneZ_1", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_2{"cfgMLModelMatchingPlaneZ_2", 0.f, "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_3{"cfgMLModelMatchingPlaneZ_3", 0.f, "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_4{"cfgMLModelMatchingPlaneZ_4", 0.f, "Z position of the matching plane"}; + Configurable fMatchingPlaneZ_5{"cfgMLModelMatchingPlaneZ_5", 0.f, "Z position of the matching plane"}; + std::array*, sMLModelsNum> fMatchingPlaneZ{ + &fMatchingPlaneZ_1, &fMatchingPlaneZ_2, &fMatchingPlaneZ_3, &fMatchingPlaneZ_4, &fMatchingPlaneZ_5}; + + Configurable fMatchingExtrapMethod_1{"cfgMLMatchingExtrapMethod_1", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_2{"cfgMLMatchingExtrapMethod_2", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_3{"cfgMLMatchingExtrapMethod_3", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_4{"cfgMLMatchingExtrapMethod_4", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + Configurable fMatchingExtrapMethod_5{"cfgMLMatchingExtrapMethod_5", static_cast(0), "Method for MCH track extrapolation to maching plane"}; + std::array*, sMLModelsNum> fMatchingExtrapMethod{ + &fMatchingExtrapMethod_1, &fMatchingExtrapMethod_2, &fMatchingExtrapMethod_3, &fMatchingExtrapMethod_4, &fMatchingExtrapMethod_5}; } fConfigMlOptions; std::vector binsPtMl; @@ -442,6 +492,7 @@ struct qaMatching { o2::framework::HistPtr histVsPt; o2::framework::HistPtr histVsMcParticleDz; o2::framework::HistPtr histVsMftTrackMult; + o2::framework::HistPtr histVsMatchAttempts; o2::framework::HistPtr histVsMftTrackType; o2::framework::HistPtr histVsDeltaChi2; o2::framework::HistPtr histVsProdRanking; @@ -450,8 +501,9 @@ struct qaMatching { { AxisSpec pAxis = {100, 0, 100, "p (GeV/c)"}; AxisSpec ptAxis = {100, 0, 10, "p_{T} (GeV/c)"}; - AxisSpec dzAxis = {100, 0, 50, "#Deltaz (cm)"}; + AxisSpec dzAxis = {100, -1, 4, "#Deltaz (cm)"}; AxisSpec trackMultAxis = {static_cast(mftMultMax) / 10, 0, static_cast(mftMultMax), "MFT track mult."}; + AxisSpec matchAttemptsAxis = {static_cast(mftMultMax) / 10, 0, static_cast(mftMultMax), "match attempts"}; AxisSpec trackTypeAxis = {2, 0, 2, "MFT track type"}; int matchTypeMax = static_cast(kMatchTypeUndefined); AxisSpec matchTypeAxis = {matchTypeMax, 0, static_cast(matchTypeMax), "match type"}; @@ -465,6 +517,7 @@ struct qaMatching { histVsPt = registry->add((histName + "VsPt").c_str(), (histTitle + " vs. p_{T}").c_str(), {HistType::kTH2F, {ptAxis, indexAxis}}); histVsMcParticleDz = registry->add((histName + "VsMcParticleDz").c_str(), (histTitle + " vs. MC particle #Deltaz").c_str(), {HistType::kTH2F, {dzAxis, indexAxis}}); histVsMftTrackMult = registry->add((histName + "VsMftTrackMult").c_str(), (histTitle + " vs. MFT track multiplicity").c_str(), {HistType::kTH2F, {trackMultAxis, indexAxis}}); + histVsMatchAttempts = registry->add((histName + "VsMatchAttempts").c_str(), (histTitle + " vs. MFT track multiplicity").c_str(), {HistType::kTH2F, {matchAttemptsAxis, indexAxis}}); histVsMftTrackType = registry->add((histName + "VsMftTrackType").c_str(), (histTitle + " vs. MFT track type").c_str(), {HistType::kTH2F, {trackTypeAxis, indexAxis}}); std::get>(histVsMftTrackType)->GetXaxis()->SetBinLabel(1, "Kalman"); std::get>(histVsMftTrackType)->GetXaxis()->SetBinLabel(2, "CA"); @@ -928,11 +981,11 @@ struct qaMatching { // Matching functions InitMatchingFunctions(); for (size_t funcId = 0; funcId < sChi2FunctionsNum; funcId++) { - auto label = fConfigChi2MatchingOptions.fFunctionLabel[funcId].value; - auto funcName = fConfigChi2MatchingOptions.fFunctionName[funcId].value; - auto scoreMin = fConfigChi2MatchingOptions.fMatchingScoreCut[funcId].value; - auto matchingPlaneZ = fConfigChi2MatchingOptions.fMatchingPlaneZ[funcId].value; - auto extrapMethod = fConfigChi2MatchingOptions.fMatchingExtrapMethod[funcId].value; + auto label = fConfigChi2MatchingOptions.fFunctionLabel[funcId]->value; + auto funcName = fConfigChi2MatchingOptions.fFunctionName[funcId]->value; + auto scoreMin = fConfigChi2MatchingOptions.fMatchingScoreCut[funcId]->value; + auto matchingPlaneZ = fConfigChi2MatchingOptions.fMatchingPlaneZ[funcId]->value; + auto extrapMethod = fConfigChi2MatchingOptions.fMatchingExtrapMethod[funcId]->value; if (label == "" || funcName == "") break; @@ -952,20 +1005,20 @@ struct qaMatching { o2::framework::LabeledArray mycutsMl(cutValues.data(), 1, 1, std::vector{"pT bin 0"}, std::vector{"score"}); for (size_t modelId = 0; modelId < sMLModelsNum; modelId++) { - auto label = fConfigMlOptions.fModelLabel[modelId].value; - auto modelPaths = fConfigMlOptions.fModelPathsCCDB[modelId].value; - auto inputFeatures = fConfigMlOptions.fInputFeatures[modelId].value; - auto modelNames = fConfigMlOptions.fModelNames[modelId].value; - auto scoreMin = fConfigMlOptions.fMatchingScoreCut[modelId].value; - auto matchingPlaneZ = fConfigMlOptions.fMatchingPlaneZ[modelId].value; - auto extrapMethod = fConfigMlOptions.fMatchingExtrapMethod[modelId].value; - - if (label == "" || modelPaths.empty() || inputFeatures.empty() || modelNames.empty()) + auto label = fConfigMlOptions.fModelLabel[modelId]->value; + auto modelPath = fConfigMlOptions.fModelPathCCDB[modelId]->value; + auto inputFeatures = fConfigMlOptions.fInputFeatures[modelId]->value; + auto modelName = fConfigMlOptions.fModelName[modelId]->value; + auto scoreMin = fConfigMlOptions.fMatchingScoreCut[modelId]->value; + auto matchingPlaneZ = fConfigMlOptions.fMatchingPlaneZ[modelId]->value; + auto extrapMethod = fConfigMlOptions.fMatchingExtrapMethod[modelId]->value; + + if (label == "" || modelPath == "" || inputFeatures == "" || modelName == "") break; matchingMlResponses[label].configure(binsPtMl, mycutsMl, cutDirMl, 1); - matchingMlResponses[label].setModelPathsCCDB(modelNames, fCCDBApi, modelPaths, fConfigCCDB.fConfigNoLaterThan.value); - matchingMlResponses[label].cacheInputFeaturesIndices(inputFeatures); + matchingMlResponses[label].setModelPathsCCDB(std::vector{modelName}, fCCDBApi, std::vector{modelPath}, fConfigCCDB.fConfigNoLaterThan.value); + matchingMlResponses[label].cacheInputFeaturesIndices(std::vector{inputFeatures}); matchingMlResponses[label].init(); matchingScoreCuts[label] = scoreMin; @@ -1757,6 +1810,41 @@ struct qaMatching { return dimuon.M(); } + template + int GetMftMchMatchAttempts(EVT const& collisions, + BC const& bcs, + TMUON const& mchTrack, + TMFTS const& mftTracks) + { + if (!mchTrack.has_collision()) { + return 0; + } + const auto& collMch = collisions.rawIteratorAt(mchTrack.collisionId()); + const auto& bcMch = bcs.rawIteratorAt(collMch.bcId()); + + int attempts{0}; + for (const auto& mftTrack : mftTracks) { + if (!mftTrack.has_collision()) { + continue; + } + + const auto& collMft = collisions.rawIteratorAt(mftTrack.collisionId()); + const auto& bcMft = bcs.rawIteratorAt(collMft.bcId()); + + int64_t deltaBc = static_cast(bcMft.globalBC()) - static_cast(bcMch.globalBC()); + double deltaBcNS = o2::constants::lhc::LHCBunchSpacingNS * deltaBc; + double deltaTrackTime = mftTrack.trackTime() - mchTrack.trackTime() + deltaBcNS; + double trackTimeResTot = mftTrack.trackTimeRes() + mchTrack.trackTimeRes(); + + if (std::fabs(deltaTrackTime) > trackTimeResTot) { + continue; + } + attempts += 1; + } + + return attempts; + } + template void FillCollisions(EVT const& collisions, BC const& bcs, @@ -1838,6 +1926,7 @@ struct qaMatching { matchScore, matchChi2, -1, + 0, kMatchTypeUndefined}); } else { collisionInfo.matchingCandidates[mchTrackIndex].emplace_back(MatchingCandidate{ @@ -1851,6 +1940,7 @@ struct qaMatching { matchScore, matchChi2, -1, + 0, kMatchTypeUndefined}); } } @@ -1885,6 +1975,8 @@ struct qaMatching { for (auto& [mchIndex, globalTracksVector] : collisionInfo.matchingCandidates) { std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareMatchingScore); + const auto& mchTrack = muonTracks.rawIteratorAt(mchIndex); + auto mftMchMatchAttempts = GetMftMchMatchAttempts(collisions, bcs, mchTrack, mftTracks); int ranking = 1; for (auto& candidate : globalTracksVector) { const auto& muonTrack = muonTracks.rawIteratorAt(candidate.globalTrackId); @@ -1892,6 +1984,7 @@ struct qaMatching { candidate.matchRanking = ranking; candidate.matchRankingProd = ranking; candidate.matchType = GetMatchType(muonTrack, muonTracks, mftTracks, collisionInfo.matchablePairs, ranking); + candidate.mftMchMatchAttempts = mftMchMatchAttempts; ranking += 1; } } @@ -1950,11 +2043,14 @@ struct qaMatching { mcParticleDz = collision.posZ() - mchMcParticle.vz(); } + int matchAttempts = globalTracksVector[0].mftMchMatchAttempts; + std::get>(plotter->fMatchRanking->hist)->Fill(trueMatchIndex); std::get>(plotter->fMatchRanking->histVsP)->Fill(mchMom, trueMatchIndex); std::get>(plotter->fMatchRanking->histVsPt)->Fill(mchPt, trueMatchIndex); std::get>(plotter->fMatchRanking->histVsMcParticleDz)->Fill(mcParticleDz, trueMatchIndex); std::get>(plotter->fMatchRanking->histVsMftTrackMult)->Fill(mftTrackMult, trueMatchIndex); + std::get>(plotter->fMatchRanking->histVsMatchAttempts)->Fill(matchAttempts, trueMatchIndex); std::get>(plotter->fMatchRanking->histVsMftTrackType)->Fill(mftTrackType, trueMatchIndex); std::get>(plotter->fMatchRanking->histVsProdRanking)->Fill(trueMatchIndexProd, trueMatchIndex); if (dchi2 >= 0) @@ -1966,6 +2062,7 @@ struct qaMatching { std::get>(plotter->fMatchRankingGoodMCH->histVsPt)->Fill(mchPt, trueMatchIndex); std::get>(plotter->fMatchRankingGoodMCH->histVsMcParticleDz)->Fill(mcParticleDz, trueMatchIndex); std::get>(plotter->fMatchRankingGoodMCH->histVsMftTrackMult)->Fill(mftTrackMult, trueMatchIndex); + std::get>(plotter->fMatchRankingGoodMCH->histVsMatchAttempts)->Fill(matchAttempts, trueMatchIndex); std::get>(plotter->fMatchRankingGoodMCH->histVsMftTrackType)->Fill(mftTrackType, trueMatchIndex); std::get>(plotter->fMatchRankingGoodMCH->histVsProdRanking)->Fill(trueMatchIndexProd, trueMatchIndex); if (dchi2 >= 0) @@ -1978,6 +2075,7 @@ struct qaMatching { std::get>(plotter->fMatchRankingPaired->histVsPt)->Fill(mchPt, trueMatchIndex); std::get>(plotter->fMatchRankingPaired->histVsMcParticleDz)->Fill(mcParticleDz, trueMatchIndex); std::get>(plotter->fMatchRankingPaired->histVsMftTrackMult)->Fill(mftTrackMult, trueMatchIndex); + std::get>(plotter->fMatchRankingPaired->histVsMatchAttempts)->Fill(matchAttempts, trueMatchIndex); std::get>(plotter->fMatchRankingPaired->histVsMftTrackType)->Fill(mftTrackType, trueMatchIndex); std::get>(plotter->fMatchRankingPaired->histVsProdRanking)->Fill(trueMatchIndexProd, trueMatchIndex); if (dchi2 >= 0) @@ -1990,6 +2088,7 @@ struct qaMatching { std::get>(plotter->fMatchRankingPairedGoodMCH->histVsPt)->Fill(mchPt, trueMatchIndex); std::get>(plotter->fMatchRankingPairedGoodMCH->histVsMcParticleDz)->Fill(mcParticleDz, trueMatchIndex); std::get>(plotter->fMatchRankingPairedGoodMCH->histVsMftTrackMult)->Fill(mftTrackMult, trueMatchIndex); + std::get>(plotter->fMatchRankingPairedGoodMCH->histVsMatchAttempts)->Fill(matchAttempts, trueMatchIndex); std::get>(plotter->fMatchRankingPairedGoodMCH->histVsMftTrackType)->Fill(mftTrackType, trueMatchIndex); std::get>(plotter->fMatchRankingPairedGoodMCH->histVsProdRanking)->Fill(trueMatchIndexProd, trueMatchIndex); if (dchi2 >= 0) @@ -2311,8 +2410,9 @@ struct qaMatching { } } - template + template void RunChi2Matching(C const& collisions, + BC const& bcs, TMUON const& muonTracks, TMFT const& mftTracks, CMFT const& mftCovs, @@ -2410,19 +2510,23 @@ struct qaMatching { for (auto& [mchIndex, globalTracksVector] : newMatchingCandidates) { std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareMatchingScore); + const auto& mchTrack = muonTracks.rawIteratorAt(mchIndex); + auto mftMchMatchAttempts = GetMftMchMatchAttempts(collisions, bcs, mchTrack, mftTracks); int ranking = 1; for (auto& candidate : globalTracksVector) { const auto& muonTrack = muonTracks.rawIteratorAt(candidate.globalTrackId); candidate.matchRanking = ranking; candidate.matchType = GetMatchType(muonTrack, muonTracks, mftTracks, matchablePairs, ranking); + candidate.mftMchMatchAttempts = mftMchMatchAttempts; ranking += 1; } } } - template + template void RunChi2Matching(C const& collisions, + BC const& bcs, TMUON const& muonTracks, TMFT const& mftTracks, CMFT const& mftCovs, @@ -2451,11 +2555,12 @@ struct qaMatching { auto matchingPlaneZ = matchingPlanesZ[label]; auto extrapMethod = matchingExtrapMethod[label]; - RunChi2Matching(collisions, muonTracks, mftTracks, mftCovs, funcName, matchingPlaneZ, extrapMethod, matchablePairs, matchingCandidates, newMatchingCandidates); + RunChi2Matching(collisions, bcs, muonTracks, mftTracks, mftCovs, funcName, matchingPlaneZ, extrapMethod, matchablePairs, matchingCandidates, newMatchingCandidates); } - template + template void RunMLMatching(C const& collisions, + BC const& bcs, TMUON const& muonTracks, TMFT const& mftTracks, CMFT const& mftCovs, @@ -2550,20 +2655,24 @@ struct qaMatching { for (auto& [mchIndex, globalTracksVector] : newMatchingCandidates) { std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareMatchingScore); + const auto& mchTrack = muonTracks.rawIteratorAt(mchIndex); + auto mftMchMatchAttempts = GetMftMchMatchAttempts(collisions, bcs, mchTrack, mftTracks); int ranking = 1; for (auto& candidate : globalTracksVector) { const auto& muonTrack = muonTracks.rawIteratorAt(candidate.globalTrackId); candidate.matchRanking = ranking; candidate.matchType = GetMatchType(muonTrack, muonTracks, mftTracks, matchablePairs, ranking); + candidate.mftMchMatchAttempts = mftMchMatchAttempts; ranking += 1; } } } - template + template void ProcessCollisionMC(const CollisionInfo& collisionInfo, C const& collisions, + BC const& bcs, TMUON const& muonTracks, TMFT const& mftTracks, CMFT const& mftCovs) @@ -2577,7 +2686,7 @@ struct qaMatching { FillMatchingPlotsMC(collision, collisionInfo, muonTracks, mftTracks, collisionInfo.matchingCandidates, collisionInfo.matchingCandidates, collisionInfo.matchablePairs, fMatchingChi2ScoreMftMchLow, fChi2MatchingPlotter.get(), false); for (auto& [label, func] : matchingChi2Functions) { MatchingCandidates matchingCandidates; - RunChi2Matching(collisions, muonTracks, mftTracks, mftCovs, label, collisionInfo.matchablePairs, collisionInfo.matchingCandidates, matchingCandidates); + RunChi2Matching(collisions, bcs, muonTracks, mftTracks, mftCovs, label, collisionInfo.matchablePairs, collisionInfo.matchingCandidates, matchingCandidates); auto* plotter = fMatchingPlotters.at(label).get(); double matchingScoreCut = matchingScoreCuts.at(label); @@ -2588,7 +2697,7 @@ struct qaMatching { // ML-based matching analysis for (auto& [label, mlResponse] : matchingMlResponses) { MatchingCandidates matchingCandidates; - RunMLMatching(collisions, muonTracks, mftTracks, mftCovs, label, collisionInfo.matchablePairs, collisionInfo.matchingCandidates, matchingCandidates); + RunMLMatching(collisions, bcs, muonTracks, mftTracks, mftCovs, label, collisionInfo.matchablePairs, collisionInfo.matchingCandidates, matchingCandidates); auto* plotter = fMatchingPlotters.at(label).get(); double matchingScoreCut = matchingScoreCuts.at(label); @@ -2668,7 +2777,7 @@ struct qaMatching { } for (auto const& [collisionIndex, collisionInfo] : fCollisionInfos) { - ProcessCollisionMC(collisionInfo, collisions, muonTracks, mftTracks, mftCovs); + ProcessCollisionMC(collisionInfo, collisions, bcs, muonTracks, mftTracks, mftCovs); } } diff --git a/PWGDQ/Tasks/tableReader.cxx b/PWGDQ/Tasks/tableReader.cxx index a4126dc5f74..fdb1c4c0d6f 100644 --- a/PWGDQ/Tasks/tableReader.cxx +++ b/PWGDQ/Tasks/tableReader.cxx @@ -163,6 +163,7 @@ struct AnalysisEventSelection { OutputObj fOutputList{"output"}; // TODO: Provide the mixing variables and binning directly via configurables (e.g. vectors of float) Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro [WARNING: under debug, do not enable!]"}; @@ -200,12 +201,18 @@ struct AnalysisEventSelection { } TString mixVarsString = fConfigMixingVariables.value; + TString mixVarsJsonString = fConfigMixingVariablesJson.value; std::unique_ptr objArray(mixVarsString.Tokenize(",")); - if (objArray->GetEntries() > 0) { + if (objArray->GetEntries() > 0 || mixVarsJsonString != "") { fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); fMixHandler->Init(); - for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { - dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + if (objArray->GetEntries() > 0) { + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + } + } + if (mixVarsJsonString != "") { + dqmixing::SetUpMixingFromJSON(fMixHandler, mixVarsJsonString.Data()); } } diff --git a/PWGDQ/Tasks/tableReader_withAssoc.cxx b/PWGDQ/Tasks/tableReader_withAssoc.cxx index 2b112f3c15d..5a71f06bbce 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.cxx @@ -195,6 +195,7 @@ DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", dqanalysisflags::Ma // Declarations of various short names using MyEvents = soa::Join; +using MyEventsBasic = soa::Join; using MyEventsMultExtra = soa::Join; using MyEventsMultExtraQVector = soa::Join; using MyEventsZdc = soa::Join; @@ -276,6 +277,7 @@ struct AnalysisEventSelection { // TODO: Provide the mixing variables and binning directly via configurables (e.g. vectors of float) Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; @@ -307,7 +309,7 @@ struct AnalysisEventSelection { void init(o2::framework::InitContext& context) { - bool isAnyProcessEnabled = context.mOptions.get("processSkimmed") || context.mOptions.get("processSkimmedWithZdc") || context.mOptions.get("processSkimmedWithMultExtra") || context.mOptions.get("processSkimmedWithMultExtraZdc") || context.mOptions.get("processSkimmedWithMultExtraZdcFit") || context.mOptions.get("processSkimmedWithQvectorCentr"); + bool isAnyProcessEnabled = context.mOptions.get("processSkimmed") || context.mOptions.get("processSkimmedBasic") || context.mOptions.get("processSkimmedWithZdc") || context.mOptions.get("processSkimmedWithMultExtra") || context.mOptions.get("processSkimmedWithMultExtraZdc") || context.mOptions.get("processSkimmedWithMultExtraZdcFit") || context.mOptions.get("processSkimmedWithQvectorCentr"); bool isDummyEnabled = context.mOptions.get("processDummy"); if (isDummyEnabled) { @@ -356,12 +358,18 @@ struct AnalysisEventSelection { } TString mixVarsString = fConfigMixingVariables.value; + TString mixVarsJsonString = fConfigMixingVariablesJson.value; std::unique_ptr objArray(mixVarsString.Tokenize(",")); - if (objArray->GetEntries() > 0) { + if (objArray->GetEntries() > 0 || mixVarsJsonString != "") { fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); fMixHandler->Init(); - for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { - dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + if (objArray->GetEntries() > 0) { + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + } + } + if (mixVarsJsonString != "") { + dqmixing::SetUpMixingFromJSON(fMixHandler, mixVarsJsonString.Data()); } } @@ -528,6 +536,11 @@ struct AnalysisEventSelection { runEventSelection(events); publishSelections(events); } + void processSkimmedBasic(MyEventsBasic const& events) + { + runEventSelection(events); + publishSelections(events); + } void processSkimmedWithZdc(MyEventsZdc const& events) { runEventSelection(events); @@ -553,12 +566,13 @@ struct AnalysisEventSelection { runEventSelection(events); publishSelections(events); } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedBasic, "Run event selection on DQ skimmed events with basic tables", false); PROCESS_SWITCH(AnalysisEventSelection, processSkimmedWithZdc, "Run event selection on DQ skimmed events, with ZDC", false); PROCESS_SWITCH(AnalysisEventSelection, processSkimmedWithMultExtra, "Run event selection on DQ skimmed events, with mult extra", false); PROCESS_SWITCH(AnalysisEventSelection, processSkimmedWithMultExtraZdc, "Run event selection on DQ skimmed events, with mult extra and ZDC", false); @@ -814,7 +828,7 @@ struct AnalysisTrackSelection { { runTrackSelection(assocs, events, tracks); } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } @@ -1025,7 +1039,7 @@ struct AnalysisMuonSelection { { runMuonSelection(assocs, events, muons); } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } @@ -1174,7 +1188,7 @@ struct AnalysisPrefilterSelection { } // end loop over combinations } - void processBarrelSkimmed(MyEvents const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) + void processBarrelSkimmed(MyEventsBasic const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) { fPrefilterMap.clear(); @@ -1207,7 +1221,7 @@ struct AnalysisPrefilterSelection { } } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } @@ -1312,6 +1326,7 @@ struct AnalysisSameEventPairing { int fNCutsBarrel; int fNCutsMuon; int fNPairCuts; + int fNPairPerEvent; bool fEnableBarrelMixingHistos; bool fEnableBarrelHistos; @@ -1627,6 +1642,12 @@ struct AnalysisSameEventPairing { fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); VarManager::SetCollisionSystem((TString)fConfigOptions.collisionSystem, fConfigOptions.centerMassEnergy); // set collision system and center of mass energy DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram.value.data()); // define all histograms + if (fEnableBarrelHistos) { + DefineHistograms(fHistMan, "PairingSEQA", "sameevent-pairing"); // histograms for QA of the pairing + }; + if (fEnableBarrelMixingHistos) { + DefineHistograms(fHistMan, "PairingMEQA", "mixedevent-pairing"); // histograms for QA of the pairing + }; dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); @@ -1735,6 +1756,7 @@ struct AnalysisSameEventPairing { constexpr bool eventHasQvectorCentr = ((TEventFillMap & VarManager::ObjTypes::CollisionQvect) > 0); constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::TrackCov) > 0 || (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); bool isSelectedBDT = false; + fNPairPerEvent = 0; for (auto& event : events) { if (!event.isEventSelected_bit(0)) { @@ -1782,6 +1804,7 @@ struct AnalysisSameEventPairing { twoTrackFilter |= (static_cast(1) << 31); } + fNPairPerEvent++; VarManager::FillPair(t1, t2); // compute quantities which depend on the associated collision, such as DCA if (fConfigOptions.propTrack) { @@ -2087,6 +2110,10 @@ struct AnalysisSameEventPairing { } } // end loop (cuts) } // end loop over pairs of track associations + VarManager::fgValues[VarManager::kNPairsPerEvent] = fNPairPerEvent; + if (fEnableBarrelHistos && fConfigQA) { + fHistMan->FillHistClass("PairingSEQA", VarManager::fgValues); + } } // end loop over events } @@ -2106,6 +2133,7 @@ struct AnalysisSameEventPairing { } auto t1 = a1.template reducedtrack_as(); auto t2 = a2.template reducedtrack_as(); + fNPairPerEvent++; VarManager::FillPairME(t1, t2); if constexpr ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0) { VarManager::FillPairVn(t1, t2); @@ -2271,7 +2299,12 @@ struct AnalysisSameEventPairing { auto assocs2 = assocs.sliceBy(preSlice, event2.globalIndex()); assocs2.bindExternalIndices(&events); + fNPairPerEvent = 0; runMixedPairing(assocs1, assocs2, tracks, tracks); + VarManager::fgValues[VarManager::kNPairsPerEvent] = fNPairPerEvent; + if (fEnableBarrelMixingHistos && fConfigQA) { + fHistMan->FillHistClass("PairingMEQA", VarManager::fgValues); + } } // end event loop } @@ -2500,7 +2533,7 @@ struct AnalysisSameEventPairing { runSameSideMixing(events, muonAssocs, muons, muonAssocsPerCollision); } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } @@ -3246,7 +3279,7 @@ struct AnalysisAsymmetricPairing { runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, VarManager::kTripleCandidateToPKPi); } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } @@ -3602,7 +3635,7 @@ struct AnalysisDileptonTrack { } // dilepton rap cut float rap = dilepton.rap(); - if (fConfigUseRapcut && abs(rap) > fConfigDileptonRapCutAbs) + if (fConfigUseRapcut && std::abs(rap) > fConfigDileptonRapCutAbs) continue; VarManager::FillTrack(dilepton, fValuesDilepton); @@ -3660,7 +3693,7 @@ struct AnalysisDileptonTrack { // for the energy correlator analysis std::vector fTransRange = fConfigTransRange; - VarManager::FillEnergyCorrelator(dilepton, track, fValuesHadron, fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom()); + VarManager::FillEnergyCorrelatorTriple(lepton1, lepton2, track, fValuesHadron, fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom()); // table to be written out for ML analysis BmesonsTable(event.runNumber(), event.globalIndex(), event.timestamp(), fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], fValuesHadron[VarManager::kPairEta], fValuesHadron[VarManager::kPairPhi], fValuesHadron[VarManager::kPairRap], @@ -3817,7 +3850,7 @@ struct AnalysisDileptonTrack { void processBarrelMixedEvent(soa::Filtered& events, soa::Filtered> const& assocs, - MyBarrelTracksWithCov const&, soa::Filtered const& dileptons) + MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons) { if (events.size() == 0) { return; @@ -3853,10 +3886,16 @@ struct AnalysisDileptonTrack { // loop over dileptons for (auto dilepton : evDileptons) { - + // get full track info of tracks based on the index + auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); + auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); + // Check that the dilepton has zero charge + if (dilepton.sign() != 0) { + continue; + } // dilepton rap cut float rap = dilepton.rap(); - if (fConfigUseRapcut && abs(rap) > fConfigDileptonRapCutAbs) + if (fConfigUseRapcut && std::abs(rap) > fConfigDileptonRapCutAbs) continue; // compute dilepton - track quantities @@ -3864,7 +3903,7 @@ struct AnalysisDileptonTrack { // for the energy correlator analysis std::vector fTransRange = fConfigTransRange; - VarManager::FillEnergyCorrelator(dilepton, track, VarManager::fgValues, fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom()); + VarManager::FillEnergyCorrelatorTriple(lepton1, lepton2, track, fValuesHadron, fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom()); // loop over dilepton leg cuts and track cuts and fill histograms separately for each combination for (int icut = 0; icut < fNCuts; icut++) { @@ -3930,7 +3969,7 @@ struct AnalysisDileptonTrack { } // end event loop } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } @@ -4185,7 +4224,7 @@ struct AnalysisDileptonTrackTrack { } } - void processDummy(MyEvents&) + void processDummy(MyEventsBasic&) { // do nothing } @@ -4254,6 +4293,10 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); } + if (classStr.Contains("Pairing")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); + } + if (classStr.Contains("Triplets")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); } diff --git a/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx b/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx index 49e0d596d50..1cdf8f65336 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx @@ -250,6 +250,7 @@ struct AnalysisEventSelection { OutputObj fOutputList{"output"}; OutputObj fStatsList{"Statistics"}; Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; @@ -368,12 +369,18 @@ struct AnalysisEventSelection { fStatsList->AddAt(histZorroSel, kStatsZorroSel); TString mixVarsString = fConfigMixingVariables.value; + TString mixVarsJsonString = fConfigMixingVariablesJson.value; std::unique_ptr objArray(mixVarsString.Tokenize(",")); - if (objArray->GetEntries() > 0) { + if (objArray->GetEntries() > 0 || mixVarsJsonString != "") { fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); fMixHandler->Init(); - for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { - dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + if (objArray->GetEntries() > 0) { + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + } + } + if (mixVarsJsonString != "") { + dqmixing::SetUpMixingFromJSON(fMixHandler, mixVarsJsonString.Data()); } } diff --git a/PWGEM/Dilepton/Core/DielectronCut.cxx b/PWGEM/Dilepton/Core/DielectronCut.cxx index b5ecd733985..85172723058 100644 --- a/PWGEM/Dilepton/Core/DielectronCut.cxx +++ b/PWGEM/Dilepton/Core/DielectronCut.cxx @@ -356,3 +356,8 @@ void DielectronCut::IncludeITSsa(bool flag, float max) mMaxPtITSsa = max; LOG(info) << "Dielectron Cut, include ITSsa tracks: " << mIncludeITSsa << ", mMaxPtITSsa = " << mMaxPtITSsa; } +void DielectronCut::EnableTTCA(bool flag) +{ + mEnableTTCA = flag; + LOG(info) << "Dielectron Cut, enable TTCA: " << mEnableTTCA; +} diff --git a/PWGEM/Dilepton/Core/DielectronCut.h b/PWGEM/Dilepton/Core/DielectronCut.h index 5c629c3f45d..b9179122279 100644 --- a/PWGEM/Dilepton/Core/DielectronCut.h +++ b/PWGEM/Dilepton/Core/DielectronCut.h @@ -17,7 +17,6 @@ #define PWGEM_DILEPTON_CORE_DIELECTRONCUT_H_ #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "CommonConstants/PhysicsConstants.h" @@ -67,6 +66,7 @@ class DielectronCut : public TNamed kITSNCls, kITSChi2NDF, kITSClusterSize, + kTTCA, kPrefilter, kNCuts }; @@ -210,6 +210,9 @@ class DielectronCut : public TNamed if (!IsSelectedTrack(track, DielectronCuts::kITSClusterSize)) { return false; } + if (!IsSelectedTrack(track, DielectronCuts::kTTCA)) { + return false; + } if (mRequireITSibAny) { auto hits_ib = std::count_if(its_ib_any_Requirement.second.begin(), its_ib_any_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); @@ -225,34 +228,35 @@ class DielectronCut : public TNamed } } - // if (!mIncludeITSsa && (!track.hasITS() || !track.hasTPC())) { // track has to be ITS-TPC matched track - // return false; - // } + if (!mIncludeITSsa && (!track.hasITS() || !track.hasTPC())) { // track has to be ITS-TPC matched track + return false; + } // if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && track.pt() > mMaxPtITSsa) { // ITSsa // return false; // } // TPC cuts - if (!IsSelectedTrack(track, DielectronCuts::kTPCNCls)) { - return false; - } - if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRows)) { - return false; - } - if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRowsOverNCls)) { - return false; - } - if (!IsSelectedTrack(track, DielectronCuts::kTPCFracSharedClusters)) { - return false; - } - if (!IsSelectedTrack(track, DielectronCuts::kRelDiffPin)) { - return false; - } - if (!IsSelectedTrack(track, DielectronCuts::kTPCChi2NDF)) { - return false; + if (track.hasTPC()) { + if (!IsSelectedTrack(track, DielectronCuts::kTPCNCls)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRows)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRowsOverNCls)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCFracSharedClusters)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kRelDiffPin)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCChi2NDF)) { + return false; + } } - if (mApplyPF && !IsSelectedTrack(track, DielectronCuts::kPrefilter)) { return false; } @@ -412,6 +416,7 @@ class DielectronCut : public TNamed case DielectronCuts::kTrackPhiPositionRange: { float phiPosition = track.phi() + std::asin(-0.30282 * track.sign() * (mBz * 0.1) * mRefR / (2.f * track.pt())); + phiPosition = RecoDecay::constrainAngle(phiPosition, 0, 1U); // 0-2pi if (mMinTrackPhiPosition < 0.f && mMaxTrackPhiPosition < M_PI) { // threshold across 0 rad. o2::math_utils::bringToPMPi(phiPosition); @@ -469,6 +474,9 @@ class DielectronCut : public TNamed case DielectronCuts::kITSClusterSize: return mMinMeanClusterSizeITS < track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS; + case DielectronCuts::kTTCA: + return mEnableTTCA ? true : track.isAssociatedToMPC(); + case DielectronCuts::kPrefilter: return track.pfb() <= 0; @@ -537,11 +545,12 @@ class DielectronCut : public TNamed void ApplyPrefilter(bool flag); void ApplyPhiV(bool flag); void IncludeITSsa(bool flag, float maxpt); + void EnableTTCA(bool flag); - void SetPIDMlResponse(o2::analysis::MlResponseDielectronSingleTrack* mlResponse) - { - mPIDMlResponse = mlResponse; - } + // void SetPIDMlResponse(o2::analysis::MlResponseDielectronSingleTrack* mlResponse) + // { + // mPIDMlResponse = mlResponse; + // } void SetMLThresholds(const std::vector bins, const std::vector cuts) { @@ -609,7 +618,7 @@ class DielectronCut : public TNamed float mMinMeanClusterSizeITS{0.0}, mMaxMeanClusterSizeITS{1e10f}; // x cos(lmabda) // float mMinP_ITSClusterSize{0.0}, mMaxP_ITSClusterSize{0.0}; bool mIncludeITSsa{false}; - float mMaxPtITSsa{0.15}; + float mMaxPtITSsa{1e+10}; // pid cuts int mPIDScheme{-1}; @@ -627,6 +636,7 @@ class DielectronCut : public TNamed float mMinTOFNsigmaPi{-1e+10}, mMaxTOFNsigmaPi{+1e+10}; float mMinTOFNsigmaKa{-1e+10}, mMaxTOFNsigmaKa{+1e+10}; float mMinTOFNsigmaPr{-1e+10}, mMaxTOFNsigmaPr{+1e+10}; + bool mEnableTTCA{true}; // float mMinITSNsigmaEl{-1e+10}, mMaxITSNsigmaEl{+1e+10}; // float mMinITSNsigmaMu{-1e+10}, mMaxITSNsigmaMu{+1e+10}; @@ -636,7 +646,7 @@ class DielectronCut : public TNamed // float mMinP_ITSNsigmaKa{0.0}, mMaxP_ITSNsigmaKa{0.0}; // float mMinP_ITSNsigmaPr{0.0}, mMaxP_ITSNsigmaPr{0.0}; - o2::analysis::MlResponseDielectronSingleTrack* mPIDMlResponse{nullptr}; + // o2::analysis::MlResponseDielectronSingleTrack* mPIDMlResponse{nullptr}; std::vector mMLBins{}; // binning for a feature variable. e.g. tpcInnerParam std::vector mMLCuts{}; // threshold for each bin. mMLCuts.size() must be mMLBins.size()-1. diff --git a/PWGEM/Dilepton/Core/Dilepton.h b/PWGEM/Dilepton/Core/Dilepton.h index 9291314d00c..5238c549445 100644 --- a/PWGEM/Dilepton/Core/Dilepton.h +++ b/PWGEM/Dilepton/Core/Dilepton.h @@ -26,14 +26,11 @@ #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" #include "PWGEM/Dilepton/Utils/EventHistograms.h" #include "PWGEM/Dilepton/Utils/EventMixingHandler.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/Zorro.h" -#include "Common/Core/trackUtilities.h" -#include "Tools/ML/MlResponse.h" #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" @@ -58,6 +55,7 @@ #include #include #include +#include #include #include @@ -78,7 +76,7 @@ using MyElectron = MyElectrons::iterator; using FilteredMyElectrons = soa::Filtered; using FilteredMyElectron = FilteredMyElectrons::iterator; -using MyMuons = soa::Join; +using MyMuons = soa::Join; using MyMuon = MyMuons::iterator; using FilteredMyMuons = soa::Filtered; using FilteredMyMuon = FilteredMyMuons::iterator; @@ -186,12 +184,12 @@ struct Dilepton { Configurable cfg_min_dphi{"cfg_min_dphi", 0.2, "min dphi between 2 electrons (elliptic cut)"}; Configurable cfg_min_opang{"cfg_min_opang", 0.0, "min opening angle"}; Configurable cfg_max_opang{"cfg_max_opang", 6.4, "max opening angle"}; - Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; + // Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; Configurable cfg_apply_cuts_from_prefilter{"cfg_apply_cuts_from_prefilter", false, "flag to apply prefilter set when producing derived data"}; Configurable cfg_prefilter_bits{"cfg_prefilter_bits", 0, "prefilter bits [kNone : 0, kElFromPC : 1, kElFromPi0_20MeV : 2, kElFromPi0_40MeV : 4, kElFromPi0_60MeV : 8, kElFromPi0_80MeV : 16, kElFromPi0_100MeV : 32, kElFromPi0_120MeV : 64, kElFromPi0_140MeV : 128] Please consider logical-OR among them."}; // see PairUtilities.h - Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply pair cut same as prefilter set in derived data"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter set in derived data"}; Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kMee : 1, kPhiV : 2, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; @@ -215,8 +213,8 @@ struct Dilepton { Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; - Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; - Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + // Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + // Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; Configurable cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; @@ -241,8 +239,8 @@ struct Dilepton { // configuration for PID ML Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; - Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; - Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20.f}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.98, 0.98, 0.9, 0.9, 0.95, 0.95, 0.8, 0.8}, "ML cuts per bin"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; @@ -265,6 +263,9 @@ struct Dilepton { Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 muons (elliptic cut)"}; Configurable cfg_min_dphi{"cfg_min_dphi", 0.02, "min dphi between 2 muons (elliptic cut)"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter set in derived data"}; + Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; @@ -276,7 +277,10 @@ struct Dilepton { Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; - Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + // Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_border_pt_for_chi2mchmft{"cfg_border_pt_for_chi2mchmft", 0, "border pt for different max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mftmch_lowPt{"cfg_max_matching_chi2_mftmch_lowPt", 8, "max chi2 for MFT-MCH matching for low pT"}; + Configurable cfg_max_matching_chi2_mftmch_highPt{"cfg_max_matching_chi2_mftmch_highPt", 40, "max chi2 for MFT-MCH matching for high pT"}; Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; @@ -588,7 +592,7 @@ struct Dilepton { if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { fRegistry.add("Pair/same/uls/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2D, {{90, 0, M_PI}, {100, 0.0f, 1.0f}}, true); // phiv is only for dielectron fRegistry.add("Pair/same/uls/hMvsOpAng", "m_{ee} vs. angle between 2 tracks;#omega (rad.);m_{ee} (GeV/c^{2})", kTH2D, {{90, 0, M_PI}, {100, 0.0f, 1.0f}}, true); - fRegistry.add("Pair/same/uls/hDCA1vsDCA2", "DCA of leg1 vs. DCA of leg2;DCA1(#sigma);DCA2 (#sigma)", kTH2D, {{100, 0, 10.0}, {100, 0, 10}}, true); + fRegistry.add("Pair/same/uls/hDCA1vsDCA2", "DCA of leg1 vs. DCA of leg2;DCA1(#sigma);DCA2 (#sigma)", kTH2D, {{200, -10, 10.0}, {200, -10, 10}}, true); } fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); @@ -694,7 +698,6 @@ struct Dilepton { fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); } - o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -708,7 +711,7 @@ struct Dilepton { fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); fDielectronCut.SetMindEtadPhi(dielectroncuts.cfg_apply_detadphi, false, dielectroncuts.cfg_min_deta, dielectroncuts.cfg_min_dphi); fDielectronCut.SetPairOpAng(dielectroncuts.cfg_min_opang, dielectroncuts.cfg_max_opang); - fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); + // fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); // for track fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); @@ -727,7 +730,8 @@ struct Dilepton { fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); fDielectronCut.SetChi2TOF(0, dielectroncuts.cfg_max_chi2tof); - fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + // fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + fDielectronCut.EnableTTCA(dielectroncuts.enableTTCA); // for eID fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); @@ -751,31 +755,6 @@ struct Dilepton { thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); } fDielectronCut.SetMLThresholds(binsML, thresholdsML); - - // static constexpr int nClassesMl = 2; - // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; - // const std::vector labelsClasses = {"Background", "Signal"}; - // const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; - // const std::vector labelsBins(nBinsMl, "bin"); - // double cutsMlArr[nBinsMl][nClassesMl]; - // for (uint32_t i = 0; i < nBinsMl; i++) { - // cutsMlArr[i][0] = 0.; - // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; - // } - // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; - - // mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); - // if (dielectroncuts.loadModelsFromCCDB) { - // ccdbApi.init(ccdburl); - // mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); - // } else { - // mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); - // } - // mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); - // mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); - // mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); - - // fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); } // end of PID ML } @@ -799,13 +778,15 @@ struct Dilepton { fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); - fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + // fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMaxMatchingChi2MCHMFTPtDep([&](float pt) { return (pt < dimuoncuts.cfg_border_pt_for_chi2mchmft ? dimuoncuts.cfg_max_matching_chi2_mftmch_lowPt : dimuoncuts.cfg_max_matching_chi2_mftmch_highPt); }); fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + fDimuonCut.EnableTTCA(dimuoncuts.enableTTCA); } template @@ -847,7 +828,7 @@ struct Dilepton { } template - bool fillPairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks) + bool fillPairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const&) { if constexpr (ev_id == 0) { if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { @@ -864,13 +845,16 @@ struct Dilepton { if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; } - - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { - return false; - } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + if (!map_best_match_globalmuon[t1.globalIndex()] || !map_best_match_globalmuon[t2.globalIndex()]) { return false; } + + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + // return false; + // } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + // return false; + // } } } @@ -1111,9 +1095,9 @@ struct Dilepton { used_trackIds_per_col.emplace_back(t1.globalIndex()); if (cfgDoMix) { if (t1.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXX(), t1.cXY(), t1.cYY())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXX(), t1.cXY(), t1.cYY())); } } } @@ -1121,9 +1105,9 @@ struct Dilepton { used_trackIds_per_col.emplace_back(t2.globalIndex()); if (cfgDoMix) { if (t2.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXX(), t2.cXY(), t2.cYY())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXX(), t2.cXY(), t2.cYY())); } } } @@ -1142,7 +1126,7 @@ struct Dilepton { Preslice perCollision_electron = aod::emprimaryelectron::emeventId; Filter trackFilter_electron = dielectroncuts.cfg_min_pt_track < o2::aod::track::pt && dielectroncuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < dielectroncuts.cfg_max_eta_track && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc; Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; - Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), true, o2::aod::emprimaryelectron::isAssociatedToMPC == true); Filter prefilter_derived_electron = ifnode(dielectroncuts.cfg_apply_cuts_from_prefilter_derived.node() && dielectroncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) <= static_cast(0), true) && ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) <= static_cast(0), true) && @@ -1166,7 +1150,12 @@ struct Dilepton { Preslice perCollision_muon = aod::emprimarymuon::emeventId; Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_pt_track < o2::aod::fwdtrack::pt && o2::aod::fwdtrack::pt < dimuoncuts.cfg_max_pt_track && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track; - Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), true, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter prefilter_derived_muon = ifnode(dimuoncuts.cfg_apply_cuts_from_prefilter_derived.node() && dimuoncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) <= static_cast(0), true) && + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) <= static_cast(0), true), + o2::aod::emprimarymuon::pfbderived >= static_cast(0)); + Partition positive_muons = o2::aod::emprimarymuon::sign > int8_t(0); Partition negative_muons = o2::aod::emprimarymuon::sign < int8_t(0); @@ -1174,6 +1163,7 @@ struct Dilepton { TEMH* emh_neg = nullptr; std::map, uint64_t> map_mixed_eventId_to_globalBC; + std::unordered_map map_best_match_globalmuon; std::vector used_trackIds_per_col; int ndf = 0; @@ -1408,7 +1398,7 @@ struct Dilepton { } // end of DF template - bool isPairOK(TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks) + bool isPairOK(TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const&) { if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { @@ -1424,13 +1414,16 @@ struct Dilepton { if (!cut.IsSelectedTrack(t1) || !cut.IsSelectedTrack(t2)) { return false; } - - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { - return false; - } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + if (!map_best_match_globalmuon[t1.globalIndex()] || !map_best_match_globalmuon[t2.globalIndex()]) { return false; } + + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + // return false; + // } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + // return false; + // } } if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { @@ -1563,12 +1556,14 @@ struct Dilepton { runPairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons); } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { auto muons = std::get<0>(std::tie(args...)); + map_best_match_globalmuon = findBestMatchMap(muons, fDimuonCut); if (cfgApplyWeightTTCA) { fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); } runPairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); } map_weight.clear(); + map_best_match_globalmuon.clear(); ndf++; } PROCESS_SWITCH(Dilepton, processAnalysis, "run dilepton analysis", true); @@ -1583,12 +1578,14 @@ struct Dilepton { runPairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons); } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { auto muons = std::get<0>(std::tie(args...)); + map_best_match_globalmuon = findBestMatchMap(muons, fDimuonCut); if (cfgApplyWeightTTCA) { fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); } runPairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); } map_weight.clear(); + map_best_match_globalmuon.clear(); ndf++; } PROCESS_SWITCH(Dilepton, processTriggerAnalysis, "run dilepton analysis on triggered data", false); diff --git a/PWGEM/Dilepton/Core/DileptonHadronMPC.h b/PWGEM/Dilepton/Core/DileptonHadronMPC.h index 77823486157..56b2c837cc8 100644 --- a/PWGEM/Dilepton/Core/DileptonHadronMPC.h +++ b/PWGEM/Dilepton/Core/DileptonHadronMPC.h @@ -27,14 +27,11 @@ #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" #include "PWGEM/Dilepton/Utils/EventHistograms.h" #include "PWGEM/Dilepton/Utils/EventMixingHandler.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/Zorro.h" -#include "Common/Core/trackUtilities.h" -#include "Tools/ML/MlResponse.h" #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" @@ -71,7 +68,7 @@ using namespace o2::aod::pwgem::dilepton::utils; using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; using namespace o2::aod::pwgem::dilepton::utils::pairutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyElectrons = soa::Join; @@ -79,7 +76,7 @@ using MyElectron = MyElectrons::iterator; using FilteredMyElectrons = soa::Filtered; using FilteredMyElectron = FilteredMyElectrons::iterator; -using MyMuons = soa::Join; +using MyMuons = soa::Join; using MyMuon = MyMuons::iterator; using FilteredMyMuons = soa::Filtered; using FilteredMyMuon = FilteredMyMuons::iterator; @@ -99,6 +96,7 @@ struct DileptonHadronMPC { Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; Configurable cfgAnalysisType{"cfgAnalysisType", static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kAzimuthalCorrelation), "kAzimuthalCorrelation:0, kCumulant:1"}; + Configurable cfgEP2Estimator_for_Mix{"cfgEP2Estimator_for_Mix", 3, "FT0M:0, FT0A:1, FT0C:2, BTot:3, BPos:4, BNeg:5, FV0A:6"}; Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; @@ -107,6 +105,7 @@ struct DileptonHadronMPC { Configurable ndiff_bc_mix{"ndiff_bc_mix", 594, "difference in global BC required in mixed events"}; ConfigurableAxis ConfVtxBins{"ConfVtxBins", {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 ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f, 999.f}, "Mixing bins - centrality"}; + ConfigurableAxis ConfEPBins{"ConfEPBins", {16, -M_PI / 2, +M_PI / 2}, "Mixing bins - event plane angle"}; ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; Configurable cfg_swt_name{"cfg_swt_name", "fHighTrackMult", "desired software trigger name"}; // 1 trigger name per 1 task. fHighTrackMult, fHighFt0Mult // Configurable cfgNtracksPV08Min{"cfgNtracksPV08Min", -1, "min. multNTracksPV"}; @@ -118,9 +117,7 @@ struct DileptonHadronMPC { ConfigurableAxis ConfPtllBins{"ConfPtllBins", {VARIABLE_WIDTH, 0.00, 0.15, 0.50, 1.00, 1.50, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pTll bins for output histograms"}; ConfigurableAxis ConfDCAllBins{"ConfDCAllBins", {VARIABLE_WIDTH, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "DCAll bins for output histograms"}; - // ConfigurableAxis ConfMmumuBins{"ConfMmumuBins", {VARIABLE_WIDTH, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.75, 2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15, 3.20, 3.25, 3.30, 3.35, 3.40, 3.45, 3.50, 3.55, 3.60, 3.65, 3.70, 3.75, 3.80, 3.85, 3.90, 3.95, 4.00, 4.10, 4.20, 4.30, 4.40, 4.50, 4.60, 4.70, 4.80, 4.90, 5.00, 5.10, 5.20, 5.30, 5.40, 5.50, 5.60, 5.70, 5.80, 5.90, 6.00, 6.10, 6.20, 6.30, 6.40, 6.50, 6.60, 6.70, 6.80, 6.90, 7.00, 7.10, 7.20, 7.30, 7.40, 7.50, 7.60, 7.70, 7.80, 7.90, 8.00, 8.10, 8.20, 8.30, 8.40, 8.50, 8.60, 8.70, 8.80, 8.90, 9.00, 9.10, 9.20, 9.30, 9.40, 9.50, 9.60, 9.70, 9.80, 9.90, 10.00, 10.10, 10.20, 10.30, 10.40, 10.50, 10.60, 10.70, 10.80, 10.90, 11.00, 11.50, 12.00}, "mmumu bins for output histograms"}; // for dimuon. one can copy bins here to hyperloop page. - - ConfigurableAxis ConfPtHadronBins{"ConfPtHadronBins", {VARIABLE_WIDTH, 0.00, 0.15, 0.2, 0.3, 0.4, 0.50, 1.00, 2.00, 3.00, 4.00, 5.00}, "pT,h bins for output histograms"}; + ConfigurableAxis ConfPtHadronBins{"ConfPtHadronBins", {50, 0, 5}, "pT,h bins for output histograms"}; ConfigurableAxis ConfYllBins{"ConfYllBins", {1, -1.f, 1.f}, "yll bins for output histograms"}; // pair rapidity ConfigurableAxis ConfDEtaBins{"ConfDEtaBins", {120, -6, 6}, "deta bins for output histograms"}; Configurable cfgNbinsDPhi{"cfgNbinsDPhi", 36, "nbins in dphi for output histograms"}; @@ -208,7 +205,7 @@ struct DileptonHadronMPC { Configurable cfg_max_dcaz{"cfg_max_dcaz", 1.0, "max dca Z for single track in cm"}; Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; - Configurable cfgRefR{"cfgRefR", 1.2, "reference R (in m) for extrapolation"}; // https://cds.cern.ch/record/1419204 + Configurable cfgRefR{"cfgRefR", 0.5, "reference R (in m) for extrapolation"}; // https://cds.cern.ch/record/1419204 Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif : 4, kPIDML : 5, kTPChadrejORTOFreq_woTOFif : 6]"}; Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; @@ -228,8 +225,8 @@ struct DileptonHadronMPC { // configuration for PID ML Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; - Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; - Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20.f}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.98, 0.98, 0.9, 0.9, 0.95, 0.95, 0.8, 0.8}, "ML cuts per bin"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; @@ -252,6 +249,9 @@ struct DileptonHadronMPC { Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 muons (elliptic cut)"}; Configurable cfg_min_dphi{"cfg_min_dphi", 0.02, "min dphi between 2 muons (elliptic cut)"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter set in derived data"}; + Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; @@ -263,7 +263,10 @@ struct DileptonHadronMPC { Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 8, "min ncluster MCH"}; Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; - Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + // Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_border_pt_for_chi2mchmft{"cfg_border_pt_for_chi2mchmft", 0, "border pt for different max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mftmch_lowPt{"cfg_max_matching_chi2_mftmch_lowPt", 8, "max chi2 for MFT-MCH matching for low pT"}; + Configurable cfg_max_matching_chi2_mftmch_highPt{"cfg_max_matching_chi2_mftmch_highPt", 40, "max chi2 for MFT-MCH matching for high pT"}; Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; @@ -311,10 +314,8 @@ struct DileptonHadronMPC { std::vector cent_bin_edges; std::vector zvtx_bin_edges; + std::vector ep_bin_edges; std::vector occ_bin_edges; - int nmod = -1; // this is for flow analysis - int subdet2 = -1; // this is for flow analysis - int subdet3 = -1; // this is for flow analysis float leptonM1 = 0.f; float leptonM2 = 0.f; @@ -363,6 +364,23 @@ struct DileptonHadronMPC { } } + if (ConfEPBins.value[0] == VARIABLE_WIDTH) { + ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); + ep_bin_edges.erase(ep_bin_edges.begin()); + for (const auto& edge : ep_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: ep_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfEPBins.value[0]); + float xmin = static_cast(ConfEPBins.value[1]); + float xmax = static_cast(ConfEPBins.value[2]); + ep_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + ep_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: ep_bin_edges[%d] = %f", i, ep_bin_edges[i]); + } + } + LOGF(info, "cfgOccupancyEstimator = %d", cfgOccupancyEstimator.value); if (ConfOccupancyBins.value[0] == VARIABLE_WIDTH) { occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); @@ -475,6 +493,7 @@ struct DileptonHadronMPC { void addhistograms() { + static constexpr std::string_view qvec_det_names[7] = {"FT0M", "FT0A", "FT0C", "BTot", "BPos", "BNeg", "FV0A"}; // event info o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<-1>(&fRegistry); @@ -519,7 +538,7 @@ struct DileptonHadronMPC { const AxisSpec axis_deta{ConfDEtaBins, deta_axis_title}; // hadron-hadron info - const AxisSpec axis_deta_hh{60, -3, +3, "#Delta#eta = #eta_{h}^{ref1} - #eta_{h}^{ref2}"}; + const AxisSpec axis_deta_hh{40, -2, +2, "#Delta#eta = #eta_{h}^{ref1} - #eta_{h}^{ref2}"}; const AxisSpec axis_pt_trg{ConfPtHadronBins, "p_{T,h} (GeV/c)"}; const AxisSpec axis_eta_trg{40, -2, +2, "#eta_{h}"}; @@ -559,6 +578,9 @@ struct DileptonHadronMPC { fRegistry.add("HadronHadron/same/hDEtaCosNDPhi", "hadron-hadron 2PC", kTH2D, {axis_cosndphi_hh, axis_deta_hh}, true); } fRegistry.add("Dilepton/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); + + fRegistry.add("Event/before/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + fRegistry.add("Event/after/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); } void DefineEMEventCut() @@ -583,7 +605,6 @@ struct DileptonHadronMPC { fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); } - o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -616,8 +637,8 @@ struct DileptonHadronMPC { fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); fDielectronCut.SetChi2TOF(0, dielectroncuts.cfg_max_chi2tof); - fDielectronCut.SetRelDiffPin(-1e+10, +1e+10); - fDielectronCut.IncludeITSsa(false, 0.15); + // fDielectronCut.SetRelDiffPin(-1e+10, +1e+10); + fDielectronCut.EnableTTCA(dielectroncuts.enableTTCA); // for eID fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); @@ -640,31 +661,6 @@ struct DileptonHadronMPC { thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); } fDielectronCut.SetMLThresholds(binsML, thresholdsML); - - // static constexpr int nClassesMl = 2; - // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; - // const std::vector labelsClasses = {"Background", "Signal"}; - // const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; - // const std::vector labelsBins(nBinsMl, "bin"); - // double cutsMlArr[nBinsMl][nClassesMl]; - // for (uint32_t i = 0; i < nBinsMl; i++) { - // cutsMlArr[i][0] = 0.; - // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; - // } - // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; - - // mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); - // if (dielectroncuts.loadModelsFromCCDB) { - // ccdbApi.init(ccdburl); - // mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); - // } else { - // mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); - // } - // mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); - // mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); - // mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); - - // fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); } // end of PID ML } @@ -688,13 +684,15 @@ struct DileptonHadronMPC { fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); - fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + // fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMaxMatchingChi2MCHMFTPtDep([&](float pt) { return (pt < dimuoncuts.cfg_border_pt_for_chi2mchmft ? dimuoncuts.cfg_max_matching_chi2_mftmch_lowPt : dimuoncuts.cfg_max_matching_chi2_mftmch_highPt); }); fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + fDimuonCut.EnableTTCA(dimuoncuts.enableTTCA); } void DefineEMTrackCut() @@ -807,9 +805,9 @@ struct DileptonHadronMPC { used_trackIds_per_col.emplace_back(t1.globalIndex()); if (cfgDoMix) { if (t1.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXX(), t1.cXY(), t1.cYY())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXX(), t1.cXY(), t1.cYY())); } } } @@ -817,9 +815,9 @@ struct DileptonHadronMPC { used_trackIds_per_col.emplace_back(t2.globalIndex()); if (cfgDoMix) { if (t2.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXX(), t2.cXY(), t2.cYY())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXX(), t2.cXY(), t2.cYY())); } } } @@ -844,9 +842,9 @@ struct DileptonHadronMPC { return false; } } - if (t1.trackId() == t3.trackId() || t2.trackId() == t3.trackId()) { - return false; - } + // if (t1.trackId() == t3.trackId() || t2.trackId() == t3.trackId()) { + // return false; + // } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; @@ -947,9 +945,9 @@ struct DileptonHadronMPC { continue; } } - if (t1.trackId() == pos.trackId() || t2.trackId() == pos.trackId()) { - return false; - } + // if (t1.trackId() == pos.trackId() || t2.trackId() == pos.trackId()) { + // return false; + // } } // end of pos lepton loop for (const auto& neg : negLeptons) { // leptons per collision @@ -962,9 +960,9 @@ struct DileptonHadronMPC { continue; } } - if (t1.trackId() == neg.trackId() || t2.trackId() == neg.trackId()) { - return false; - } + // if (t1.trackId() == neg.trackId() || t2.trackId() == neg.trackId()) { + // return false; + // } } // end of neg lepton lopp } // end of if kDielectron @@ -1018,7 +1016,12 @@ struct DileptonHadronMPC { Preslice perCollision_muon = aod::emprimarymuon::emeventId; Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_pt_track < o2::aod::fwdtrack::pt && o2::aod::fwdtrack::pt < dimuoncuts.cfg_max_pt_track && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track && dimuoncuts.cfg_min_phi_track < o2::aod::fwdtrack::phi && o2::aod::fwdtrack::phi < dimuoncuts.cfg_max_phi_track; - Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), true, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter prefilter_derived_muon = ifnode(dimuoncuts.cfg_apply_cuts_from_prefilter_derived.node() && dimuoncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) <= static_cast(0), true) && + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) <= static_cast(0), true), + o2::aod::emprimarymuon::pfbderived >= static_cast(0)); + Partition positive_muons = o2::aod::emprimarymuon::sign > int8_t(0); Partition negative_muons = o2::aod::emprimarymuon::sign < int8_t(0); @@ -1048,8 +1051,13 @@ struct DileptonHadronMPC { continue; } + const float eventplanes_2_for_mix[7] = {collision.ep2ft0m(), collision.ep2ft0a(), collision.ep2ft0c(), collision.ep2btot(), collision.ep2bpos(), collision.ep2bneg(), collision.ep2fv0a()}; + float ep2 = eventplanes_2_for_mix[cfgEP2Estimator_for_Mix]; + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, -1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + if (!fEMEventCut.IsSelected(collision)) { continue; } @@ -1066,6 +1074,7 @@ struct DileptonHadronMPC { o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, -1>(&fRegistry, collision); fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); auto refTracks_per_coll = refTracks.sliceBy(perCollision_track, collision.globalIndex()); @@ -1143,7 +1152,12 @@ struct DileptonHadronMPC { centbin = static_cast(cent_bin_edges.size()) - 2; } - int epbin = 0; + int epbin = lower_bound(ep_bin_edges.begin(), ep_bin_edges.end(), ep2) - ep_bin_edges.begin() - 1; + if (epbin < 0) { + epbin = 0; + } else if (static_cast(ep_bin_edges.size()) - 2 < epbin) { + epbin = static_cast(ep_bin_edges.size()) - 2; + } int occbin = -1; if (cfgOccupancyEstimator == 0) { diff --git a/PWGEM/Dilepton/Core/DileptonMC.h b/PWGEM/Dilepton/Core/DileptonMC.h index b20a9be3820..0c00de8bec5 100644 --- a/PWGEM/Dilepton/Core/DileptonMC.h +++ b/PWGEM/Dilepton/Core/DileptonMC.h @@ -24,13 +24,10 @@ #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" #include "PWGEM/Dilepton/Utils/EventHistograms.h" #include "PWGEM/Dilepton/Utils/MCUtilities.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "Tools/ML/MlResponse.h" #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" @@ -52,6 +49,7 @@ #include #include #include +#include #include #include @@ -75,7 +73,7 @@ using MyMCElectron = MyMCElectrons::iterator; using FilteredMyMCElectrons = soa::Filtered; using FilteredMyMCElectron = FilteredMyMCElectrons::iterator; -using MyMCMuons = soa::Join; +using MyMCMuons = soa::Join; using MyMCMuon = MyMCMuons::iterator; using FilteredMyMCMuons = soa::Filtered; using FilteredMyMCMuon = FilteredMyMCMuons::iterator; @@ -188,7 +186,7 @@ struct DileptonMC { Configurable cfg_min_dphi{"cfg_min_dphi", 0.2, "min dphi between 2 electrons (elliptic cut)"}; Configurable cfg_min_opang{"cfg_min_opang", 0.0, "min opening angle"}; Configurable cfg_max_opang{"cfg_max_opang", 6.4, "max opening angle"}; - Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; + // Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; Configurable cfg_apply_cuts_from_prefilter{"cfg_apply_cuts_from_prefilter", false, "flag to apply prefilter set when producing derived data"}; Configurable cfg_prefilter_bits{"cfg_prefilter_bits", 0, "prefilter bits [kNone : 0, kElFromPC : 1, kElFromPi0_20MeV : 2, kElFromPi0_40MeV : 4, kElFromPi0_60MeV : 8, kElFromPi0_80MeV : 16, kElFromPi0_100MeV : 32, kElFromPi0_120MeV : 64, kElFromPi0_140MeV : 128] Please consider logical-OR among them."}; // see PairUtilities.h @@ -217,8 +215,8 @@ struct DileptonMC { Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; - Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; - Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + // Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + // Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; Configurable cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; @@ -243,8 +241,8 @@ struct DileptonMC { // configuration for PID ML Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; - Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; - Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20.f}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.98, 0.98, 0.9, 0.9, 0.95, 0.95, 0.8, 0.8}, "ML cuts per bin"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; @@ -267,6 +265,9 @@ struct DileptonMC { Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 muons (elliptic cut)"}; Configurable cfg_min_dphi{"cfg_min_dphi", 0.02, "min dphi between 2 muons (elliptic cut)"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter set in derived data"}; + Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; @@ -278,7 +279,10 @@ struct DileptonMC { Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; - Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + // Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_border_pt_for_chi2mchmft{"cfg_border_pt_for_chi2mchmft", 0, "border pt for different max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mftmch_lowPt{"cfg_max_matching_chi2_mftmch_lowPt", 8, "max chi2 for MFT-MCH matching for low pT"}; + Configurable cfg_max_matching_chi2_mftmch_highPt{"cfg_max_matching_chi2_mftmch_highPt", 40, "max chi2 for MFT-MCH matching for high pT"}; Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; @@ -289,7 +293,8 @@ struct DileptonMC { Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; - Configurable rejectWrongMatch{"rejectWrongMatch", false, "flag to reject wrong match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. + Configurable acceptOnlyCorrectMatch{"acceptOnlyCorrectMatch", false, "flag to accept only correct match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. + Configurable acceptOnlyWrongMatch{"acceptOnlyWrongMatch", false, "flag to accept only wrong match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. } dimuoncuts; o2::aod::rctsel::RCTFlagsChecker rctChecker; @@ -701,7 +706,6 @@ struct DileptonMC { fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); } - o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -715,7 +719,7 @@ struct DileptonMC { fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); fDielectronCut.SetMindEtadPhi(dielectroncuts.cfg_apply_detadphi, false, dielectroncuts.cfg_min_deta, dielectroncuts.cfg_min_dphi); fDielectronCut.SetPairOpAng(dielectroncuts.cfg_min_opang, dielectroncuts.cfg_max_opang); - fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); + // fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); // for track fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); @@ -734,7 +738,8 @@ struct DileptonMC { fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); - fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + // fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + fDielectronCut.EnableTTCA(dielectroncuts.enableTTCA); // for eID fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); @@ -758,31 +763,6 @@ struct DileptonMC { thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); } fDielectronCut.SetMLThresholds(binsML, thresholdsML); - - // static constexpr int nClassesMl = 2; - // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; - // const std::vector labelsClasses = {"Background", "Signal"}; - // const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; - // const std::vector labelsBins(nBinsMl, "bin"); - // double cutsMlArr[nBinsMl][nClassesMl]; - // for (uint32_t i = 0; i < nBinsMl; i++) { - // cutsMlArr[i][0] = 0.; - // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; - // } - // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; - - // mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); - // if (dielectroncuts.loadModelsFromCCDB) { - // ccdbApi.init(ccdburl); - // mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); - // } else { - // mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); - // } - // mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); - // mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); - // mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); - - // fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); } // end of PID ML } @@ -806,13 +786,15 @@ struct DileptonMC { fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); - fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + // fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMaxMatchingChi2MCHMFTPtDep([&](float pt) { return (pt < dimuoncuts.cfg_border_pt_for_chi2mchmft ? dimuoncuts.cfg_max_matching_chi2_mftmch_lowPt : dimuoncuts.cfg_max_matching_chi2_mftmch_highPt); }); fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + fDimuonCut.EnableTTCA(dimuoncuts.enableTTCA); } template @@ -1391,7 +1373,7 @@ struct DileptonMC { } template - bool fillTruePairInfo(TCollision const& collision, TMCCollisions const&, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks, TMCParticles const& mcparticles) + bool fillTruePairInfo(TCollision const& collision, TMCCollisions const&, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const&, TMCParticles const& mcparticles) { auto t1mc = mcparticles.iteratorAt(t1.emmcparticleId()); auto t2mc = mcparticles.iteratorAt(t2.emmcparticleId()); @@ -1426,14 +1408,17 @@ struct DileptonMC { if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; } - - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + if (!map_best_match_globalmuon[t1.globalIndex()] || !map_best_match_globalmuon[t2.globalIndex()]) { return false; } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { - return false; - } - if (dimuoncuts.rejectWrongMatch) { + + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + // return false; + // } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + // return false; + // } + if (dimuoncuts.acceptOnlyCorrectMatch) { if (t1.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && t1.emmcparticleId() != t1.emmftmcparticleId()) { return false; } @@ -1441,6 +1426,14 @@ struct DileptonMC { return false; } } + if (dimuoncuts.acceptOnlyWrongMatch) { // reject correctly matched MFT-MCH-MID for bkg estimation + if (t1.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && t1.emmcparticleId() == t1.emmftmcparticleId()) { + return false; + } + if (t2.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && t2.emmcparticleId() == t2.emmftmcparticleId()) { + return false; + } + } if (!cut.IsSelectedPair(t1, t2)) { return false; @@ -2132,7 +2125,7 @@ struct DileptonMC { } template - bool isPairOK(TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks) + bool isPairOK(TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const&) { if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { @@ -2148,12 +2141,15 @@ struct DileptonMC { if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { - return false; - } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + if (!map_best_match_globalmuon[t1.globalIndex()] || !map_best_match_globalmuon[t2.globalIndex()]) { return false; } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + // return false; + // } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + // return false; + // } } if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { @@ -2479,11 +2475,13 @@ struct DileptonMC { } // end of collision loop } + std::unordered_map map_best_match_globalmuon; + SliceCache cache; Preslice perCollision_electron = aod::emprimaryelectron::emeventId; Filter trackFilter_electron = nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc; Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; - Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), true, o2::aod::emprimaryelectron::isAssociatedToMPC == true); Filter prefilter_derived_electron = ifnode(dielectroncuts.cfg_apply_cuts_from_prefilter_derived.node() && dielectroncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) <= static_cast(0), true) && ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) <= static_cast(0), true) && @@ -2504,7 +2502,11 @@ struct DileptonMC { Preslice perCollision_muon = aod::emprimarymuon::emeventId; Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type; - Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), true, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter prefilter_derived_muon = ifnode(dimuoncuts.cfg_apply_cuts_from_prefilter_derived.node() && dimuoncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) <= static_cast(0), true) && + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) <= static_cast(0), true), + o2::aod::emprimarymuon::pfbderived >= static_cast(0)); Filter collisionFilter_centrality = (eventcuts.cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcuts.cfgCentMax); Filter collisionFilter_numContrib = eventcuts.cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < eventcuts.cfgNumContribMax; @@ -2538,6 +2540,7 @@ struct DileptonMC { fillUnfolding(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles); } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + map_best_match_globalmuon = findBestMatchMap(leptons, fDimuonCut); if (cfgApplyWeightTTCA) { fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles); } @@ -2548,6 +2551,7 @@ struct DileptonMC { } } map_weight.clear(); + map_best_match_globalmuon.clear(); } PROCESS_SWITCH(DileptonMC, processAnalysis, "run dilepton mc analysis", true); @@ -2569,6 +2573,7 @@ struct DileptonMC { fillUnfolding(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles_smeared); } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + map_best_match_globalmuon = findBestMatchMap(leptons, fDimuonCut); if (cfgApplyWeightTTCA) { fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles_smeared); } @@ -2579,6 +2584,7 @@ struct DileptonMC { } } map_weight.clear(); + map_best_match_globalmuon.clear(); } PROCESS_SWITCH(DileptonMC, processAnalysis_Smeared, "run dilepton mc analysis with smearing", false); diff --git a/PWGEM/Dilepton/Core/DileptonProducer.h b/PWGEM/Dilepton/Core/DileptonProducer.h index 26b06061cb4..69327c1b068 100644 --- a/PWGEM/Dilepton/Core/DileptonProducer.h +++ b/PWGEM/Dilepton/Core/DileptonProducer.h @@ -162,7 +162,7 @@ struct DileptonProducer { Configurable cfg_min_dphi{"cfg_min_dphi", 0.2, "min dphi between 2 electrons (elliptic cut)"}; Configurable cfg_min_opang{"cfg_min_opang", 0.0, "min opening angle"}; Configurable cfg_max_opang{"cfg_max_opang", 6.4, "max opening angle"}; - Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; + // Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; Configurable cfg_apply_cuts_from_prefilter{"cfg_apply_cuts_from_prefilter", false, "flag to apply prefilter set when producing derived data"}; Configurable cfg_prefilter_bits{"cfg_prefilter_bits", 0, "prefilter bits [kNone : 0, kElFromPC : 1, kElFromPi0_20MeV : 2, kElFromPi0_40MeV : 4, kElFromPi0_60MeV : 8, kElFromPi0_80MeV : 16, kElFromPi0_100MeV : 32, kElFromPi0_120MeV : 64, kElFromPi0_140MeV : 128] Please consider logical-OR among them."}; // see PairUtilities.h @@ -191,8 +191,8 @@ struct DileptonProducer { Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; - Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; - Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + // Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + // Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; Configurable cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; @@ -213,14 +213,12 @@ struct DileptonProducer { Configurable cfg_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; - Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; - Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; // configuration for PID ML Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; - Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; - Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20.f}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.98, 0.98, 0.9, 0.9, 0.95, 0.95, 0.8, 0.8}, "ML cuts per bin"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; @@ -243,6 +241,9 @@ struct DileptonProducer { Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 muons (elliptic cut)"}; Configurable cfg_min_dphi{"cfg_min_dphi", 0.02, "min dphi between 2 muons (elliptic cut)"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter set in derived data"}; + Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; @@ -393,7 +394,7 @@ struct DileptonProducer { fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); fDielectronCut.SetMindEtadPhi(dielectroncuts.cfg_apply_detadphi, false, dielectroncuts.cfg_min_deta, dielectroncuts.cfg_min_dphi); fDielectronCut.SetPairOpAng(dielectroncuts.cfg_min_opang, dielectroncuts.cfg_max_opang); - fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); + // fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); // for track fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); @@ -412,8 +413,7 @@ struct DileptonProducer { fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); fDielectronCut.SetChi2TOF(0, dielectroncuts.cfg_max_chi2tof); - fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); - fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + // fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); // for eID fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); @@ -573,6 +573,10 @@ struct DileptonProducer { Preslice perCollision_muon = aod::emprimarymuon::emeventId; Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_pt_track < o2::aod::fwdtrack::pt && o2::aod::fwdtrack::pt < dimuoncuts.cfg_max_pt_track && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track; Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter prefilter_derived_muon = ifnode(dimuoncuts.cfg_apply_cuts_from_prefilter_derived.node() && dimuoncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) <= static_cast(0), true) && + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) <= static_cast(0), true), + o2::aod::emprimarymuon::pfbderived >= static_cast(0)); Partition positive_muons = o2::aod::emprimarymuon::sign > int8_t(0); Partition negative_muons = o2::aod::emprimarymuon::sign < int8_t(0); diff --git a/PWGEM/Dilepton/Core/DimuonCut.cxx b/PWGEM/Dilepton/Core/DimuonCut.cxx index c9cded44408..c5e9743bf10 100644 --- a/PWGEM/Dilepton/Core/DimuonCut.cxx +++ b/PWGEM/Dilepton/Core/DimuonCut.cxx @@ -93,6 +93,11 @@ void DimuonCut::SetMatchingChi2MCHMFT(float min, float max) mMaxMatchingChi2MCHMFT = max; LOG(info) << "Dimuon Cut, set matching chi2 MFT-MCH range: " << mMinMatchingChi2MCHMFT << " - " << mMaxMatchingChi2MCHMFT; } +void DimuonCut::SetMaxMatchingChi2MCHMFTPtDep(std::function PtDepCut) +{ + mMaxMatchingChi2MCHMFTPtDep = PtDepCut; + LOG(info) << "Dimuon Cut, set matching chi2 MFT-MCH range: " << mMaxMatchingChi2MCHMFTPtDep(0.5); +} void DimuonCut::SetMatchingChi2MCHMID(float min, float max) { mMinMatchingChi2MCHMID = min; @@ -123,6 +128,11 @@ void DimuonCut::SetDCAxy(float min, float max) mMaxDcaXY = max; LOG(info) << "Dimuon Cut, set DCAxy range: " << mMinDcaXY << " - " << mMaxDcaXY; } +void DimuonCut::EnableTTCA(const bool flag) +{ + mEnableTTCA = flag; + LOG(info) << "Dimuon Cut, enable TTCA: " << mEnableTTCA; +} void DimuonCut::SetMaxPDCARabsDep(std::function RabsDepCut) { mMaxPDCARabsDep = RabsDepCut; diff --git a/PWGEM/Dilepton/Core/DimuonCut.h b/PWGEM/Dilepton/Core/DimuonCut.h index 53421b278a9..dd10561196d 100644 --- a/PWGEM/Dilepton/Core/DimuonCut.h +++ b/PWGEM/Dilepton/Core/DimuonCut.h @@ -64,6 +64,7 @@ class DimuonCut : public TNamed kPDCA, kMFTHitMap, kDPtDEtaDPhiwrtMCHMID, + kTTCA, kNCuts }; @@ -166,6 +167,9 @@ class DimuonCut : public TNamed if (!IsSelectedTrack(track, DimuonCuts::kRabs)) { return false; } + if (!IsSelectedTrack(track, DimuonCuts::kTTCA)) { + return false; + } if (mApplyMFTHitMap && track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && !IsSelectedTrack(track, DimuonCuts::kMFTHitMap)) { return false; } @@ -208,7 +212,8 @@ class DimuonCut : public TNamed return track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? 0.f < track.chi2MFT() / (2.f * track.nClustersMFT() - 5.f) && track.chi2MFT() / (2.f * track.nClustersMFT() - 5.f) < mMaxChi2MFT : true; case DimuonCuts::kMatchingChi2MCHMFT: - return 0.f < track.chi2MatchMCHMFT() && track.chi2MatchMCHMFT() < mMaxMatchingChi2MCHMFT; + // return 0.f < track.chi2MatchMCHMFT() && track.chi2MatchMCHMFT() < mMaxMatchingChi2MCHMFT; + return 0.f < track.chi2MatchMCHMFT() && track.chi2MatchMCHMFT() < mMaxMatchingChi2MCHMFTPtDep(track.pt()); case DimuonCuts::kMatchingChi2MCHMID: return 0.f < track.chi2MatchMCHMID() && track.chi2MatchMCHMID() < mMaxMatchingChi2MCHMID; @@ -219,6 +224,9 @@ class DimuonCut : public TNamed case DimuonCuts::kRabs: return mMinRabs < track.rAtAbsorberEnd() && track.rAtAbsorberEnd() < mMaxRabs; + case DimuonCuts::kTTCA: + return mEnableTTCA ? true : track.isAssociatedToMPC(); + case DimuonCuts::kMFTHitMap: { std::vector mftHitMap{checkMFTHitMap<0, 1>(track), checkMFTHitMap<2, 3>(track), checkMFTHitMap<4, 5>(track), checkMFTHitMap<6, 7>(track), checkMFTHitMap<8, 9>(track)}; for (const auto& iDisk : mRequiredMFTDisks) { @@ -259,6 +267,8 @@ class DimuonCut : public TNamed void SetMaxPDCARabsDep(std::function RabsDepCut); void SetMFTHitMap(bool flag, std::vector hitMap); void SetMaxdPtdEtadPhiwrtMCHMID(float reldPtMax, float dEtaMax, float dPhiMax); // this is relevant for global muons + void SetMaxMatchingChi2MCHMFTPtDep(std::function PtDepCut); + void EnableTTCA(bool flag); private: // pair cuts @@ -269,6 +279,7 @@ class DimuonCut : public TNamed bool mApplydEtadPhi{false}; // flag to apply deta, dphi cut between 2 tracks float mMinDeltaEta{0.f}; float mMinDeltaPhi{0.f}; + bool mEnableTTCA{true}; // kinematic cuts float mMinTrackPt{0.f}, mMaxTrackPt{1e10f}; // range in pT @@ -284,6 +295,7 @@ class DimuonCut : public TNamed float mMinMatchingChi2MCHMFT{0.f}, mMaxMatchingChi2MCHMFT{1e10f}; // max matching chi2 between MCH-MFT float mMinMatchingChi2MCHMID{0.f}, mMaxMatchingChi2MCHMID{1e10f}; // max matching chi2 between MCH-MID std::function mMaxPDCARabsDep{}; // max pdca in xy plane as function of Rabs + std::function mMaxMatchingChi2MCHMFTPtDep{}; // max matching chi2 between MCH-MFT as function of pt float mMinRabs{17.6}, mMaxRabs{89.5}; float mMinDcaXY{0.0f}, mMaxDcaXY{1e10f}; diff --git a/PWGEM/Dilepton/Core/EMTrackCut.cxx b/PWGEM/Dilepton/Core/EMTrackCut.cxx index 2ea7934a30b..ed9e345a0f9 100644 --- a/PWGEM/Dilepton/Core/EMTrackCut.cxx +++ b/PWGEM/Dilepton/Core/EMTrackCut.cxx @@ -17,14 +17,8 @@ #include "Framework/Logger.h" -#include -#include - ClassImp(EMTrackCut); -const std::pair> EMTrackCut::its_ib_any_Requirement = {1, {0, 1, 2}}; // hits on any ITS ib layers. -const std::pair> EMTrackCut::its_ib_1st_Requirement = {1, {0}}; // hit on 1st ITS ib layers. - void EMTrackCut::SetTrackPtRange(float minPt, float maxPt) { mMinTrackPt = minPt; @@ -43,74 +37,12 @@ void EMTrackCut::SetTrackPhiRange(float minPhi, float maxPhi) mMaxTrackPhi = maxPhi; LOG(info) << "EMTrack Cut, set track phi range (rad.): " << mMinTrackPhi << " - " << mMaxTrackPhi; } -void EMTrackCut::SetMinNClustersTPC(int minNClustersTPC) -{ - mMinNClustersTPC = minNClustersTPC; - LOG(info) << "EMTrack Cut, set min N clusters TPC: " << mMinNClustersTPC; -} -void EMTrackCut::SetMinNCrossedRowsTPC(int minNCrossedRowsTPC) -{ - mMinNCrossedRowsTPC = minNCrossedRowsTPC; - LOG(info) << "EMTrack Cut, set min N crossed rows TPC: " << mMinNCrossedRowsTPC; -} -void EMTrackCut::SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC) -{ - mMinNCrossedRowsOverFindableClustersTPC = minNCrossedRowsOverFindableClustersTPC; - LOG(info) << "EMTrack Cut, set min N crossed rows over findable clusters TPC: " << mMinNCrossedRowsOverFindableClustersTPC; -} -void EMTrackCut::SetMaxFracSharedClustersTPC(float max) -{ - mMaxFracSharedClustersTPC = max; - LOG(info) << "EMTrack Cut, set max fraction of shared clusters in TPC: " << mMaxFracSharedClustersTPC; -} -void EMTrackCut::SetChi2PerClusterTPC(float min, float max) -{ - mMinChi2PerClusterTPC = min; - mMaxChi2PerClusterTPC = max; - LOG(info) << "EMTrack Cut, set chi2 per cluster TPC range: " << mMinChi2PerClusterTPC << " - " << mMaxChi2PerClusterTPC; -} - -void EMTrackCut::SetNClustersITS(int min, int max) -{ - mMinNClustersITS = min; - mMaxNClustersITS = max; - LOG(info) << "EMTrack Cut, set N clusters ITS range: " << mMinNClustersITS << " - " << mMaxNClustersITS; -} -void EMTrackCut::SetChi2PerClusterITS(float min, float max) -{ - mMinChi2PerClusterITS = min; - mMaxChi2PerClusterITS = max; - LOG(info) << "EMTrack Cut, set chi2 per cluster ITS range: " << mMinChi2PerClusterITS << " - " << mMaxChi2PerClusterITS; -} - -void EMTrackCut::SetTrackMaxDcaXY(float maxDcaXY) -{ - mMaxDcaXY = maxDcaXY; - LOG(info) << "EMTrack Cut, set max DCA xy: " << mMaxDcaXY; -} -void EMTrackCut::SetTrackMaxDcaZ(float maxDcaZ) -{ - mMaxDcaZ = maxDcaZ; - LOG(info) << "EMTrack Cut, set max DCA z: " << mMaxDcaZ; -} -void EMTrackCut::SetTrackMaxDcaXYPtDep(std::function ptDepCut) -{ - mMaxDcaXYPtDep = ptDepCut; - LOG(info) << "EMTrack Cut, set max DCA xy pt dep: " << mMaxDcaXYPtDep(1.0); -} - -void EMTrackCut::RequireITSibAny(bool flag) -{ - mRequireITSibAny = flag; - LOG(info) << "EMTrack Cut, require ITS ib any: " << mRequireITSibAny; -} - -void EMTrackCut::RequireITSib1st(bool flag) -{ - mRequireITSib1st = flag; - LOG(info) << "EMTrack Cut, require ITS ib 1st: " << mRequireITSib1st; -} +// void EMTrackCut::SetTrackMaxDcaXYPtDep(std::function ptDepCut) +// { +// mMaxDcaXYPtDep = ptDepCut; +// LOG(info) << "EMTrack Cut, set max DCA xy pt dep: " << mMaxDcaXYPtDep(1.0); +// } void EMTrackCut::SetTrackBit(uint16_t bit) { diff --git a/PWGEM/Dilepton/Core/EMTrackCut.h b/PWGEM/Dilepton/Core/EMTrackCut.h index d70a009aaac..2194aabb7cf 100644 --- a/PWGEM/Dilepton/Core/EMTrackCut.h +++ b/PWGEM/Dilepton/Core/EMTrackCut.h @@ -16,23 +16,10 @@ #ifndef PWGEM_DILEPTON_CORE_EMTRACKCUT_H_ #define PWGEM_DILEPTON_CORE_EMTRACKCUT_H_ -#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/DataTypes.h" #include "Framework/Logger.h" -#include "Math/Vector4D.h" #include "TNamed.h" -#include -#include -#include -#include -#include - -using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; - class EMTrackCut : public TNamed { public: @@ -45,15 +32,6 @@ class EMTrackCut : public TNamed kTrackPtRange, kTrackEtaRange, kTrackPhiRange, - // kDCAxy, - // kDCAz, - // kTPCNCls, - // kTPCCrossedRows, - // kTPCCrossedRowsOverNCls, - // kTPCFracSharedClusters, - // kTPCChi2NDF, - // kITSNCls, - // kITSChi2NDF, kTrackBit, kNCuts }; @@ -61,10 +39,6 @@ class EMTrackCut : public TNamed template bool IsSelected(TTrack const& track) const { - // if (!track.hasITS() || !track.hasTPC()) { - // return false; - // } - if (!IsSelectedTrack(track, EMTrackCuts::kTrackPtRange)) { return false; } @@ -75,56 +49,10 @@ class EMTrackCut : public TNamed return false; } - // if (!IsSelectedTrack(track, EMTrackCuts::kDCAxy)) { - // return false; - // } - // if (!IsSelectedTrack(track, EMTrackCuts::kDCAz)) { - // return false; - // } - if (!IsSelectedTrack(track, EMTrackCuts::kTrackBit)) { return false; } - // // ITS cuts - // if (!IsSelectedTrack(track, EMTrackCuts::kITSNCls)) { - // return false; - // } - // if (!IsSelectedTrack(track, EMTrackCuts::kITSChi2NDF)) { - // return false; - // } - // - // if (mRequireITSibAny) { - // auto hits_ib = std::count_if(its_ib_any_Requirement.second.begin(), its_ib_any_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - // if (hits_ib < its_ib_any_Requirement.first) { - // return false; - // } - // } - // - // if (mRequireITSib1st) { - // auto hits_ib = std::count_if(its_ib_1st_Requirement.second.begin(), its_ib_1st_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - // if (hits_ib < its_ib_1st_Requirement.first) { - // return false; - // } - // } - // - // // TPC cuts - // if (!IsSelectedTrack(track, EMTrackCuts::kTPCNCls)) { - // return false; - // } - // if (!IsSelectedTrack(track, EMTrackCuts::kTPCCrossedRows)) { - // return false; - // } - // if (!IsSelectedTrack(track, EMTrackCuts::kTPCCrossedRowsOverNCls)) { - // return false; - // } - // if (!IsSelectedTrack(track, EMTrackCuts::kTPCFracSharedClusters)) { - // return false; - // } - // if (!IsSelectedTrack(track, EMTrackCuts::kTPCChi2NDF)) { - // return false; - // } - return true; } @@ -141,12 +69,6 @@ class EMTrackCut : public TNamed case EMTrackCuts::kTrackPhiRange: return track.phi() > mMinTrackPhi && track.phi() < mMaxTrackPhi; - // case EMTrackCuts::kDCAxy: - // return std::fabs(track.dcaXY()) < ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); - - // case EMTrackCuts::kDCAz: - // return std::fabs(track.dcaZ()) < mMaxDcaZ; - case EMTrackCuts::kTrackBit: { // for (int i = 0; i < 10; i++) { // if ((mTrackBit & (1 << i)) > 0 && !((track.trackBit() & (1 << i)) > 0)) { @@ -157,27 +79,6 @@ class EMTrackCut : public TNamed return (track.trackBit() & mTrackBit) >= mTrackBit; } - // case EMTrackCuts::kTPCNCls: - // return track.tpcNClsFound() >= mMinNClustersTPC; - - // case EMTrackCuts::kTPCCrossedRows: - // return track.tpcNClsCrossedRows() >= mMinNCrossedRowsTPC; - - // case EMTrackCuts::kTPCCrossedRowsOverNCls: - // return track.tpcCrossedRowsOverFindableCls() > mMinNCrossedRowsOverFindableClustersTPC; - - // case EMTrackCuts::kTPCFracSharedClusters: - // return track.tpcFractionSharedCls() < mMaxFracSharedClustersTPC; - - // case EMTrackCuts::kTPCChi2NDF: - // return mMinChi2PerClusterTPC < track.tpcChi2NCl() && track.tpcChi2NCl() < mMaxChi2PerClusterTPC; - - // case EMTrackCuts::kITSNCls: - // return mMinNClustersITS <= track.itsNCls() && track.itsNCls() <= mMaxNClustersITS; - - // case EMTrackCuts::kITSChi2NDF: - // return mMinChi2PerClusterITS < track.itsChi2NCl() && track.itsChi2NCl() < mMaxChi2PerClusterITS; - default: return false; } @@ -187,46 +88,17 @@ class EMTrackCut : public TNamed void SetTrackPtRange(float minPt = 0.f, float maxPt = 1e10f); void SetTrackEtaRange(float minEta = -1e10f, float maxEta = 1e10f); void SetTrackPhiRange(float minPhi = 0.f, float maxPhi = 6.3f); - void SetMinNClustersTPC(int minNClustersTPC); - void SetMinNCrossedRowsTPC(int minNCrossedRowsTPC); - void SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC); - void SetMaxFracSharedClustersTPC(float max); - void SetChi2PerClusterTPC(float min, float max); - void SetNClustersITS(int min, int max); - void SetChi2PerClusterITS(float min, float max); - - void SetTrackDca3DRange(float min, float max); // in sigma - void SetTrackMaxDcaXY(float maxDcaXY); // in cm - void SetTrackMaxDcaZ(float maxDcaZ); // in cm - void SetTrackMaxDcaXYPtDep(std::function ptDepCut); - void RequireITSibAny(bool flag); - void RequireITSib1st(bool flag); void SetTrackBit(uint16_t bits); private: - static const std::pair> its_ib_any_Requirement; - static const std::pair> its_ib_1st_Requirement; - // kinematic cuts float mMinTrackPt{0.f}, mMaxTrackPt{1e10f}; // range in pT float mMinTrackEta{-1e10f}, mMaxTrackEta{1e10f}; // range in eta float mMinTrackPhi{0.f}, mMaxTrackPhi{6.3}; // range in phi // track quality cuts - int mMinNClustersTPC{0}; // min number of TPC clusters - int mMinNCrossedRowsTPC{0}; // min number of crossed rows in TPC - float mMinChi2PerClusterTPC{0.f}, mMaxChi2PerClusterTPC{1e10f}; // max tpc fit chi2 per TPC cluster - float mMinNCrossedRowsOverFindableClustersTPC{0.f}; // min ratio crossed rows / findable clusters - float mMaxFracSharedClustersTPC{999.f}; // max ratio shared clusters / clusters in TPC - int mMinNClustersITS{0}, mMaxNClustersITS{7}; // range in number of ITS clusters - float mMinChi2PerClusterITS{0.f}, mMaxChi2PerClusterITS{1e10f}; // max its fit chi2 per ITS cluster - bool mRequireITSibAny{true}; - bool mRequireITSib1st{false}; uint16_t mTrackBit{0}; - - float mMaxDcaXY{1.0f}; // max dca in xy plane - float mMaxDcaZ{1.0f}; // max dca in z direction - std::function mMaxDcaXYPtDep{}; // max dca in xy plane as function of pT + // std::function mMaxDcaXYPtDep{}; // max dca in xy plane as function of pT ClassDef(EMTrackCut, 1); }; diff --git a/PWGEM/Dilepton/Core/SingleTrackQC.h b/PWGEM/Dilepton/Core/SingleTrackQC.h index 8b2d00019a3..3aeb5f44893 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQC.h @@ -21,14 +21,10 @@ #include "PWGEM/Dilepton/Core/DimuonCut.h" #include "PWGEM/Dilepton/Core/EMEventCut.h" #include "PWGEM/Dilepton/DataModel/dileptonTables.h" -#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" #include "PWGEM/Dilepton/Utils/EventHistograms.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/Zorro.h" -#include "Tools/ML/MlResponse.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" @@ -52,7 +48,6 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; @@ -78,7 +73,6 @@ struct SingleTrackQC { Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfg_swt_name{"cfg_swt_name", "fHighTrackMult", "desired software trigger name"}; // 1 trigger name per 1 task. fHighTrackMult, fHighFt0Mult Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", false, "flag to apply weighting by 1/N"}; ConfigurableAxis ConfPtlBins{"ConfPtlBins", {VARIABLE_WIDTH, 0.00, 0.05, 0.10, 0.15, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pTl bins for output histograms"}; @@ -172,14 +166,12 @@ struct SingleTrackQC { Configurable cfg_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; - Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; - Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; // configuration for PID ML Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; - Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; - Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20.f}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.98, 0.98, 0.9, 0.9, 0.95, 0.95, 0.8, 0.8}, "ML cuts per bin"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; @@ -202,7 +194,10 @@ struct SingleTrackQC { Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; - Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + // Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_border_pt_for_chi2mchmft{"cfg_border_pt_for_chi2mchmft", 0, "border pt for different max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mftmch_lowPt{"cfg_max_matching_chi2_mftmch_lowPt", 8, "max chi2 for MFT-MCH matching for low pT"}; + Configurable cfg_max_matching_chi2_mftmch_highPt{"cfg_max_matching_chi2_mftmch_highPt", 40, "max chi2 for MFT-MCH matching for high pT"}; Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; @@ -287,6 +282,7 @@ struct SingleTrackQC { // fRegistry.add("Track/positive/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); // fRegistry.add("Track/positive/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hPIDForTracking", "PID for trackng", kTH1F, {{9, -0.5, 8.5}}, false); // see numbering in O2/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h fRegistry.add("Track/positive/hProbElBDT", "probability to be e from BDT;p_{in} (GeV/c);BDT score;", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); fRegistry.add("Track/positive/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); fRegistry.add("Track/positive/hMeanClusterSizeITSib", "mean cluster size ITS inner barrel;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); @@ -449,7 +445,6 @@ struct SingleTrackQC { fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); } - o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -472,7 +467,7 @@ struct SingleTrackQC { fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); - fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + fDielectronCut.EnableTTCA(dielectroncuts.enableTTCA); // for eID fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); @@ -496,31 +491,6 @@ struct SingleTrackQC { thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); } fDielectronCut.SetMLThresholds(binsML, thresholdsML); - - // static constexpr int nClassesMl = 2; - // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; - // const std::vector labelsClasses = {"Background", "Signal"}; - // const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; - // const std::vector labelsBins(nBinsMl, "bin"); - // double cutsMlArr[nBinsMl][nClassesMl]; - // for (uint32_t i = 0; i < nBinsMl; i++) { - // cutsMlArr[i][0] = 0.; - // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; - // } - // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; - - // mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); - // if (dielectroncuts.loadModelsFromCCDB) { - // ccdbApi.init(ccdburl); - // mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); - // } else { - // mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); - // } - // mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); - // mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); - // mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); - - // fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); } // end of PID ML } @@ -537,13 +507,15 @@ struct SingleTrackQC { fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); - fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + // fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMaxMatchingChi2MCHMFTPtDep([&](float pt) { return (pt < dimuoncuts.cfg_border_pt_for_chi2mchmft ? dimuoncuts.cfg_max_matching_chi2_mftmch_lowPt : dimuoncuts.cfg_max_matching_chi2_mftmch_highPt); }); fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + fDimuonCut.EnableTTCA(dimuoncuts.enableTTCA); } template @@ -585,6 +557,7 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/positive/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); fRegistry.fill(HIST("Track/positive/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/positive/hPIDForTracking"), track.pidForTracking()); fRegistry.fill(HIST("Track/positive/hProbElBDT"), track.tpcInnerParam(), track.probElBDT()); fRegistry.fill(HIST("Track/positive/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); fRegistry.fill(HIST("Track/positive/hMeanClusterSizeITSib"), track.p(), track.meanClusterSizeITSib() * std::cos(std::atan(track.tgl()))); @@ -624,6 +597,7 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/negative/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); fRegistry.fill(HIST("Track/negative/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/negative/hPIDForTracking"), track.pidForTracking()); fRegistry.fill(HIST("Track/negative/hProbElBDT"), track.tpcInnerParam(), track.probElBDT()); fRegistry.fill(HIST("Track/negative/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); fRegistry.fill(HIST("Track/negative/hMeanClusterSizeITSib"), track.p(), track.meanClusterSizeITSib() * std::cos(std::atan(track.tgl()))); @@ -662,9 +636,9 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/positive/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/positive/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/positive/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/positive/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); - fRegistry.fill(HIST("Track/positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); - fRegistry.fill(HIST("Track/positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/positive/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); + fRegistry.fill(HIST("Track/positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); + fRegistry.fill(HIST("Track/positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); fRegistry.fill(HIST("Track/positive/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); fRegistry.fill(HIST("Track/positive/hDCAx_PosZ"), collision.posZ(), track.fwdDcaX()); fRegistry.fill(HIST("Track/positive/hDCAy_PosZ"), collision.posZ(), track.fwdDcaY()); @@ -686,9 +660,9 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/negative/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/negative/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/negative/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/negative/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); - fRegistry.fill(HIST("Track/negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); - fRegistry.fill(HIST("Track/negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/negative/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); + fRegistry.fill(HIST("Track/negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); + fRegistry.fill(HIST("Track/negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); fRegistry.fill(HIST("Track/negative/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); fRegistry.fill(HIST("Track/negative/hDCAx_PosZ"), collision.posZ(), track.fwdDcaX()); fRegistry.fill(HIST("Track/negative/hDCAy_PosZ"), collision.posZ(), track.fwdDcaY()); @@ -771,9 +745,12 @@ struct SingleTrackQC { if (!cut.template IsSelectedTrack(track)) { continue; } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + if (!map_best_match_globalmuon[track.globalIndex()]) { continue; } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + // continue; + // } fillMuonInfo(track, collision); } // end of track loop @@ -827,9 +804,12 @@ struct SingleTrackQC { if (!cut.template IsSelectedTrack(track)) { continue; } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + if (!map_best_match_globalmuon[track.globalIndex()]) { continue; } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + // continue; + // } passed_trackIds.emplace_back(track.globalIndex()); } // end of track loop } @@ -865,15 +845,17 @@ struct SingleTrackQC { passed_trackIds.shrink_to_fit(); } + std::unordered_map map_best_match_globalmuon; + SliceCache cache; Preslice perCollision_electron = aod::emprimaryelectron::emeventId; Filter trackFilter_electron = dielectroncuts.cfg_min_pt_track < o2::aod::track::pt && dielectroncuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < dielectroncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; - Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), true, o2::aod::emprimaryelectron::isAssociatedToMPC == true); Preslice perCollision_muon = aod::emprimarymuon::emeventId; Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_pt_track < o2::aod::fwdtrack::pt && o2::aod::fwdtrack::pt < dimuoncuts.cfg_max_pt_track && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track && dimuoncuts.cfg_min_phi_track < o2::aod::fwdtrack::phi && o2::aod::fwdtrack::phi < dimuoncuts.cfg_max_phi_track; - Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), true, o2::aod::emprimarymuon::isAssociatedToMPC == true); Filter collisionFilter_centrality = (eventcuts.cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcuts.cfgCentMax); Filter collisionFilter_numContrib = eventcuts.cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < eventcuts.cfgNumContribMax; @@ -891,13 +873,14 @@ struct SingleTrackQC { runQC(collisions, electrons, perCollision_electron, fDielectronCut); } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { auto muons = std::get<0>(std::tie(args...)); + map_best_match_globalmuon = findBestMatchMap(muons, fDimuonCut); if (cfgApplyWeightTTCA) { fillTrackWeightMap(collisions, muons, perCollision_muon, fDimuonCut); } runQC(collisions, muons, perCollision_muon, fDimuonCut); } - map_weight.clear(); + map_best_match_globalmuon.clear(); } PROCESS_SWITCH(SingleTrackQC, processQC, "run single track QC", true); @@ -911,12 +894,14 @@ struct SingleTrackQC { runQC(collisions, electrons, perCollision_electron, fDielectronCut); } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { auto muons = std::get<0>(std::tie(args...)); + map_best_match_globalmuon = findBestMatchMap(muons, fDimuonCut); if (cfgApplyWeightTTCA) { fillTrackWeightMap(collisions, muons, perCollision_muon, fDimuonCut); } runQC(collisions, muons, perCollision_muon, fDimuonCut); } map_weight.clear(); + map_best_match_globalmuon.clear(); } PROCESS_SWITCH(SingleTrackQC, processQC_TriggeredData, "run single track QC on triggered data", false); diff --git a/PWGEM/Dilepton/Core/SingleTrackQCMC.h b/PWGEM/Dilepton/Core/SingleTrackQCMC.h index 32169f6330f..b000ee4ba28 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQCMC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQCMC.h @@ -21,14 +21,10 @@ #include "PWGEM/Dilepton/Core/DimuonCut.h" #include "PWGEM/Dilepton/Core/EMEventCut.h" #include "PWGEM/Dilepton/DataModel/dileptonTables.h" -#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" #include "PWGEM/Dilepton/Utils/EventHistograms.h" #include "PWGEM/Dilepton/Utils/MCUtilities.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Common/CCDB/RCTSelectionFlags.h" -#include "Tools/ML/MlResponse.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" @@ -181,14 +177,13 @@ struct SingleTrackQCMC { Configurable cfg_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; - Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; - Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks only for MC. switch ON only if needed."}; // configuration for PID ML Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; - Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; - Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20.f}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.98, 0.98, 0.9, 0.9, 0.95, 0.95, 0.8, 0.8}, "ML cuts per bin"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; @@ -210,7 +205,10 @@ struct SingleTrackQCMC { Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; - Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + // Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_border_pt_for_chi2mchmft{"cfg_border_pt_for_chi2mchmft", 0, "border pt for different max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mftmch_lowPt{"cfg_max_matching_chi2_mftmch_lowPt", 8, "max chi2 for MFT-MCH matching for low pT"}; + Configurable cfg_max_matching_chi2_mftmch_highPt{"cfg_max_matching_chi2_mftmch_highPt", 40, "max chi2 for MFT-MCH matching for high pT"}; Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; @@ -221,7 +219,8 @@ struct SingleTrackQCMC { Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; - Configurable rejectWrongMatch{"rejectWrongMatch", false, "flag to reject wrong match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. + Configurable acceptOnlyCorrectMatch{"acceptOnlyCorrectMatch", false, "flag to accept only correct match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. + Configurable acceptOnlyWrongMatch{"acceptOnlyWrongMatch", false, "flag to accept only wrong match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. } dimuoncuts; o2::aod::rctsel::RCTFlagsChecker rctChecker; @@ -282,17 +281,18 @@ struct SingleTrackQCMC { fRegistry.add("Track/PromptLF/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); fRegistry.add("Track/PromptLF/positive/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); fRegistry.add("Track/PromptLF/positive/hDCA3dRes_Pt", "DCA_{3D} resolution vs. pT;p_{T} (GeV/c);DCA_{3D} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); - fRegistry.add("Track/PromptLF/positive/hNclsTPC_Pt", "number of TPC clusters;p_{T,e} (GeV/c);;TPC N_{cls}", kTH2F, {axis_pt, {161, -0.5, 160.5}}, false); - fRegistry.add("Track/PromptLF/positive/hNcrTPC_Pt", "number of TPC crossed rows;p_{T,e} (GeV/c);;TPC N_{CR}", kTH2F, {axis_pt, {161, -0.5, 160.5}}, false); - fRegistry.add("Track/PromptLF/positive/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); - fRegistry.add("Track/PromptLF/positive/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); - fRegistry.add("Track/PromptLF/positive/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/PromptLF/positive/hNclsTPC_Pt", "number of TPC clusters;p_{T,e} (GeV/c);TPC N_{cls}", kTH2F, {axis_pt, {161, -0.5, 160.5}}, false); + fRegistry.add("Track/PromptLF/positive/hNcrTPC_Pt", "number of TPC crossed rows;p_{T,e} (GeV/c);TPC N_{CR}", kTH2F, {axis_pt, {161, -0.5, 160.5}}, false); + fRegistry.add("Track/PromptLF/positive/hChi2TPC", "chi2/number of TPC clusters;TPC #chi^{2}/N_{CR}", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/PromptLF/positive/hTPCNcr2Nf", "TPC Ncr/Nfindable;TPC N_{CR}/N_{cls}^{findable}", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/PromptLF/positive/hTPCNcls2Nf", "TPC Ncls/Nfindable;TPC N_{cls}/N_{cls}^{findable}", kTH1F, {{200, 0, 2}}, false); fRegistry.add("Track/PromptLF/positive/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); - fRegistry.add("Track/PromptLF/positive/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); - fRegistry.add("Track/PromptLF/positive/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/PromptLF/positive/hNclsITS", "number of ITS clusters;ITS N_{cls}", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/PromptLF/positive/hChi2ITS", "chi2/number of ITS clusters;ITS #chi^{2}/N_{cls}", kTH1F, {{100, 0, 10}}, false); fRegistry.add("Track/PromptLF/positive/hDeltaPin", "p_{in} vs. p_{pv};p_{in} (GeV/c);(p_{pv} - p_{in})/p_{in}", kTH2F, {{1000, 0, 10}, {200, -1, +1}}, false); - fRegistry.add("Track/PromptLF/positive/hChi2TOF", "TOF Chi2;p_{pv} (GeV/c);chi2", kTH2F, {{1000, 0, 10}, {100, 0, 10}}, false); + fRegistry.add("Track/PromptLF/positive/hChi2TOF", "TOF Chi2;p_{pv} (GeV/c);TOF #chi^{2}", kTH2F, {{1000, 0, 10}, {100, 0, 10}}, false); fRegistry.add("Track/PromptLF/positive/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/PromptLF/positive/hPIDForTracking", "PID for trackng", kTH1F, {{9, -0.5, 8.5}}, false); // see numbering in O2/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaPtOverPtGen", "electron p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{200, 0, 10}, {200, -1.0f, 1.0f}}, true); fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaEta", "electron #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaPhi", "electron #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); @@ -493,7 +493,6 @@ struct SingleTrackQCMC { fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); } - o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -516,7 +515,8 @@ struct SingleTrackQCMC { fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); - fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, 1e+10); + fDielectronCut.EnableTTCA(dielectroncuts.enableTTCA); // for eID fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); @@ -540,31 +540,6 @@ struct SingleTrackQCMC { thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); } fDielectronCut.SetMLThresholds(binsML, thresholdsML); - - // static constexpr int nClassesMl = 2; - // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; - // const std::vector labelsClasses = {"Background", "Signal"}; - // const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; - // const std::vector labelsBins(nBinsMl, "bin"); - // double cutsMlArr[nBinsMl][nClassesMl]; - // for (uint32_t i = 0; i < nBinsMl; i++) { - // cutsMlArr[i][0] = 0.; - // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; - // } - // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; - - // mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); - // if (dielectroncuts.loadModelsFromCCDB) { - // ccdbApi.init(ccdburl); - // mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); - // } else { - // mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); - // } - // mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); - // mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); - // mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); - - // fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); } // end of PID ML } @@ -581,13 +556,15 @@ struct SingleTrackQCMC { fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); - fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + // fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMaxMatchingChi2MCHMFTPtDep([&](float pt) { return (pt < dimuoncuts.cfg_border_pt_for_chi2mchmft ? dimuoncuts.cfg_max_matching_chi2_mftmch_lowPt : dimuoncuts.cfg_max_matching_chi2_mftmch_highPt); }); fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + fDimuonCut.EnableTTCA(dimuoncuts.enableTTCA); } template @@ -678,6 +655,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDeltaPin"), track.tpcInnerParam(), (track.p() - track.tpcInnerParam()) / track.tpcInnerParam()); } fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPIDForTracking"), track.pidForTracking()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); @@ -723,6 +701,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDeltaPin"), track.tpcInnerParam(), (track.p() - track.tpcInnerParam()) / track.tpcInnerParam()); } fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPIDForTracking"), track.pidForTracking()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); @@ -769,9 +748,9 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy"), std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2))); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAx_PosZ"), collision.posZ(), track.fwdDcaX()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAy_PosZ"), collision.posZ(), track.fwdDcaY()); @@ -802,9 +781,9 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy"), std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2))); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAx_PosZ"), collision.posZ(), track.fwdDcaX()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAy_PosZ"), collision.posZ(), track.fwdDcaY()); @@ -885,10 +864,16 @@ struct SingleTrackQCMC { if (!cut.template IsSelectedTrack(track)) { continue; } - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + if (!map_best_match_globalmuon[track.globalIndex()]) { continue; } - if (dimuoncuts.rejectWrongMatch && track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && track.emmcparticleId() != track.emmftmcparticleId()) { + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + // continue; + // } + if (dimuoncuts.acceptOnlyCorrectMatch && track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && track.emmcparticleId() != track.emmftmcparticleId()) { + continue; + } + if (dimuoncuts.acceptOnlyWrongMatch && track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && track.emmcparticleId() == track.emmftmcparticleId()) { continue; } } @@ -1079,10 +1064,12 @@ struct SingleTrackQCMC { if (!cut.template IsSelectedTrack(track)) { continue; } - - if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + if (!map_best_match_globalmuon[track.globalIndex()]) { continue; } + // if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + // continue; + // } passed_trackIds.emplace_back(track.globalIndex()); } // end of track loop } @@ -1118,15 +1105,16 @@ struct SingleTrackQCMC { passed_trackIds.shrink_to_fit(); } + std::unordered_map map_best_match_globalmuon; SliceCache cache; Preslice perCollision_electron = aod::emprimaryelectron::emeventId; Filter trackFilter_electron = o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; - Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), true, o2::aod::emprimaryelectron::isAssociatedToMPC == true); Preslice perCollision_muon = aod::emprimarymuon::emeventId; Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_phi_track < o2::aod::fwdtrack::phi && o2::aod::fwdtrack::phi < dimuoncuts.cfg_max_phi_track; - Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), true, o2::aod::emprimarymuon::isAssociatedToMPC == true); Filter collisionFilter_centrality = (eventcuts.cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcuts.cfgCentMax); Filter collisionFilter_numContrib = eventcuts.cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < eventcuts.cfgNumContribMax; @@ -1149,6 +1137,7 @@ struct SingleTrackQCMC { runQCMC(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles); runGenInfo(collisions, electronsMC, mccollisions, mcparticles); } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + map_best_match_globalmuon = findBestMatchMap(tracks, fDimuonCut); if (cfgApplyWeightTTCA) { fillTrackWeightMap(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles); } @@ -1156,6 +1145,7 @@ struct SingleTrackQCMC { runGenInfo(collisions, muonsMC, mccollisions, mcparticles); } map_weight.clear(); + map_best_match_globalmuon.clear(); } PROCESS_SWITCH(SingleTrackQCMC, processQCMC, "run single track QC MC", true); @@ -1171,6 +1161,7 @@ struct SingleTrackQCMC { runQCMC(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles_smeared); runGenInfo(collisions, electronsMC_smeared, mccollisions, mcparticles_smeared); } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + map_best_match_globalmuon = findBestMatchMap(tracks, fDimuonCut); if (cfgApplyWeightTTCA) { fillTrackWeightMap(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles_smeared); } @@ -1178,6 +1169,7 @@ struct SingleTrackQCMC { runGenInfo(collisions, muonsMC_smeared, mccollisions, mcparticles_smeared); } map_weight.clear(); + map_best_match_globalmuon.clear(); } PROCESS_SWITCH(SingleTrackQCMC, processQCMC_Smeared, "run single track QC MC with smearing", false); diff --git a/PWGEM/Dilepton/DataModel/dileptonTables.h b/PWGEM/Dilepton/DataModel/dileptonTables.h index e26f3ef9ab4..882f714188e 100644 --- a/PWGEM/Dilepton/DataModel/dileptonTables.h +++ b/PWGEM/Dilepton/DataModel/dileptonTables.h @@ -328,7 +328,7 @@ DECLARE_SOA_TABLE_VERSIONED(EMEventsAlias_000, "AOD", "EMEVENTALIAS", 0, evsel:: using EMEventsAlias = EMEventsAlias_000; using EMEventAlias = EMEventsAlias::iterator; -DECLARE_SOA_TABLE(EMEventsXY, "AOD", "EMEVENTXY", emevent::PosX, emevent::PosY); // joinable to EMEvents, only for treeCreatetorML.cxx +DECLARE_SOA_TABLE(EMEventsXY, "AOD", "EMEVENTXY", collision::PosX, collision::PosY); // joinable to EMEvents using EMEventXY = EMEventsXY::iterator; DECLARE_SOA_TABLE(EMEventsCov, "AOD", "EMEVENTCOV", //! joinable to EMEvents @@ -910,7 +910,42 @@ DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectrons_005, "AOD", "EMPRIMARYEL", 5, //! emprimaryelectron::MeanClusterSizeITSib, emprimaryelectron::MeanClusterSizeITSob); -using EMPrimaryElectrons = EMPrimaryElectrons_005; +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectrons_006, "AOD", "EMPRIMARYEL", 6, //! + o2::soa::Index<>, emprimaryelectron::CollisionId, + emprimaryelectron::TrackId, emprimaryelectron::Sign, + track::Pt, track::Eta, track::Phi, + track::DcaXY, track::DcaZ, aod::track::CYY, aod::track::CZY, aod::track::CZZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusPID, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, /*pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr,*/ + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, /*track::Tgl,*/ + emprimaryelectron::IsAssociatedToMPC, emprimaryelectron::IsAmbiguous, emprimaryelectron::ProbElBDT, track::Flags, + mcpidtpc::DeDxTunedMc, + + // dynamic column + track::TPCNClsFound, + track::TPCNClsPID, + track::TPCNClsCrossedRows, + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::TPCFractionSharedCls, + track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, + track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, + track::PIDForTracking, // see numbering in O2/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h + track::IsPVContributor, + + emprimaryelectron::Signed1Pt, + emprimaryelectron::P, + emprimaryelectron::Px, + emprimaryelectron::Py, + emprimaryelectron::Pz, + emprimaryelectron::Tgl, + emprimaryelectron::MeanClusterSizeITS, + emprimaryelectron::MeanClusterSizeITSib, + emprimaryelectron::MeanClusterSizeITSob); + +using EMPrimaryElectrons = EMPrimaryElectrons_006; // iterators using EMPrimaryElectron = EMPrimaryElectrons::iterator; @@ -971,7 +1006,7 @@ DECLARE_SOA_TABLE(EMAmbiguousElectronSelfIds, "AOD", "EMAMBELSELFID", emprimarye // iterators using EMAmbiguousElectronSelfId = EMAmbiguousElectronSelfIds::iterator; -DECLARE_SOA_TABLE(EMPrimaryElectronsPrefilterBitDerived, "AOD", "PRMELPFBPI0", emprimaryelectron::PrefilterBitDerived); // To be joined with EMPrimaryElectrons table at analysis level. +DECLARE_SOA_TABLE(EMPrimaryElectronsPrefilterBitDerived, "AOD", "PRMELPFBDERIVED", emprimaryelectron::PrefilterBitDerived); // To be joined with EMPrimaryElectrons table at analysis level. // iterators using EMPrimaryElectronPrefilterBitDerived = EMPrimaryElectronsPrefilterBitDerived::iterator; @@ -982,6 +1017,7 @@ DECLARE_SOA_COLUMN(CollisionId, collisionId, int); DECLARE_SOA_COLUMN(FwdTrackId, fwdtrackId, int); //! DECLARE_SOA_COLUMN(MFTTrackId, mfttrackId, int); //! DECLARE_SOA_COLUMN(MCHTrackId, mchtrackId, int); //! +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(GlobalMuonsWithSameMCHMID, globalMuonsWithSameMCHMID); //! self indices to global muons that have the same MCHTrackId DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(GlobalMuonsWithSameMFT, globalMuonsWithSameMFT); //! self indices to global muons that have the same MFTTrackId DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(AmbiguousMuons, ambiguousMuons); DECLARE_SOA_COLUMN(CXXatDCA, cXXatDCA, float); //! DCAx resolution squared at DCA @@ -999,6 +1035,8 @@ DECLARE_SOA_COLUMN(IsAmbiguous, isAmbiguous, bool); //! is am DECLARE_SOA_COLUMN(IsCorrectMatchMFTMCH, isCorrectMatchMFTMCH, bool); //! is correct match between MFT and MCH, only for MC DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! DECLARE_SOA_COLUMN(Chi2MFT, chi2MFT, float); //! chi2 of MFT standalone track +DECLARE_SOA_COLUMN(PrefilterBitDerived, pfbderived, uint16_t); //! +DECLARE_SOA_DYNAMIC_COLUMN(Tgl, tgl, [](float eta) -> float { return std::tan(o2::constants::math::PIHalf - 2 * std::atan(std::exp(-eta))); }); DECLARE_SOA_DYNAMIC_COLUMN(Signed1Pt, signed1Pt, [](float pt, int8_t sign) -> float { return sign * 1. / pt; }); DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); @@ -1071,26 +1109,53 @@ DECLARE_SOA_TABLE_VERSIONED(EMPrimaryMuons_001, "AOD", "EMPRIMARYMU", 1, //! emprimarymuon::Py, emprimarymuon::Pz); -using EMPrimaryMuons = EMPrimaryMuons_001; +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryMuons_002, "AOD", "EMPRIMARYMU", 2, //! + o2::soa::Index<>, emprimarymuon::CollisionId, + emprimarymuon::FwdTrackId, emprimarymuon::MFTTrackId, emprimarymuon::MCHTrackId, fwdtrack::TrackType, + fwdtrack::Pt, fwdtrack::Eta, fwdtrack::Phi, emprimarymuon::Sign, + fwdtrack::FwdDcaX, fwdtrack::FwdDcaY, aod::fwdtrack::CXX, aod::fwdtrack::CYY, aod::fwdtrack::CXY, + emprimarymuon::PtMatchedMCHMID, emprimarymuon::EtaMatchedMCHMID, emprimarymuon::PhiMatchedMCHMID, + // emprimarymuon::EtaMatchedMCHMIDatMP, emprimarymuon::PhiMatchedMCHMIDatMP, + // emprimarymuon::EtaMatchedMFTatMP, emprimarymuon::PhiMatchedMFTatMP, + + fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, + fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT, + fwdtrack::MCHBitMap, fwdtrack::MIDBitMap, fwdtrack::MIDBoards, + fwdtrack::MFTClusterSizesAndTrackFlags, emprimarymuon::Chi2MFT, emprimarymuon::IsAssociatedToMPC, emprimarymuon::IsAmbiguous, + + // dynamic column + emprimarymuon::Signed1Pt, + emprimarymuon::Tgl, + emprimarymuon::NClustersMFT, + fwdtrack::IsCA, + emprimarymuon::MFTClusterMap, + emprimarymuon::P, + emprimarymuon::Px, + emprimarymuon::Py, + emprimarymuon::Pz); + +using EMPrimaryMuons = EMPrimaryMuons_002; // iterators using EMPrimaryMuon = EMPrimaryMuons::iterator; -DECLARE_SOA_TABLE(EMPrimaryMuonsCov, "AOD", "EMPRIMARYMUCOV", //! - aod::fwdtrack::CXX, - aod::fwdtrack::CXY, - aod::fwdtrack::CYY, - aod::fwdtrack::CPhiX, - aod::fwdtrack::CPhiY, - aod::fwdtrack::CPhiPhi, - aod::fwdtrack::CTglX, - aod::fwdtrack::CTglY, - aod::fwdtrack::CTglPhi, - aod::fwdtrack::CTglTgl, - aod::fwdtrack::C1PtX, - aod::fwdtrack::C1PtY, - aod::fwdtrack::C1PtPhi, - aod::fwdtrack::C1PtTgl, - aod::fwdtrack::C1Pt21Pt2); +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryMuonsCov_002, "AOD", "EMPRIMARYMUCOV", 2, //! + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, // at PV. Signed1Pt, Tgl and Phi are in EMPrimaryMuons table. + // aod::fwdtrack::CXX, + // aod::fwdtrack::CXY, + // aod::fwdtrack::CYY, + aod::fwdtrack::CPhiX, + aod::fwdtrack::CPhiY, + aod::fwdtrack::CPhiPhi, + aod::fwdtrack::CTglX, + aod::fwdtrack::CTglY, + aod::fwdtrack::CTglPhi, + aod::fwdtrack::CTglTgl, + aod::fwdtrack::C1PtX, + aod::fwdtrack::C1PtY, + aod::fwdtrack::C1PtPhi, + aod::fwdtrack::C1PtTgl, + aod::fwdtrack::C1Pt21Pt2); +using EMPrimaryMuonsCov = EMPrimaryMuonsCov_002; // iterators using EMPrimaryMuonCov = EMPrimaryMuonsCov::iterator; @@ -1102,10 +1167,16 @@ DECLARE_SOA_TABLE(EMAmbiguousMuonSelfIds, "AOD", "EMAMBMUSELFID", emprimarymuon: // iterators using EMAmbiguousMuonSelfId = EMAmbiguousMuonSelfIds::iterator; -DECLARE_SOA_TABLE(EMGlobalMuonSelfIds, "AOD", "EMGLMUSELFID", emprimarymuon::GlobalMuonsWithSameMFTIds); // To be joined with EMPrimaryMuons table at analysis level. +DECLARE_SOA_TABLE(EMGlobalMuonSelfIds_000, "AOD", "EMGLMUSELFID", emprimarymuon::GlobalMuonsWithSameMFTIds); // To be joined with EMPrimaryMuons table at analysis level. +DECLARE_SOA_TABLE_VERSIONED(EMGlobalMuonSelfIds_001, "AOD", "EMGLMUSELFID", 1, emprimarymuon::GlobalMuonsWithSameMCHMIDIds, emprimarymuon::GlobalMuonsWithSameMFTIds); // To be joined with EMPrimaryMuons table at analysis level. +using EMGlobalMuonSelfIds = EMGlobalMuonSelfIds_001; // iterators using EMGlobalMuonSelfId = EMGlobalMuonSelfIds::iterator; +DECLARE_SOA_TABLE(EMPrimaryMuonsPrefilterBitDerived, "AOD", "PRMMUPFBDERIVED", emprimarymuon::PrefilterBitDerived); // To be joined with EMPrimaryMuons table at analysis level. +// iterators +using EMPrimaryMuonPrefilterBitDerived = EMPrimaryMuonsPrefilterBitDerived::iterator; + DECLARE_SOA_TABLE(EMPrimaryMuonsMatchMC, "AOD", "EMMUONMATCHMC", emprimarymuon::IsCorrectMatchMFTMCH); // To be joined with EMPrimaryMuons table at analysis level. only for MC. // iterators using EMPrimaryMuonMatchMC = EMPrimaryMuonsMatchMC::iterator; @@ -1131,8 +1202,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, [](float signed1Pt) -> short { return (si DECLARE_SOA_TABLE_VERSIONED(EMPrimaryTracks_000, "AOD", "EMPRIMARYTRACK", 0, //! primary charged track table for 2PC o2::soa::Index<>, emprimarytrack::CollisionId, emprimarytrack::TrackId, oldemprimarytrack::Sign, track::Pt, track::Eta, track::Phi, emprimarytrack::TrackBit); -DECLARE_SOA_TABLE_VERSIONED(EMPrimaryTracks_001, "AOD", "EMPRIMARYTRACK", 1, //! primary charged track table for 2PC - o2::soa::Index<>, emprimarytrack::CollisionId, emprimarytrack::TrackId, +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryTracks_001, "AOD", "EMPRIMARYTRACK", 1, //! primary charged track table for 2PC + o2::soa::Index<>, /*emprimarytrack::CollisionId,*/ /*emprimarytrack::TrackId,*/ emprimarytrack::Signed1Pt, emprimarytrack::Eta, emprimarytrack::Phi, emprimarytrack::TrackBit, // dynamic column emprimarytrack::Sign, emprimarytrack::Pt); diff --git a/PWGEM/Dilepton/DataModel/lmeeMLTables.h b/PWGEM/Dilepton/DataModel/lmeeMLTables.h index 86a8ad1a7eb..ebc5309fe00 100644 --- a/PWGEM/Dilepton/DataModel/lmeeMLTables.h +++ b/PWGEM/Dilepton/DataModel/lmeeMLTables.h @@ -55,6 +55,10 @@ DECLARE_SOA_COLUMN(TPCNClsPID, tpcNClsPID, uint8_t); //! DECLARE_SOA_COLUMN(IsForValidation, isForValidation, bool); //! DECLARE_SOA_COLUMN(Sign, sign, short); //! DECLARE_SOA_COLUMN(P, p, float); //! +DECLARE_SOA_COLUMN(PtGen, ptGen, float); //! +DECLARE_SOA_COLUMN(EtaGen, etaGen, float); //! +DECLARE_SOA_COLUMN(PhiGen, phiGen, float); //! + // DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITS, meanClusterSizeITS, [](uint32_t itsClusterSizes) -> float { int total_cluster_size = 0, nl = 0; @@ -140,7 +144,8 @@ DECLARE_SOA_TABLE_VERSIONED(EMFwdTracksForML_000, "AOD", "EMFWDTRKML", 0, //! fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT, // fwdtrack::MCHBitMap, fwdtrack::MIDBitMap, fwdtrack::MIDBoards, - fwdtrack::MFTClusterSizesAndTrackFlags, emmlfwdtrack::Chi2MFT, emmlfwdtrack::NClustersMFT, mcparticle::PdgCode, emmlfwdtrack::IsPrimary, emmlfwdtrack::IsCorrectMatchMFTMCH); + fwdtrack::MFTClusterSizesAndTrackFlags, emmlfwdtrack::Chi2MFT, emmlfwdtrack::NClustersMFT, mcparticle::PdgCode, emmlfwdtrack::IsPrimary, emmlfwdtrack::IsCorrectMatchMFTMCH, + emmltrack::PtGen, emmltrack::EtaGen, emmltrack::PhiGen); using EMFwdTracksForML = EMFwdTracksForML_000; // iterators diff --git a/PWGEM/Dilepton/TableProducer/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/CMakeLists.txt index 109248797d6..617d07a86d1 100644 --- a/PWGEM/Dilepton/TableProducer/CMakeLists.txt +++ b/PWGEM/Dilepton/TableProducer/CMakeLists.txt @@ -41,6 +41,11 @@ o2physics_add_dpl_workflow(skimmer-primary-muon PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(skimmer-primary-muon-qc + SOURCES skimmerPrimaryMuonQC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(skimmer-primary-track SOURCES skimmerPrimaryTrack.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -101,3 +106,7 @@ o2physics_add_dpl_workflow(qvector3-dummy-otf PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(prefilter-dimuon + SOURCES prefilterDimuon.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/Dilepton/TableProducer/Converters/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/Converters/CMakeLists.txt index 9d130209e72..d3b100b2a31 100644 --- a/PWGEM/Dilepton/TableProducer/Converters/CMakeLists.txt +++ b/PWGEM/Dilepton/TableProducer/Converters/CMakeLists.txt @@ -50,6 +50,11 @@ o2physics_add_dpl_workflow(electron-converter5 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(electron-converter6 + SOURCES electronConverter6.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(track-converter1 SOURCES trackConverter1.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -60,6 +65,16 @@ o2physics_add_dpl_workflow(muon-converter1 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(muon-converter2 + SOURCES muonConverter2.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(muon-selfid-converter1 + SOURCES muonSelfIdConverter1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(mcparticle-converter1 SOURCES mcParticleConverter1.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGEM/Dilepton/TableProducer/Converters/electronConverter6.cxx b/PWGEM/Dilepton/TableProducer/Converters/electronConverter6.cxx new file mode 100644 index 00000000000..4f4550cccc9 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/electronConverter6.cxx @@ -0,0 +1,76 @@ +// 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 code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct electronConverter6 { + Produces track_006; + + void process(aod::EMPrimaryElectrons_005 const& tracks) + { + for (const auto& track : tracks) { + track_006(track.collisionId(), + track.trackId(), + track.sign(), + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + track.cYY(), + track.cZY(), + track.cZZ(), + track.tpcNClsFindable(), + track.tpcNClsFindableMinusFound(), + track.tpcNClsFindableMinusPID(), + track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), + track.tpcChi2NCl(), + track.tpcInnerParam(), + track.tpcSignal(), + track.tpcNSigmaEl(), + track.tpcNSigmaPi(), + track.tpcNSigmaKa(), + track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), + track.itsClusterSizes(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + track.isAssociatedToMPC(), + track.isAmbiguous(), + track.probElBDT(), + 0, + track.mcTunedTPCSignal()); + } // end of track loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"electron-converter6"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/muonConverter2.cxx b/PWGEM/Dilepton/TableProducer/Converters/muonConverter2.cxx new file mode 100644 index 00000000000..aea074131e3 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/muonConverter2.cxx @@ -0,0 +1,52 @@ +// 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 code produces muon table 001 from 000. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct muonConverter2 { + Produces muon_002; + + void process(aod::EMPrimaryMuons_001 const& muons) + { + for (const auto& muon : muons) { + muon_002( + muon.collisionId(), + muon.fwdtrackId(), muon.mfttrackId(), muon.mchtrackId(), muon.trackType(), + muon.pt(), muon.eta(), muon.phi(), muon.sign(), + muon.fwdDcaX(), muon.fwdDcaY(), muon.cXXatDCA(), muon.cYYatDCA(), muon.cXYatDCA(), + muon.ptMatchedMCHMID(), muon.etaMatchedMCHMID(), muon.phiMatchedMCHMID(), + muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), + muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), + muon.mftClusterSizesAndTrackFlags(), muon.chi2MFT(), muon.isAssociatedToMPC(), muon.isAmbiguous()); + } // end of muon loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"muon-converter2"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/muonSelfIdConverter1.cxx b/PWGEM/Dilepton/TableProducer/Converters/muonSelfIdConverter1.cxx new file mode 100644 index 00000000000..abbbe47695a --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/muonSelfIdConverter1.cxx @@ -0,0 +1,43 @@ +// 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 code produces muon table 001 from 000. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct muonSelfIdConverter1 { + Produces muon_001; + + void process(aod::EMGlobalMuonSelfIds_000 const& muons) + { + for (const auto& muon : muons) { + muon_001(std::vector{}, muon.globalMuonsWithSameMFTIds()); + } // end of muon loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"muon-selfid-converter1"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/trackConverter1.cxx b/PWGEM/Dilepton/TableProducer/Converters/trackConverter1.cxx index c6f7bfce634..7ae8f3d47da 100644 --- a/PWGEM/Dilepton/TableProducer/Converters/trackConverter1.cxx +++ b/PWGEM/Dilepton/TableProducer/Converters/trackConverter1.cxx @@ -32,12 +32,13 @@ struct trackConverter1 { void process(aod::EMPrimaryTracks_000 const& tracks) { for (const auto& track : tracks) { - track_001(track.collisionId(), - track.trackId(), - track.sign() / track.pt(), - track.eta(), - track.phi(), - track.trackBit()); + track_001( + // track.collisionId(), + // track.trackId(), + track.sign() / track.pt(), + track.eta(), + track.phi(), + track.trackBit()); } // end of track loop } }; diff --git a/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx b/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx index e60f9b54365..86c8fff432a 100644 --- a/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx +++ b/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx @@ -11,11 +11,10 @@ // // ======================== // -// This code produces reduced events for photon analyses. +// This code produces reduced mc info for dilepton analyses. // Please write to: daiki.sekihata@cern.ch #include "PWGEM/Dilepton/DataModel/dileptonTables.h" -// #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "Common/Core/TableHelper.h" @@ -39,7 +38,6 @@ struct AssociateMCInfoDilepton { enum SubSystem { kElectron = 0x1, kFwdMuon = 0x2, - // kPCM = 0x4, }; using MyCollisionsMC = soa::Join; @@ -51,15 +49,14 @@ struct AssociateMCInfoDilepton { Produces mceventlabels; Produces emmcparticles; Produces emmcgenvms; - // Produces v0legmclabels; Produces emprimaryelectronmclabels; Produces emprimarymuonmclabels; Produces emmftmclabels; Produces emdummydata; Configurable n_dummy_loop{"n_dummy_loop", 0, "for loop runs over n times"}; - Configurable down_scaling_omega{"down_scaling_omega", 1.1, "down scaling factor to store omega"}; - Configurable down_scaling_phi{"down_scaling_phi", 1.1, "down scaling factor to store phi"}; + Configurable down_scaling_omega{"down_scaling_omega", 1.0, "down scaling factor to store omega"}; + Configurable down_scaling_phi{"down_scaling_phi", 1.0, "down scaling factor to store phi"}; Configurable min_eta_gen_primary{"min_eta_gen_primary", -1.5, "min eta to store generated information"}; // smearing is applied at analysis stage. set wider value. Configurable max_eta_gen_primary{"max_eta_gen_primary", +1.5, "max eta to store generated information"}; // smearing is applied at analysis stage. set wider value. Configurable min_eta_gen_primary_fwd{"min_eta_gen_primary_fwd", -6.0, "min eta to store generated information"}; // smearing is applied at analysis stage. set wider value. @@ -130,7 +127,6 @@ struct AssociateMCInfoDilepton { SliceCache cache; Preslice perMcCollision = aod::mcparticle::mcCollisionId; - // Preslice perCollision_pcm = aod::v0photonkf::collisionId; Preslice perCollision_el = aod::emprimaryelectron::collisionId; Preslice perCollision_mu = aod::emprimarymuon::collisionId; @@ -683,23 +679,6 @@ struct AssociateMCInfoDilepton { skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, o2fwdtracks, o2mfttracks, nullptr, nullptr, emprimaryelectrons, emprimarymuons); } - // void processMC_Electron_FwdMuon_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, FwdTracksMC const& o2fwdtracks, MFTTracksMC const& o2mfttracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::EMPrimaryElectrons const& emprimaryelectrons, aod::EMPrimaryMuons const& emprimarymuons) - // { - // const uint8_t sysflag = kPCM | kElectron | kFwdMuon; - // skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, o2fwdtracks, o2mfttracks, v0photons, v0legs, emprimaryelectrons, emprimarymuons); - // } - - // void processMC_Electron_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::EMPrimaryElectrons const& emprimaryelectrons) - // { - // const uint8_t sysflag = kPCM | kElectron; - // skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, nullptr, v0photons, v0legs, emprimaryelectrons, nullptr); - // } - - // void processMC_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs) - // { - // skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, nullptr, v0photons, v0legs, nullptr, nullptr); - // } - void processGenDummy(MyCollisionsMC const&) { for (int i = 0; i < n_dummy_loop; i++) { @@ -718,9 +697,6 @@ struct AssociateMCInfoDilepton { PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron, "create em mc event table for Electron", false); PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_FwdMuon, "create em mc event table for Forward Muon", false); PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron_FwdMuon, "create em mc event table for Electron, FwdMuon", false); - // PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron_FwdMuon_PCM, "create em mc event table for PCM, Electron, FwdMuon", false); - // PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron_PCM, "create em mc event table for PCM, Electron", false); - // PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_PCM, "create em mc event table for PCM", false); PROCESS_SWITCH(AssociateMCInfoDilepton, processGenDummy, "produce dummy data", false); PROCESS_SWITCH(AssociateMCInfoDilepton, processDummy, "processDummy", true); }; diff --git a/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx index 4c92285441c..d35815b69f3 100644 --- a/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx +++ b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx @@ -299,7 +299,8 @@ struct AssociateDileptonToEMEvent { PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; PresliceUnsorted perCollision_mu = aod::emprimarymuon::collisionId; - Preslice perCollision_track = aod::emprimarytrack::collisionId; + // Preslice perCollision_track = aod::emprimarytrack::collisionId; + Preslice perCollision_track = aod::track::collisionId; void init(o2::framework::InitContext&) {} @@ -329,7 +330,7 @@ struct AssociateDileptonToEMEvent { fillEventId(collisions, tracks, prmmueventid, perCollision_mu); } - void processChargedTrack(aod::EMEvents const& collisions, aod::EMPrimaryTracks const& tracks) + void processChargedTrack(aod::EMEvents const& collisions, soa::Join const& tracks) { fillEventId(collisions, tracks, prmtrackeventid, perCollision_track); } diff --git a/PWGEM/Dilepton/TableProducer/prefilterDimuon.cxx b/PWGEM/Dilepton/TableProducer/prefilterDimuon.cxx new file mode 100644 index 00000000000..d965dde3061 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/prefilterDimuon.cxx @@ -0,0 +1,460 @@ +// 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 code produces information on prefilter for dimuons. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; + +struct prefilterDimuon { + using MyCollisions = soa::Join; + using MyCollision = MyCollisions::iterator; + + using MyTracks = soa::Join; + using MyTrack = MyTracks::iterator; + + Produces pfb_derived; + + // // Configurables + // 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 skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + // Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + } eventcuts; + + DimuonCut fDimuonCut; + struct : ConfigurableGroup { + std::string prefix = "dimuoncut_group"; + + // for deta-dphi prefilter + Configurable cfg_apply_detadphi_uls{"cfg_apply_detadphi_uls", false, "flag to apply generator deta-dphi elliptic cut in ULS"}; // region to be rejected + Configurable cfg_apply_detadphi_ls{"cfg_apply_detadphi_ls", false, "flag to apply generator deta-dphi elliptic cut in LS"}; // region to be rejected + Configurable cfg_min_deta_ls{"cfg_min_deta_ls", 0.04, "deta between 2 electrons (elliptic cut)"}; // region to be rejected + Configurable cfg_min_dphi_ls{"cfg_min_dphi_ls", 0.2, "dphi between 2 electrons (elliptic cut)"}; // region to be rejected + Configurable cfg_min_deta_uls{"cfg_min_deta_uls", 0.04, "deta between 2 electrons (elliptic cut)"}; // region to be rejected + Configurable cfg_min_dphi_uls{"cfg_min_dphi_uls", 0.2, "dphi between 2 electrons (elliptic cut)"}; // region to be rejected + + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -4.0, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", -2.5, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "min phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_mft{"cfg_min_ncluster_mft", 5, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + // Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_border_pt_for_chi2mchmft{"cfg_border_pt_for_chi2mchmft", 0, "border pt for different max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mftmch_lowPt{"cfg_max_matching_chi2_mftmch_lowPt", 8, "max chi2 for MFT-MCH matching for low pT"}; + Configurable cfg_max_matching_chi2_mftmch_highPt{"cfg_max_matching_chi2_mftmch_highPt", 40, "max chi2 for MFT-MCH matching for high pT"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; + Configurable cfg_max_rabs{"cfg_max_rabs", 89.5, "max Radius at the absorber end"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + } dimuoncuts; + + // o2::ccdb::CcdbApi ccdbApi; + // Service ccdb; + // int mRunNumber; + // float d_bz; + // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + void init(InitContext& /*context*/) + { + DefineEMEventCut(); + DefineDimuonCut(); + addhistograms(); + + // mRunNumber = 0; + // d_bz = 0; + + // ccdb->setURL(ccdburl); + // ccdb->setCaching(true); + // ccdb->setLocalObjectValidityChecking(); + // ccdb->setFatalWhenNull(false); + } + + // template + // void initCCDB(TCollision const& collision) + // { + // if (mRunNumber == collision.runNumber()) { + // return; + // } + + // // In case override, don't proceed, please - no CCDB access required + // if (d_bz_input > -990) { + // d_bz = d_bz_input; + // o2::parameters::GRPMagField grpmag; + // if (fabs(d_bz) > 1e-5) { + // grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + // } + // o2::base::Propagator::initFieldFromGRP(&grpmag); + // mRunNumber = collision.runNumber(); + // return; + // } + + // auto run3grp_timestamp = collision.timestamp(); + // o2::parameters::GRPObject* grpo = 0x0; + // o2::parameters::GRPMagField* grpmag = 0x0; + // if (!skipGRPOquery) + // grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + // 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 = collision.runNumber(); + // } + + ~prefilterDimuon() {} + + void addhistograms() + { + const AxisSpec axis_mass{380, 0.2, 4, "m_{#mu#mu} (GeV/c^{2})"}; + const AxisSpec axis_pair_pt{100, 0, 10, "p_{T,#mu#mu} (GeV/c)"}; + + // for pair + fRegistry.add("Pair/before/uls/hMvsPt", "m_{#mu#mu} vs. p_{T,#mu#mu}", kTH2D, {axis_mass, axis_pair_pt}, true); + fRegistry.add("Pair/before/uls/hDeltaEtaDeltaPhi", "#Delta#eta-#Delta#varphi between 2 tracks;#Delta#varphi (rad.);#Delta#eta;", kTH2D, {{180, -M_PI, M_PI}, {400, -2, +2}}, true); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lspp/"); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lsmm/"); + fRegistry.addClone("Pair/before/", "Pair/after/"); + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + } + + void DefineDimuonCut() + { + fDimuonCut = DimuonCut("fDimuonCut", "fDimuonCut"); + + // don't apply pair cut in prefilter! + + // for track + fDimuonCut.SetTrackType(dimuoncuts.cfg_track_type); + fDimuonCut.SetTrackPtRange(dimuoncuts.cfg_min_pt_track, dimuoncuts.cfg_max_pt_track); + fDimuonCut.SetTrackEtaRange(dimuoncuts.cfg_min_eta_track, dimuoncuts.cfg_max_eta_track); + fDimuonCut.SetTrackPhiRange(dimuoncuts.cfg_min_phi_track, dimuoncuts.cfg_max_phi_track); + fDimuonCut.SetNClustersMFT(dimuoncuts.cfg_min_ncluster_mft, 10); + fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); + fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); + // fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMaxMatchingChi2MCHMFTPtDep([&](float pt) { return (pt < dimuoncuts.cfg_border_pt_for_chi2mchmft ? dimuoncuts.cfg_max_matching_chi2_mftmch_lowPt : dimuoncuts.cfg_max_matching_chi2_mftmch_highPt); }); + fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); + fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); + fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); + fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + fDimuonCut.EnableTTCA(dimuoncuts.enableTTCA); + } + + std::unordered_map map_best_match_globalmuon; + std::unordered_map map_pfb; // map track.globalIndex -> prefilter bit + + SliceCache cache; + Preslice perCollision_track = aod::emprimarymuon::emeventId; + Partition posTracks = o2::aod::emprimarymuon::sign > int8_t(0); + Partition negTracks = o2::aod::emprimarymuon::sign < int8_t(0); + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + void processPFB(FilteredMyCollisions const& collisions, MyTracks const& tracks) + { + map_best_match_globalmuon = findBestMatchMap(tracks, fDimuonCut); + + for (const auto& track : tracks) { + map_pfb[track.globalIndex()] = 0; + } // end of track loop + + for (const auto& collision : collisions) { + // initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + bool is_cent_ok = true; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + is_cent_ok = false; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimarymuon::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimarymuon::emeventId, collision.globalIndex(), cache); + + if (!fEMEventCut.IsSelected(collision) || !is_cent_ok) { + for (const auto& pos : posTracks_per_coll) { + map_pfb[pos.globalIndex()] = 0; + } + for (const auto& neg : negTracks_per_coll) { + map_pfb[neg.globalIndex()] = 0; + } + continue; + } + + // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); + + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + if (!fDimuonCut.IsSelectedTrack(pos) || !fDimuonCut.IsSelectedTrack(neg)) { + continue; + } + if (!map_best_match_globalmuon[pos.globalIndex()] || !map_best_match_globalmuon[neg.globalIndex()]) { + continue; + } + + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v2(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float deta = pos.sign() * v1.Pt() > neg.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos.sign() * v1.Pt() > neg.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/uls/hDeltaEtaDeltaPhi"), dphi, deta); + + if (dimuoncuts.cfg_apply_detadphi_uls && std::pow(deta / dimuoncuts.cfg_min_deta_uls, 2) + std::pow(dphi / dimuoncuts.cfg_min_dphi_uls, 2) < 1.f) { + map_pfb[pos.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS); + map_pfb[neg.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS); + } + } // end of ULS pairing + + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + if (!fDimuonCut.IsSelectedTrack(pos1) || !fDimuonCut.IsSelectedTrack(pos2)) { + continue; + } + if (!map_best_match_globalmuon[pos1.globalIndex()] || !map_best_match_globalmuon[pos2.globalIndex()]) { + continue; + } + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float deta = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/before/lspp/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/lspp/hDeltaEtaDeltaPhi"), dphi, deta); + + if (dimuoncuts.cfg_apply_detadphi_ls && std::pow(deta / dimuoncuts.cfg_min_deta_ls, 2) + std::pow(dphi / dimuoncuts.cfg_min_dphi_ls, 2) < 1.f) { + map_pfb[pos1.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + map_pfb[pos2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + } + } // end of LS++ pairing + + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + if (!fDimuonCut.IsSelectedTrack(neg1) || !fDimuonCut.IsSelectedTrack(neg2)) { + continue; + } + if (!map_best_match_globalmuon[neg1.globalIndex()] || !map_best_match_globalmuon[neg2.globalIndex()]) { + continue; + } + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(neg1.pt(), neg1.eta(), neg1.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v2(neg2.pt(), neg2.eta(), neg2.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float deta = neg1.sign() * v1.Pt() > neg2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = neg1.sign() * v1.Pt() > neg2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/lsmm/hDeltaEtaDeltaPhi"), dphi, deta); + + if (dimuoncuts.cfg_apply_detadphi_ls && std::pow(deta / dimuoncuts.cfg_min_deta_ls, 2) + std::pow(dphi / dimuoncuts.cfg_min_dphi_ls, 2) < 1.f) { + map_pfb[neg1.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + map_pfb[neg2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + } + } // end of LS-- pairing + + } // end of collision loop + + for (const auto& track : tracks) { + // LOGF(info, "map_pfb[%d] = %d", track.globalIndex(), map_pfb[track.globalIndex()]); + pfb_derived(map_pfb[track.globalIndex()]); + } // end of track loop + + // check pfb. + for (const auto& collision : collisions) { + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimarymuon::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimarymuon::emeventId, collision.globalIndex(), cache); + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + if (!fDimuonCut.IsSelectedTrack(pos) || !fDimuonCut.IsSelectedTrack(neg)) { + continue; + } + if (!map_best_match_globalmuon[pos.globalIndex()] || !map_best_match_globalmuon[neg.globalIndex()]) { + continue; + } + if (map_pfb[pos.globalIndex()] != 0 || map_pfb[neg.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v2(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float deta = pos.sign() * v1.Pt() > neg.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos.sign() * v1.Pt() > neg.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/after/uls/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/uls/hDeltaEtaDeltaPhi"), dphi, deta); + } + + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + if (!fDimuonCut.IsSelectedTrack(pos1) || !fDimuonCut.IsSelectedTrack(pos2)) { + continue; + } + if (!map_best_match_globalmuon[pos1.globalIndex()] || !map_best_match_globalmuon[pos2.globalIndex()]) { + continue; + } + if (map_pfb[pos1.globalIndex()] != 0 || map_pfb[pos2.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float deta = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/after/lspp/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/lspp/hDeltaEtaDeltaPhi"), dphi, deta); + } + + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + if (!fDimuonCut.IsSelectedTrack(neg1) || !fDimuonCut.IsSelectedTrack(neg2)) { + continue; + } + if (!map_best_match_globalmuon[neg1.globalIndex()] || !map_best_match_globalmuon[neg2.globalIndex()]) { + continue; + } + if (map_pfb[neg1.globalIndex()] != 0 || map_pfb[neg2.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(neg1.pt(), neg1.eta(), neg1.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v2(neg2.pt(), neg2.eta(), neg2.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float deta = neg1.sign() * v1.Pt() > neg2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = neg1.sign() * v1.Pt() > neg2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/after/lsmm/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/lsmm/hDeltaEtaDeltaPhi"), dphi, deta); + } + + } // end of collision loop + map_pfb.clear(); + map_best_match_globalmuon.clear(); + } // end of process + PROCESS_SWITCH(prefilterDimuon, processPFB, "produce prefilter bit", false); + + void processDummy(MyTracks const& tracks) + { + for (int i = 0; i < tracks.size(); i++) { + pfb_derived(0); + } + } + PROCESS_SWITCH(prefilterDimuon, processDummy, "dummy", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"prefilter-dimuon"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx index c838228edcf..34c20624a9f 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx @@ -59,12 +59,40 @@ using MyTrack = MyTracks::iterator; using MyTracksMC = soa::Join; using MyTrackMC = MyTracksMC::iterator; +namespace o2::aod +{ +namespace pwgem::dilepton::recalculatedtofpid +{ +DECLARE_SOA_COLUMN(BetaRecalculated, betaRecalculated, float); +DECLARE_SOA_COLUMN(TOFNSigmaElRecalculated, tofNSigmaElRecalculated, float); +} // namespace pwgem::dilepton::recalculatedtofpid + +DECLARE_SOA_TABLE(EMTOFNSigmas, "AOD", "EMTOFNSIGMA", // make std::map in your tasks later. // Don't store this table in the derived data. + o2::aod::emprimaryelectron::CollisionId, o2::aod::emprimaryelectron::TrackId, + o2::aod::pwgem::dilepton::recalculatedtofpid::BetaRecalculated, o2::aod::pwgem::dilepton::recalculatedtofpid::TOFNSigmaElRecalculated); + +using EMTOFNSigma = EMTOFNSigmas::iterator; + +namespace pwgem::dilepton::mlpid +{ +DECLARE_SOA_COLUMN(BDTScore, bdtScore, float); +} // namespace pwgem::dilepton::mlpid + +DECLARE_SOA_TABLE(EMMLPIDs, "AOD", "EMMLPID", // make std::map in your tasks later. // Don't store this table in the derived data. + o2::aod::emprimaryelectron::CollisionId, o2::aod::emprimaryelectron::TrackId, o2::aod::pwgem::dilepton::mlpid::BDTScore); +using EMMLPID = EMMLPIDs::iterator; + +} // namespace o2::aod + struct skimmerPrimaryElectron { SliceCache cache; Preslice perCol = o2::aod::track::collisionId; Produces emprimaryelectrons; Produces emprimaryelectronscov; + Produces emtofs; + Produces emmlpids; + // Configurables 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"}; @@ -81,6 +109,8 @@ struct skimmerPrimaryElectron { Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable minchi2tpc{"minchi2tpc", 0.0, "min. chi2/NclsTPC"}; + Configurable minchi2its{"minchi2its", 0.0, "min. chi2/NclsITS"}; Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; Configurable minpt{"minpt", 0.15, "min pt for ITS-TPC track"}; @@ -104,16 +134,17 @@ struct skimmerPrimaryElectron { Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; Configurable storeOnlyTrueElectronMC{"storeOnlyTrueElectronMC", false, "Flag to store only true electron in MC"}; Configurable minNelectron{"minNelectron", 0, "min number of electron candidates per collision"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks only for MC. switch ON only if needed."}; Configurable useTOFNSigmaDeltaBC{"useTOFNSigmaDeltaBC", false, "Flag to shift delta BC for TOF n sigma (only with TTCA)"}; // configuration for PID ML Configurable usePIDML{"usePIDML", false, "Flag to use PID ML"}; Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; - Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; - Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; - Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; - Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95, 0.95, 0.7, 0.7, 0.8, 0.8, 0.7, 0.7}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"tpcInnerParam", "tpcNClsFound", "tpcChi2NCl", "tpcNSigmaEl", "tofNSigmaEl", "meanClusterSizeITSobCos"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "tpcInnerParam", "Names of ML model binning feature"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; @@ -288,11 +319,11 @@ struct skimmerPrimaryElectron { return false; } - if (!track.hasITS() || !track.hasTPC()) { + if (!track.hasITS()) { return false; } - if (track.itsChi2NCl() < 0.f || maxchi2its < track.itsChi2NCl()) { + if (track.itsChi2NCl() < minchi2its || maxchi2its < track.itsChi2NCl()) { return false; } if (track.itsNCls() < min_ncluster_its) { @@ -302,24 +333,30 @@ struct skimmerPrimaryElectron { return false; } - if (track.tpcChi2NCl() < 0.f || maxchi2tpc < track.tpcChi2NCl()) { + if (!includeITSsa && (!track.hasITS() || !track.hasTPC())) { return false; } - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } + if (track.hasTPC()) { + if (track.tpcChi2NCl() < minchi2tpc || maxchi2tpc < track.tpcChi2NCl()) { + return false; + } - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { - return false; - } + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } - if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { - return false; + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } } o2::dataformats::DCA mDcaInfoCov; @@ -372,25 +409,21 @@ struct skimmerPrimaryElectron { } template - bool isElectron(TCollision const& collision, TTrack const& track, float& probaEl) + void fillMLPIDTable(TCollision const& collision, TTrack const& track) { - probaEl = 1.f; if (usePIDML) { - if (!isElectron_TOFif(track, collision)) { - probaEl = 0.0; - return false; - } o2::dataformats::DCA mDcaInfoCov; mDcaInfoCov.set(999, 999, 999, 999, 999); auto trackParCov = getTrackParCov(track); trackParCov.setPID(o2::track::PID::Electron); - mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); - mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); - if (!isPropOK) { - probaEl = 0.0; - return false; - } + + // mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + // mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + // bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + // if (!isPropOK) { + // probaEl = 0.0; + // return false; + // } std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); @@ -402,10 +435,47 @@ struct skimmerPrimaryElectron { } // LOGF(info, "track.tpcInnerParam() = %f (GeV/c), pbin = %d", track.tpcInnerParam(), pbin); - probaEl = mlResponseSingleTrack.getModelOutput(inputFeatures, pbin)[1]; // 0: hadron, 1:electron - return probaEl > cutsMl.value[pbin]; + float probaEl = mlResponseSingleTrack.getModelOutput(inputFeatures, pbin)[1]; // 0: hadron, 1:electron + mapProbaEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; + emmlpids(collision.globalIndex(), track.globalIndex(), probaEl); + } else { + mapProbaEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = 1.0; + emmlpids(collision.globalIndex(), track.globalIndex(), 1.0); + } + } + + template + bool isElectron(TCollision const& collision, TTrack const& track) + { + if (usePIDML) { + if (isElectron_TOFif(track, collision)) { + auto trackParCov = getTrackParCov(track); + // trackParCov.setPID(o2::track::PID::Electron); + // o2::dataformats::DCA mDcaInfoCov; + // mDcaInfoCov.set(999, 999, 999, 999, 999); + // mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + // mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + // bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + // if (!isPropOK) { + // probaEl = 0.0; + // return false; + // } + // std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + + int pbin = lower_bound(binsMl.value.begin(), binsMl.value.end(), binningFeature) - binsMl.value.begin() - 1; + if (pbin < 0) { + pbin = 0; + } else if (static_cast(binsMl.value.size()) - 2 < pbin) { + pbin = static_cast(binsMl.value.size()) - 2; + } + // LOGF(info, "track.tpcInnerParam() = %f (GeV/c), pbin = %d", track.tpcInnerParam(), pbin); + + return mapProbaEl[std::make_pair(collision.globalIndex(), track.globalIndex())] > cutsMl.value[pbin]; + } else { + return false; + } } else { - probaEl = 1.f; return isElectron_TPChadrej(track, collision) || isElectron_TOFreq(track, collision); } } @@ -456,7 +526,7 @@ struct skimmerPrimaryElectron { } template - void fillTrackTable(TCollision const& collision, TTrack const& track, const float probaEl) + void fillTrackTable(TCollision const& collision, TTrack const& track) { if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::pair{collision.globalIndex(), track.globalIndex()}) == stored_trackIds.end()) { o2::dataformats::DCA mDcaInfoCov; @@ -479,6 +549,7 @@ struct skimmerPrimaryElectron { float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; float beta = mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + float probaEl = mapProbaEl[std::make_pair(collision.globalIndex(), track.globalIndex())]; bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); float mcTunedTPCSignal = 0.f; @@ -495,7 +566,7 @@ struct skimmerPrimaryElectron { beta, tofNSigmaEl, track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), - isAssociatedToMPC, false, probaEl, mcTunedTPCSignal); + isAssociatedToMPC, false, probaEl, track.flags(), mcTunedTPCSignal); emprimaryelectronscov( trackParCov.getX(), @@ -612,11 +683,12 @@ struct skimmerPrimaryElectron { float beta = track.length() / (track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()) - mapCollisionTime[collision.globalIndex()]) / (TMath::C() * 1e+2 * 1e-12); mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = tofNSigmaEl; mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = beta; + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); } else { mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); } - } // end of track loop } // end of collision loop } else { @@ -628,6 +700,7 @@ struct skimmerPrimaryElectron { } mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); } } // end of track loop } // end of collision loop @@ -642,6 +715,7 @@ struct skimmerPrimaryElectron { } mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); } // end of track loop } // end of collision loop } else { @@ -653,6 +727,7 @@ struct skimmerPrimaryElectron { } mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); } } // end of track loop } // end of collision loop @@ -667,14 +742,14 @@ struct skimmerPrimaryElectron { Partition posTracks = o2::aod::track::signed1Pt > 0.f; Partition negTracks = o2::aod::track::signed1Pt < 0.f; - std::map, float> mapProbEl; // map pair(collisionId, trackId) -> probaEl std::unordered_multimap multiMapTracksPerCollision; // collisionId -> trackIds std::unordered_map mapCollisionTime; std::unordered_map mapCollisionTimeError; - std::map, float> mapTOFNsigmaReassociated; - std::map, float> mapTOFBetaReassociated; + std::map, float> mapProbaEl; // map pair(collisionId, trackId) -> probaEl + std::map, float> mapTOFNsigmaReassociated; // map pair(collisionId, trackId) -> tof n sigma + std::map, float> mapTOFBetaReassociated; // map pair(collisionId, trackId) -> tof beta // ---------- for data ---------- @@ -697,14 +772,13 @@ struct skimmerPrimaryElectron { auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); for (const auto& track : tracks_per_coll) { - float probaEl = 1.0; + fillMLPIDTable(collision, track); if (!checkTrack(collision, track)) { continue; } - if (!isElectron(collision, track, probaEl)) { + if (!isElectron(collision, track)) { continue; } - mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } } // end of collision loop @@ -718,12 +792,12 @@ struct skimmerPrimaryElectron { auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); for (auto it = range_electrons.first; it != range_electrons.second; it++) { auto track = tracks.rawIteratorAt(it->second); - fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + fillTrackTable(collision, track); } } } // end of collision loop - mapProbEl.clear(); + mapProbaEl.clear(); multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); @@ -763,14 +837,13 @@ struct skimmerPrimaryElectron { for (const auto& trackId : trackIdsThisCollision) { auto track = trackId.template track_as(); - float probaEl = 1.0; + fillMLPIDTable(collision, track); if (!checkTrack(collision, track)) { continue; } - if (!isElectron(collision, track, probaEl)) { + if (!isElectron(collision, track)) { continue; } - mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } } // end of collision loop @@ -784,12 +857,12 @@ struct skimmerPrimaryElectron { auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); for (auto it = range_electrons.first; it != range_electrons.second; it++) { auto track = tracks.rawIteratorAt(it->second); - fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + fillTrackTable(collision, track); } } } // end of collision loop - mapProbEl.clear(); + mapProbaEl.clear(); multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); @@ -821,14 +894,13 @@ struct skimmerPrimaryElectron { auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); for (const auto& track : tracks_per_coll) { - float probaEl = 1.0; + fillMLPIDTable(collision, track); if (!checkTrack(collision, track)) { continue; } - if (!isElectron(collision, track, probaEl)) { + if (!isElectron(collision, track)) { continue; } - mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } @@ -843,12 +915,12 @@ struct skimmerPrimaryElectron { auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); for (auto it = range_electrons.first; it != range_electrons.second; it++) { auto track = tracks.rawIteratorAt(it->second); - fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + fillTrackTable(collision, track); } } } // end of collision loop - mapProbEl.clear(); + mapProbaEl.clear(); multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); @@ -888,14 +960,13 @@ struct skimmerPrimaryElectron { for (const auto& trackId : trackIdsThisCollision) { auto track = trackId.template track_as(); - float probaEl = 1.0; + fillMLPIDTable(collision, track); if (!checkTrack(collision, track)) { continue; } - if (!isElectron(collision, track, probaEl)) { + if (!isElectron(collision, track)) { continue; } - mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } } // end of collision loop @@ -909,12 +980,12 @@ struct skimmerPrimaryElectron { auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); for (auto it = range_electrons.first; it != range_electrons.second; it++) { auto track = tracks.rawIteratorAt(it->second); - fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + fillTrackTable(collision, track); } } } // end of collision loop - mapProbEl.clear(); + mapProbaEl.clear(); multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); @@ -950,14 +1021,13 @@ struct skimmerPrimaryElectron { auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); for (const auto& track : tracks_per_coll) { - float probaEl = 1.0; + fillMLPIDTable(collision, track); if (!checkTrack(collision, track)) { continue; } - if (!isElectron(collision, track, probaEl)) { + if (!isElectron(collision, track)) { continue; } - mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } } // end of collision loop @@ -971,12 +1041,12 @@ struct skimmerPrimaryElectron { auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); for (auto it = range_electrons.first; it != range_electrons.second; it++) { auto track = tracks.rawIteratorAt(it->second); - fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + fillTrackTable(collision, track); } } } // end of collision loop - mapProbEl.clear(); + mapProbaEl.clear(); multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); @@ -1016,14 +1086,13 @@ struct skimmerPrimaryElectron { for (const auto& trackId : trackIdsThisCollision) { auto track = trackId.template track_as(); - float probaEl = 1.0; + fillMLPIDTable(collision, track); if (!checkTrack(collision, track)) { continue; } - if (!isElectron(collision, track, probaEl)) { + if (!isElectron(collision, track)) { continue; } - mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } } // end of collision loop @@ -1037,12 +1106,12 @@ struct skimmerPrimaryElectron { auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); for (auto it = range_electrons.first; it != range_electrons.second; it++) { auto track = tracks.rawIteratorAt(it->second); - fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + fillTrackTable(collision, track); } } } // end of collision loop - mapProbEl.clear(); + mapProbaEl.clear(); multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); @@ -1075,22 +1144,38 @@ struct prefilterPrimaryElectron { Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; Configurable max_dcaxy{"max_dcaxy", 1.0, "DCAxy To PV for loose track sample"}; Configurable max_dcaz{"max_dcaz", 1.0, "DCAz To PV for loose track sample"}; - Configurable minpt{"minpt", 0.1, "min pt for ITS-TPC track"}; - Configurable maxeta{"maxeta", 1.2, "eta acceptance for loose track sample"}; + Configurable minpt{"minpt", 0.01, "min pt for ITS-TPC track"}; + Configurable maxeta{"maxeta", 0.9, "eta acceptance for loose track sample"}; Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; - Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable mincrossedrows{"mincrossedrows", 40, "min crossed rows"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 0.7f, "max fraction of shared clusters in TPC"}; Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; Configurable maxchi2its{"maxchi2its", 36.0, "max chi2/NclsITS"}; - Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_its{"min_ncluster_its", 2, "min ncluster its"}; Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.0, "max. TPC n sigma for electron inclusion"}; + Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", 3.0, "max. TOF n sigma for electron inclusion"}; // TOFif + Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 0, "max. TPC n sigma for pion exclusion"}; + Configurable minTPCNsigmaPi{"minTPCNsigmaPi", 0, "min. TPC n sigma for pion exclusion"}; + Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", 0, "max. TPC n sigma for kaon exclusion"}; + Configurable minTPCNsigmaKa{"minTPCNsigmaKa", 0, "min. TPC n sigma for kaon exclusion"}; + Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 0, "max. TPC n sigma for proton exclusion"}; + Configurable minTPCNsigmaPr{"minTPCNsigmaPr", 0, "min. TPC n sigma for proton exclusion"}; + Configurable min_pin_for_pion_rejection{"min_pin_for_pion_rejection", 0.0, "pion rejection is applied above this pin"}; // this is used only in TOFreq + Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 0.5, "pion rejection is applied below this pin"}; Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; Configurable intercept{"intercept", -0.0280, "intercept for m vs. phiv"}; Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; + // Configurable useTOFNSigmaDeltaBC{"useTOFNSigmaDeltaBC", false, "Flag to shift delta BC for TOF n sigma (only with TTCA)"}; + + Configurable usePIDML{"usePIDML", false, "Flag to use PID ML"}; + Configurable> binsMl{"binsMl", std::vector{0.1, 0.15, 0.2, 0.25, 0.4, 0.8, 1.6, 2.0, 20}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.85, 0.85, 0.6, 0.6, 0.7, 0.7, 0.6, 0.6}, "ML cuts per bin"}; + Configurable nameBinningFeature{"nameBinningFeature", "tpcInnerParam", "Names of ML model binning feature"}; + o2::analysis::MlResponseO2Track mlResponseSingleTrack; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; const std::vector max_mee_vec{0.02, 0.04, 0.06, 0.08, 0.10, 0.12, 0.14}; @@ -1103,7 +1188,7 @@ struct prefilterPrimaryElectron { const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; o2::base::MatLayerCylSet* lut = nullptr; - void init(InitContext&) + void init(InitContext& initContext) { mRunNumber = 0; d_bz = 0; @@ -1116,13 +1201,52 @@ struct prefilterPrimaryElectron { if (!doprocessDummy && fillQAHistogram) { addHistograms(); } + + // BDT files are inherited from skimmer-primary-electron task above. + getTaskOptionValue(initContext, "skimmer-primary-electron", "usePIDML", usePIDML.value, true); + // getTaskOptionValue(initContext, "skimmer-primary-electron", "useTOFNSigmaDeltaBC", useTOFNSigmaDeltaBC.value, true); + + if (usePIDML) { + getTaskOptionValue(initContext, "skimmer-primary-electron", "binsMl.value", binsMl.value, true); + // getTaskOptionValue(initContext, "skimmer-primary-electron", "cutsMl.value", cutsMl.value, true); + getTaskOptionValue(initContext, "skimmer-primary-electron", "nameBinningFeature", nameBinningFeature.value, true); + } + + if (usePIDML) { + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + const std::vector labelsClasses = {"Background", "Signal"}; + const uint32_t nBinsMl = binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = 0.0; + cutsMlArr[i][1] = cutsMl.value[i]; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(binsMl.value, cutsMl, cutDirMl, nClassesMl); + + // if (loadModelsFromCCDB) { + // ccdbApi.init(ccdburl); + // mlResponseSingleTrack.setModelPathsCCDB(onnxFileNames.value, ccdbApi, onnxPathsCCDB.value, timestampCCDB.value); + // } else { + // mlResponseSingleTrack.setModelPathsLocal(onnxFileNames.value); + // } + // mlResponseSingleTrack.cacheInputFeaturesIndices(namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(nameBinningFeature); + // mlResponseSingleTrack.init(enableOptimizations.value); + // mlResponseSingleTrack.useReassociatedTOF(useTOFNSigmaDeltaBC.value); + } // end of PID ML } void addHistograms() { fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); - fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, 2 * M_PI}, {80, -2.0f, 2.0f}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, 2 * M_PI}, {40, -1.0f, 1.0f}}, false); fRegistry.add("Track/hTPCNsigmaEl", "loose track TPC PID", kTH2F, {{1000, 0.f, 10}, {100, -5, +5}}); + fRegistry.add("Track/hTOFNsigmaEl", "loose track TOF PID", kTH2F, {{1000, 0.f, 10}, {100, -5, +5}}); + fRegistry.add("Track/hProbElBDT", "BDT score", kTH2F, {{1000, 0.f, 10}, {100, 0, 1}}); fRegistry.add("Pair/before/uls/hMvsPt", "mass vs. pT;m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{500, 0, 0.5}, {100, 0, 1}}); fRegistry.add("Pair/before/uls/hMvsPhiV", "mass vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0.f, M_PI}, {100, 0, 0.1}}); fRegistry.addClone("Pair/before/uls/", "Pair/before/lspp/"); @@ -1203,9 +1327,10 @@ struct prefilterPrimaryElectron { return false; } - if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { - return false; - } + // if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + // return false; + // } + if (track.tpcNClsFound() < min_ncluster_tpc) { return false; } @@ -1259,6 +1384,87 @@ struct prefilterPrimaryElectron { return true; } + template + bool isElectron(TCollision const& collision, TTrack const& track) + { + if (usePIDML) { + if (isElectron_TOFif(track, collision)) { + auto trackParCov = getTrackParCov(track); + // trackParCov.setPID(o2::track::PID::Electron); + // o2::dataformats::DCA mDcaInfoCov; + // mDcaInfoCov.set(999, 999, 999, 999, 999); + // mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + // mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + // bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + // if (!isPropOK) { + // probaEl = 0.0; + // return false; + // } + // std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + + int pbin = lower_bound(binsMl.value.begin(), binsMl.value.end(), binningFeature) - binsMl.value.begin() - 1; + if (pbin < 0) { + pbin = 0; + } else if (static_cast(binsMl.value.size()) - 2 < pbin) { + pbin = static_cast(binsMl.value.size()) - 2; + } + // LOGF(info, "track.tpcInnerParam() = %f (GeV/c), pbin = %d", track.tpcInnerParam(), pbin); + + return mapProbaEl[std::make_pair(collision.globalIndex(), track.globalIndex())] > cutsMl.value[pbin]; + } else { + return false; + } + } else { + return isElectron_TPChadrej(track, collision) || isElectron_TOFreq(track, collision); + } + } + + template + bool isElectron_TOFif(TTrack const& track, TCollision const& collision) + { + // collisionId must be collisionId after reassociation. + // track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCascade.globalBC()) + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + bool is_EL_TPC = minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl; + bool is_EL_TOF = track.hasTOF() ? (std::fabs(tofNSigmaEl) < maxTOFNsigmaEl) : true; // TOFif + return is_EL_TPC && is_EL_TOF; + } + + template + bool isElectron_TPChadrej(TTrack const& track, TCollision const& collision) + { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { + return false; + } + if (minTPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < maxTPCNsigmaKa) { + return false; + } + if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { + return false; + } + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(tofNSigmaEl))) { + return false; + } + return true; + } + + template + bool isElectron_TOFreq(TTrack const& track, TCollision const& collision) + { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && (min_pin_for_pion_rejection < track.tpcInnerParam() && track.tpcInnerParam() < max_pin_for_pion_rejection)) { + return false; + } + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl; + } + template bool reconstructPC(TCollision const& collision, TTrack1 const& ele, TTrack2 const& pos) { @@ -1306,6 +1512,10 @@ struct prefilterPrimaryElectron { } } + std::map, float> mapProbaEl; // map pair(collisionId, trackId) -> probaEl + std::map, float> mapTOFNsigmaReassociated; // map pair(collisionId, trackId) -> tof n sigma + std::map, float> mapTOFBetaReassociated; // map pair(collisionId, trackId) -> tof beta + Preslice trackIndicesPerCollision = aod::track_association::collisionId; Filter trackFilter = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; @@ -1316,8 +1526,16 @@ struct prefilterPrimaryElectron { Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0); Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0); - void processPrefilter_TTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const&, aod::EMPrimaryElectrons const& primaryelectrons, aod::TrackAssoc const& trackIndices) + void processPrefilter_TTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const&, aod::EMPrimaryElectrons const& primaryelectrons, aod::TrackAssoc const& trackIndices, aod::EMTOFNSigmas const& emtofs, aod::EMMLPIDs const& emmlpids) { + for (const auto& emtof : emtofs) { + mapTOFNsigmaReassociated[std::make_pair(emtof.collisionId(), emtof.trackId())] = emtof.tofNSigmaElRecalculated(); + mapTOFBetaReassociated[std::make_pair(emtof.collisionId(), emtof.trackId())] = emtof.betaRecalculated(); + } + for (const auto& emmlpid : emmlpids) { + mapProbaEl[std::make_pair(emmlpid.collisionId(), emmlpid.trackId())] = emmlpid.bdtScore(); + } + std::unordered_map pfb_map; // map track.globalIndex -> prefilter bit for (const auto& collision : collisions) { @@ -1341,9 +1559,15 @@ struct prefilterPrimaryElectron { if (!checkTrack(collision, track)) { continue; } + if (!isElectron(collision, track)) { + continue; + } if (fillQAHistogram) { fRegistry.fill(HIST("Track/hPt"), track.pt()); fRegistry.fill(HIST("Track/hEtaPhi"), track.phi(), track.eta()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + fRegistry.fill(HIST("Track/hProbElBDT"), track.tpcInnerParam(), mapProbaEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); } if (track.sign() > 0) { posTracks_per_coll.emplace_back(track); @@ -1382,11 +1606,6 @@ struct prefilterPrimaryElectron { fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); } - if (v12.M() < max_mee_vec.at(static_cast(max_mee_vec.size()) - 1)) { - if (fillQAHistogram) { - fRegistry.fill(HIST("Track/hTPCNsigmaEl"), ele.tpcInnerParam(), ele.tpcNSigmaEl()); - } - } for (int i = 0; i < static_cast(max_mee_vec.size()); i++) { if (v12.M() < max_mee_vec.at(i)) { pfb_map[empos.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV) + i)); @@ -1429,11 +1648,6 @@ struct prefilterPrimaryElectron { fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); } - if (v12.M() < max_mee_vec.at(static_cast(max_mee_vec.size()) - 1)) { - if (fillQAHistogram) { - fRegistry.fill(HIST("Track/hTPCNsigmaEl"), pos.tpcInnerParam(), pos.tpcNSigmaEl()); - } - } for (int i = 0; i < static_cast(max_mee_vec.size()); i++) { if (v12.M() < max_mee_vec.at(i)) { pfb_map[emele.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV) + i)); @@ -1544,11 +1758,22 @@ struct prefilterPrimaryElectron { } // end of collision loop pfb_map.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); + mapProbaEl.clear(); } PROCESS_SWITCH(prefilterPrimaryElectron, processPrefilter_TTCA, "process prefilter with TTCA", false); - void processPrefilter_SA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&, aod::EMPrimaryElectrons const& primaryelectrons) + void processPrefilter_SA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&, aod::EMPrimaryElectrons const& primaryelectrons, aod::EMTOFNSigmas const& emtofs, aod::EMMLPIDs const& emmlpids) { + for (const auto& emtof : emtofs) { + mapTOFNsigmaReassociated[std::make_pair(emtof.collisionId(), emtof.trackId())] = emtof.tofNSigmaElRecalculated(); + mapTOFBetaReassociated[std::make_pair(emtof.collisionId(), emtof.trackId())] = emtof.betaRecalculated(); + } + for (const auto& emmlpid : emmlpids) { + mapProbaEl[std::make_pair(emmlpid.collisionId(), emmlpid.trackId())] = emmlpid.bdtScore(); + } + std::unordered_map pfb_map; // map track.globalIndex -> prefilter bit for (const auto& collision : collisions) { @@ -1568,18 +1793,30 @@ struct prefilterPrimaryElectron { if (!checkTrack(collision, pos)) { // track cut is applied to loose sample continue; } + if (!isElectron(collision, pos)) { + continue; + } if (fillQAHistogram) { fRegistry.fill(HIST("Track/hPt"), pos.pt()); fRegistry.fill(HIST("Track/hEtaPhi"), pos.phi(), pos.eta()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), pos.tpcInnerParam(), pos.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), pos.tpcInnerParam(), mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), pos.globalIndex())]); + fRegistry.fill(HIST("Track/hProbElBDT"), pos.tpcInnerParam(), mapProbaEl[std::make_pair(collision.globalIndex(), pos.globalIndex())]); } } for (const auto& neg : negTracks_per_coll) { if (!checkTrack(collision, neg)) { // track cut is applied to loose sample continue; } + if (!isElectron(collision, neg)) { + continue; + } if (fillQAHistogram) { fRegistry.fill(HIST("Track/hPt"), neg.pt()); fRegistry.fill(HIST("Track/hEtaPhi"), neg.phi(), neg.eta()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), neg.tpcInnerParam(), neg.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), neg.tpcInnerParam(), mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), neg.globalIndex())]); + fRegistry.fill(HIST("Track/hProbElBDT"), neg.tpcInnerParam(), mapProbaEl[std::make_pair(collision.globalIndex(), neg.globalIndex())]); } } @@ -1588,6 +1825,9 @@ struct prefilterPrimaryElectron { if (!checkTrack(collision, ele)) { // track cut is applied to loose sample continue; } + if (!isElectron(collision, ele)) { + continue; + } if (empos.trackId() == ele.globalIndex()) { continue; } @@ -1600,11 +1840,6 @@ struct prefilterPrimaryElectron { fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); } - if (v12.M() < max_mee_vec.at(static_cast(max_mee_vec.size()) - 1)) { - if (fillQAHistogram) { - fRegistry.fill(HIST("Track/hTPCNsigmaEl"), ele.tpcInnerParam(), ele.tpcNSigmaEl()); - } - } for (int i = 0; i < static_cast(max_mee_vec.size()); i++) { if (v12.M() < max_mee_vec.at(i)) { pfb_map[empos.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV) + i)); @@ -1622,6 +1857,9 @@ struct prefilterPrimaryElectron { if (!checkTrack(collision, pos)) { // track cut is applied to loose sample continue; } + if (!isElectron(collision, pos)) { + continue; + } if (emele.trackId() == pos.globalIndex()) { continue; } @@ -1634,11 +1872,6 @@ struct prefilterPrimaryElectron { fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); } - if (v12.M() < max_mee_vec.at(static_cast(max_mee_vec.size()) - 1)) { - if (fillQAHistogram) { - fRegistry.fill(HIST("Track/hTPCNsigmaEl"), pos.tpcInnerParam(), pos.tpcNSigmaEl()); - } - } for (int i = 0; i < static_cast(max_mee_vec.size()); i++) { if (v12.M() < max_mee_vec.at(i)) { pfb_map[emele.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV) + i)); @@ -1656,6 +1889,9 @@ struct prefilterPrimaryElectron { if (!checkTrack(collision, pos)) { // track cut is applied to loose sample continue; } + if (!isElectron(collision, pos)) { + continue; + } if (empos.trackId() == pos.globalIndex()) { continue; } @@ -1675,6 +1911,9 @@ struct prefilterPrimaryElectron { if (!checkTrack(collision, ele)) { // track cut is applied to loose sample continue; } + if (!isElectron(collision, ele)) { + continue; + } if (emele.trackId() == ele.globalIndex()) { continue; } @@ -1717,6 +1956,9 @@ struct prefilterPrimaryElectron { } // end of collision loop pfb_map.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); + mapProbaEl.clear(); } PROCESS_SWITCH(prefilterPrimaryElectron, processPrefilter_SA, "process prefilter standalone", false); diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectronQC.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectronQC.cxx index edae6eba189..b50a0df8bab 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectronQC.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectronQC.cxx @@ -75,13 +75,14 @@ struct skimmerPrimaryElectronQC { struct : ConfigurableGroup { std::string prefix = "trackcut"; Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 40, "min. crossed rows"}; + Configurable mincrossedrows{"mincrossedrows", 0, "min. crossed rows"}; Configurable min_ncluster_its{"min_ncluster_its", 2, "min ncluster its"}; Configurable min_ncluster_itsib{"min_ncluster_itsib", 0, "min ncluster itsib"}; - Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.0, "min. TPC Ncr/Nf ratio"}; Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; - Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; - Configurable maxchi2its{"maxchi2its", 36.0, "max. chi2/NclsITS"}; + Configurable maxchi2tpc{"maxchi2tpc", 1e+10, "max. chi2/NclsTPC"}; + Configurable minchi2tpc{"minchi2tpc", -1e+10, "min. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 1e+10, "max. chi2/NclsITS"}; // actual maximum is 36 in the reconstruction. Configurable minchi2its{"minchi2its", -1e+10, "min. chi2/NclsITS"}; Configurable minpt{"minpt", 0.05, "min pt for ITS-TPC track"}; Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; @@ -94,9 +95,9 @@ struct skimmerPrimaryElectronQC { struct : ConfigurableGroup { std::string prefix = "tighttrackcut"; - Configurable min_ncluster_tpc_pid{"min_ncluster_tpc_pid", 60, "min ncluster tpc used for PID"}; + Configurable min_ncluster_tpc_pid{"min_ncluster_tpc_pid", 0, "min ncluster tpc used for PID"}; Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 100, "min. crossed rows"}; + Configurable mincrossedrows{"mincrossedrows", 120, "min. crossed rows"}; Configurable min_ncluster_its{"min_ncluster_its", 5, "min ncluster its"}; Configurable min_ncluster_itsib{"min_ncluster_itsib", 3, "min ncluster itsib"}; Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; @@ -309,7 +310,7 @@ struct skimmerPrimaryElectronQC { } if (track.hasTPC()) { - if (track.tpcChi2NCl() < 0.f || trackcut.maxchi2tpc < track.tpcChi2NCl()) { + if (track.tpcChi2NCl() < trackcut.minchi2tpc || trackcut.maxchi2tpc < track.tpcChi2NCl()) { return false; } @@ -501,7 +502,7 @@ struct skimmerPrimaryElectronQC { track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), // trackParCov.getTgl(), - isAssociatedToMPC, false, probaEl, mcTunedTPCSignal); + isAssociatedToMPC, false, probaEl, track.flags(), mcTunedTPCSignal); emprimaryelectronscov( trackParCov.getX(), diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMFTTrack.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMFTTrack.cxx index 77f8d6b692c..83835874d87 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMFTTrack.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMFTTrack.cxx @@ -17,7 +17,6 @@ #include "Common/Core/TableHelper.h" #include "Common/Core/fwdtrackUtilities.h" -// #include "Common/DataModel/CollisionAssociationTables.h" #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" @@ -59,6 +58,7 @@ struct skimmerPrimaryMFTTrack { SliceCache cache; Preslice perCol = o2::aod::fwdtrack::collisionId; Produces emprimarytracks; + Produces prmtrackeventidtmp; // Configurables Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -67,7 +67,7 @@ struct skimmerPrimaryMFTTrack { Configurable fillQAHistogram{"fillQAHistogram", true, "flag to fill QA histograms"}; - Configurable cfgPtMin{"cfgPtMin", 0.2, "min pt for MFTsa track"}; + Configurable cfgPtMin{"cfgPtMin", 0.1, "min pt for MFTsa track"}; Configurable cfgPtMax{"cfgPtMax", 1e+10, "max pt for MFTsa track"}; Configurable cfgEtaMin{"cfgEtaMin", -4, "min eta acceptance"}; Configurable cfgEtaMax{"cfgEtaMax", -2, "max eta acceptance"}; @@ -197,13 +197,16 @@ struct skimmerPrimaryMFTTrack { // As minimal cuts, following cuts are applied. The cut values are hardcoded on the purpose for consistent bit operation. // Ncls MFT >= 5 - // chi2/ndf MFT < 5 + // chi2/ndf MFT < 4 // |dcaXY| < 0.06 cm - if (mfttrack.nClusters() < 6 || mfttrack.chi2() / ndf > 5.f || std::fabs(dcaXY) > 0.05) { + if (mfttrack.nClusters() < 5 || mfttrack.chi2() / ndf > 4.f || std::fabs(dcaXY) > 0.06) { return; } + if (mfttrack.nClusters() >= 6) { + trackBit |= static_cast(RefMFTTrackBit::kNclsMFT6); + } if (mfttrack.nClusters() >= 7) { trackBit |= static_cast(RefMFTTrackBit::kNclsMFT7); } @@ -211,13 +214,16 @@ struct skimmerPrimaryMFTTrack { trackBit |= static_cast(RefMFTTrackBit::kNclsMFT8); } - if (mfttrack.chi2() / ndf < 4.f) { - trackBit |= static_cast(RefMFTTrackBit::kChi2MFT4); - } if (mfttrack.chi2() / ndf < 3.f) { trackBit |= static_cast(RefMFTTrackBit::kChi2MFT3); } + if (mfttrack.chi2() / ndf < 2.f) { + trackBit |= static_cast(RefMFTTrackBit::kChi2MFT2); + } + if (std::fabs(dcaXY) < 0.05) { + trackBit |= static_cast(RefMFTTrackBit::kDCAxy005cm); + } if (std::fabs(dcaXY) < 0.04) { trackBit |= static_cast(RefMFTTrackBit::kDCAxy004cm); } @@ -231,7 +237,8 @@ struct skimmerPrimaryMFTTrack { trackBit |= static_cast(RefMFTTrackBit::kDCAxy001cm); } - emprimarytracks(collision.globalIndex(), mfttrack.globalIndex(), mfttrack.sign() / pt, eta, phi, trackBit); + emprimarytracks(mfttrack.sign() / pt, eta, phi, trackBit); + prmtrackeventidtmp(collision.globalIndex()); if (fillQAHistogram) { fRegistry.fill(HIST("MFT/hPt"), pt); diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx index 1cc19c0ff76..bba65c5e5d7 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx @@ -171,14 +171,12 @@ struct skimmerPrimaryMuon { hMuonType->GetXaxis()->SetBinLabel(4, "MCH-MID"); hMuonType->GetXaxis()->SetBinLabel(5, "MCH standalone"); - fRegistry.add("MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{200, 0.0f, 10}}, false); fRegistry.add("MFTMCHMID/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); fRegistry.add("MFTMCHMID/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); fRegistry.add("MFTMCHMID/hDeltaPt_Pt", "#Deltap_{T}/p_{T} vs. p_{T};p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl}", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); fRegistry.add("MFTMCHMID/hDeltaEta_Pt", "#Delta#eta vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#eta", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); fRegistry.add("MFTMCHMID/hDeltaPhi_Pt", "#Delta#varphi vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - fRegistry.add("MFTMCHMID/hDeltaEtaAtMP_Pt", "#Delta#eta vs. p_{T} at MP;p_{T}^{gl} (GeV/c);#Delta#eta", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - fRegistry.add("MFTMCHMID/hDeltaPhiAtMP_Pt", "#Delta#varphi vs. p_{T} at MP;p_{T}^{gl} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); fRegistry.add("MFTMCHMID/hSign", "sign;sign", kTH1F, {{3, -1.5, +1.5}}, false); fRegistry.add("MFTMCHMID/hNclusters", "Nclusters;Nclusters", kTH1F, {{21, -0.5f, 20.5}}, false); fRegistry.add("MFTMCHMID/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1F, {{11, -0.5f, 10.5}}, false); @@ -300,9 +298,9 @@ struct skimmerPrimaryMuon { int ndf_mchmft = 1; int ndf_mft = 1; - float etaMatchedMCHMIDatMP = 999.f; + // float etaMatchedMCHMIDatMP = 999.f; float phiMatchedMCHMIDatMP = 999.f; - float etaMatchedMFTatMP = 999.f; + // float etaMatchedMFTatMP = 999.f; float phiMatchedMFTatMP = 999.f; float deta = 999.f; @@ -369,9 +367,9 @@ struct skimmerPrimaryMuon { auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz, mZShift); // propagated to matching plane o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwdShift(mfttrack, mZShift, mfttrackcov); // values at innermost update mftsaAtMP.propagateToZhelix(matchingZ, mBz); // propagated to matching plane - etaMatchedMFTatMP = mftsaAtMP.getEta(); + // etaMatchedMFTatMP = mftsaAtMP.getEta(); phiMatchedMFTatMP = mftsaAtMP.getPhi(); - etaMatchedMCHMIDatMP = muonAtMP.getEta(); + // etaMatchedMCHMIDatMP = muonAtMP.getEta(); phiMatchedMCHMIDatMP = muonAtMP.getPhi(); o2::math_utils::bringTo02Pi(phiMatchedMCHMIDatMP); o2::math_utils::bringTo02Pi(phiMatchedMFTatMP); @@ -447,23 +445,24 @@ struct skimmerPrimaryMuon { if constexpr (fillTable) { float dpt = (ptMatchedMCHMID - pt) / pt; - float detaMP = etaMatchedMCHMIDatMP - etaMatchedMFTatMP; - float dphiMP = phiMatchedMCHMIDatMP - phiMatchedMFTatMP; - o2::math_utils::bringToPMPi(dphiMP); + // float detaMP = etaMatchedMCHMIDatMP - etaMatchedMFTatMP; + // float dphiMP = phiMatchedMCHMIDatMP - phiMatchedMFTatMP; + // o2::math_utils::bringToPMPi(dphiMP); bool isAssociatedToMPC = fwdtrack.collisionId() == collision.globalIndex(); // LOGF(info, "isAmbiguous = %d, isAssociatedToMPC = %d, fwdtrack.globalIndex() = %d, fwdtrack.collisionId() = %d, collision.globalIndex() = %d", isAmbiguous, isAssociatedToMPC, fwdtrack.globalIndex(), fwdtrack.collisionId(), collision.globalIndex()); emprimarymuons(collision.globalIndex(), fwdtrack.globalIndex(), fwdtrack.matchMFTTrackId(), fwdtrack.matchMCHTrackId(), fwdtrack.trackType(), pt, eta, phi, fwdtrack.sign(), dcaX, dcaY, cXX, cYY, cXY, ptMatchedMCHMID, etaMatchedMCHMID, phiMatchedMCHMID, - etaMatchedMCHMIDatMP, phiMatchedMCHMIDatMP, etaMatchedMFTatMP, phiMatchedMFTatMP, + // etaMatchedMCHMIDatMP, phiMatchedMCHMIDatMP, etaMatchedMFTatMP, phiMatchedMFTatMP, fwdtrack.nClusters(), pDCA, rAtAbsorberEnd, fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), fwdtrack.chi2MatchMCHMFT(), fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards(), mftClusterSizesAndTrackFlags, chi2mft, isAssociatedToMPC, isAmbiguous); const auto& fwdcov = propmuonAtPV.getCovariances(); // covatiance matrix at PV emprimarymuonscov( - fwdcov(0, 0), - fwdcov(0, 1), fwdcov(1, 1), + propmuonAtPV.getX(), propmuonAtPV.getY(), propmuonAtPV.getZ(), + // fwdcov(0, 0), + // fwdcov(0, 1), fwdcov(1, 1), fwdcov(2, 0), fwdcov(2, 1), fwdcov(2, 2), fwdcov(3, 0), fwdcov(3, 1), fwdcov(3, 2), fwdcov(3, 3), fwdcov(4, 0), fwdcov(4, 1), fwdcov(4, 2), fwdcov(4, 3), fwdcov(4, 4)); @@ -487,8 +486,6 @@ struct skimmerPrimaryMuon { fRegistry.fill(HIST("MFTMCHMID/hDeltaPt_Pt"), pt, dpt); fRegistry.fill(HIST("MFTMCHMID/hDeltaEta_Pt"), pt, deta); fRegistry.fill(HIST("MFTMCHMID/hDeltaPhi_Pt"), pt, dphi); - fRegistry.fill(HIST("MFTMCHMID/hDeltaEtaAtMP_Pt"), pt, detaMP); - fRegistry.fill(HIST("MFTMCHMID/hDeltaPhiAtMP_Pt"), pt, dphiMP); fRegistry.fill(HIST("MFTMCHMID/hSign"), fwdtrack.sign()); fRegistry.fill(HIST("MFTMCHMID/hNclusters"), fwdtrack.nClusters()); fRegistry.fill(HIST("MFTMCHMID/hNclustersMFT"), nClustersMFT); @@ -517,8 +514,6 @@ struct skimmerPrimaryMuon { fRegistry.fill(HIST("MCHMID/hDeltaPt_Pt"), pt, dpt); fRegistry.fill(HIST("MCHMID/hDeltaEta_Pt"), pt, deta); fRegistry.fill(HIST("MCHMID/hDeltaPhi_Pt"), pt, dphi); - fRegistry.fill(HIST("MCHMID/hDeltaEtaAtMP_Pt"), pt, detaMP); - fRegistry.fill(HIST("MCHMID/hDeltaPhiAtMP_Pt"), pt, dphiMP); fRegistry.fill(HIST("MCHMID/hSign"), fwdtrack.sign()); fRegistry.fill(HIST("MCHMID/hNclusters"), fwdtrack.nClusters()); fRegistry.fill(HIST("MCHMID/hNclustersMFT"), nClustersMFT); @@ -694,9 +689,9 @@ struct skimmerPrimaryMuon { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; @@ -784,9 +779,10 @@ struct skimmerPrimaryMuon { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } + // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -875,9 +871,11 @@ struct skimmerPrimaryMuon { if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } + // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -957,9 +955,10 @@ struct skimmerPrimaryMuon { if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } + // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -1045,9 +1044,10 @@ struct skimmerPrimaryMuon { if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } + // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -1137,9 +1137,9 @@ struct skimmerPrimaryMuon { if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -1220,9 +1220,9 @@ struct skimmerPrimaryMuon { if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -1311,9 +1311,9 @@ struct skimmerPrimaryMuon { if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -1406,9 +1406,9 @@ struct skimmerPrimaryMuon { if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } // if (!isBestMatch(fwdtrack, fwdtracks, mfttracks)) { // continue; // } @@ -1486,12 +1486,15 @@ struct associateAmbiguousMuon { } } }; -struct associateSameMFT { - Produces em_same_mft_ids; + +struct associateSameMuonElement { + Produces glmuon_same_ids; SliceCache cache; PresliceUnsorted perMFTTrack = o2::aod::emprimarymuon::mfttrackId; - std::vector self_Ids; + PresliceUnsorted perMCHTrack = o2::aod::emprimarymuon::mchtrackId; + std::vector selfIds_per_MFT; + std::vector selfIds_per_MCHMID; // Multiple MCH-MID tracks can match with the same MFTsa. This function is to reject such global muons. void process(aod::EMPrimaryMuons const& muons) @@ -1499,24 +1502,42 @@ struct associateSameMFT { for (const auto& muon : muons) { if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { auto muons_with_same_mfttrackId = muons.sliceBy(perMFTTrack, muon.mfttrackId()); - self_Ids.reserve(muons_with_same_mfttrackId.size()); + auto muons_with_same_mchtrackId = muons.sliceBy(perMCHTrack, muon.mchtrackId()); + selfIds_per_MFT.reserve(muons_with_same_mfttrackId.size()); + selfIds_per_MCHMID.reserve(muons_with_same_mchtrackId.size()); + // LOGF(info, "muons_with_same_mchtrackId.size() = %d, muons_with_same_mfttrackId.size() = %d", muons_with_same_mchtrackId.size(), muons_with_same_mfttrackId.size()); + for (const auto& global_muon : muons_with_same_mfttrackId) { + // LOGF(info, "same MFT: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. continue; } - // self_Ids.emplace_back(global_muon.globalIndex()); + if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. + selfIds_per_MFT.emplace_back(global_muon.globalIndex()); + } + } + for (const auto& global_muon : muons_with_same_mchtrackId) { + // LOGF(info, "same MCH: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); + if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. + continue; + } if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. - self_Ids.emplace_back(global_muon.globalIndex()); + selfIds_per_MCHMID.emplace_back(global_muon.globalIndex()); } } - em_same_mft_ids(self_Ids); - self_Ids.clear(); - self_Ids.shrink_to_fit(); + + glmuon_same_ids(selfIds_per_MCHMID, selfIds_per_MFT); + selfIds_per_MFT.clear(); + selfIds_per_MFT.shrink_to_fit(); + selfIds_per_MCHMID.clear(); + selfIds_per_MCHMID.shrink_to_fit(); } else { - em_same_mft_ids(std::vector{}); // empty for standalone muons - self_Ids.clear(); - self_Ids.shrink_to_fit(); + glmuon_same_ids(std::vector{}, std::vector{}); // empty for standalone muons + selfIds_per_MFT.clear(); + selfIds_per_MFT.shrink_to_fit(); + selfIds_per_MCHMID.clear(); + selfIds_per_MCHMID.shrink_to_fit(); } } // end of muon loop } @@ -1526,5 +1547,5 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) return WorkflowSpec{ adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-muon"}), adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-muon"}), - adaptAnalysisTask(cfgc, TaskName{"associate-same-mft"})}; + adaptAnalysisTask(cfgc, TaskName{"associate-same-muon-element"})}; } diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx new file mode 100644 index 00000000000..3ad5171301c --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx @@ -0,0 +1,788 @@ +// 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 write relevant information for muons. +/// \author daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Common/Core/TableHelper.h" +#include "Common/Core/fwdtrackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "Math/SMatrix.h" +#include "Math/Vector4D.h" +#include "TGeoGlobalMagField.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::aod::fwdtrackutils; + +struct skimmerPrimaryMuonQC { + using MyCollisions = soa::Join; + using MyCollisionsWithSWT = soa::Join; + + using MyFwdTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. + using MyFwdTrack = MyFwdTracks::iterator; + + using MyFwdTracksMC = soa::Join; + using MyFwdTrackMC = MyFwdTracksMC::iterator; + + using MFTTracksMC = soa::Join; + using MFTTrackMC = MFTTracksMC::iterator; + + Produces emprimarymuons; + Produces emprimarymuonscov; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable fillQAHistograms{"fillQAHistograms", false, "flag to fill QA histograms"}; + + // for z shift for propagation + Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; + Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; + Configurable cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; + Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; + Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + + struct : ConfigurableGroup { // tight cut + std::string prefix = "tagMuonCut"; + Configurable minPt{"minPt", 0.8, "min pt for muon"}; + Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; + Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; + Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; + Configurable minRabs{"minRabs", 27.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 + Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + Configurable maxDCAxy{"maxDCAxy", 0.06, "max. DCAxy for global muons"}; + Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 40.f, "max. chi2 for MCH-MFT matching"}; + Configurable maxChi2{"maxChi2", 4.f, "max. chi2/ndf for global muon"}; + // Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; + // Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; + Configurable maxDEta{"maxDEta", 0.08, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable maxDPhi{"maxDPhi", 0.08, "max. dphi between MFT-MCH-MID and MCH-MID"}; + } tagMuonCut; + + struct : ConfigurableGroup { // loose cut + std::string prefix = "probeMuonCut"; + Configurable minPt{"minPt", 0.01, "min pt for muon"}; + Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; + Configurable minEtaSA{"minEtaSA", -4.0, "min. eta acceptance for MFT-MCH"}; + Configurable maxEtaSA{"maxEtaSA", -2.5, "max. eta acceptance for MFT-MCH"}; + Configurable minEtaGL{"minEtaGL", -3.6, "min. eta acceptance for MFT-MCH-MID"}; + Configurable maxEtaGL{"maxEtaGL", -2.5, "max. eta acceptance for MFT-MCH-MID"}; + Configurable minRabs{"minRabs", 17.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 + Configurable midRabs{"midRabs", 26.5, "middle R at absorber end for pDCA cut"}; + Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + Configurable maxDCAxy{"maxDCAxy", 1.f, "max. DCAxy for global muons"}; + Configurable maxPDCAforLargeR{"maxPDCAforLargeR", 324.f, "max. pDCA for large R at absorber end"}; + Configurable maxPDCAforSmallR{"maxPDCAforSmallR", 594.f, "max. pDCA for small R at absorber end"}; + Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 100, "max. chi2 for MCH-MFT matching"}; + Configurable maxChi2{"maxChi2", 1e+10, "max. chi2/ndf for global muon"}; + // Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; + // Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; + Configurable maxDEta{"maxDEta", 1e+10, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable maxDPhi{"maxDPhi", 1e+10, "max. dphi between MFT-MCH-MID and MCH-MID"}; + } probeMuonCut; + + struct : ConfigurableGroup { + std::string prefix = "pairCuts"; + Configurable minMass{"minMass", 0.21, "min mass"}; + Configurable maxMass{"maxMass", 0.30, "max mass"}; + } pairCuts; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber = 0; + float mBz = 0; + float mZShift = 0; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + // static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; + + void init(InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + ccdbApi.init(ccdburl); + + if (fillQAHistograms) { + addHistograms(); + } + mRunNumber = 0; + mBz = 0; + mZShift = 0; + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + + std::map metadata; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); + auto ts = soreor.first; + auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + o2::base::Propagator::initFieldFromGRP(grpmag); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + const double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + mBz = field->getBz(centerMFT); // Get field at centre of MFT + LOGF(info, "Bz at center of MFT = %f kZG", mBz); + + if (cfgApplyZShiftFromCCDB) { + auto* zShift = ccdb->getForTimeStamp>(cfgZShiftPath, bc.timestamp()); + if (zShift != nullptr && !zShift->empty()) { + LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); + mZShift = (*zShift)[0]; + } else { + LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); + mZShift = 0; + } + } else { + LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); + mZShift = cfgManualZShift; + } + } + + void addHistograms() + { + // auto hMuonType = fRegistry.add("hMuonType", "muon type", kTH1F, {{5, -0.5f, 4.5f}}, false); + // hMuonType->GetXaxis()->SetBinLabel(1, "MFT-MCH-MID (global muon)"); + // hMuonType->GetXaxis()->SetBinLabel(2, "MFT-MCH-MID (global muon other match)"); + // hMuonType->GetXaxis()->SetBinLabel(3, "MFT-MCH"); + // hMuonType->GetXaxis()->SetBinLabel(4, "MCH-MID"); + // hMuonType->GetXaxis()->SetBinLabel(5, "MCH standalone"); + + // fRegistry.add("MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{200, 0.0f, 10}}, false); + // fRegistry.add("MFTMCHMID/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); + // fRegistry.add("MFTMCHMID/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); + // fRegistry.add("MFTMCHMID/hDeltaPt_Pt", "#Deltap_{T}/p_{T} vs. p_{T};p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl}", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); + // fRegistry.add("MFTMCHMID/hDeltaEta_Pt", "#Delta#eta vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#eta", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); + // fRegistry.add("MFTMCHMID/hDeltaPhi_Pt", "#Delta#varphi vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); + // fRegistry.add("MFTMCHMID/hSign", "sign;sign", kTH1F, {{3, -1.5, +1.5}}, false); + // fRegistry.add("MFTMCHMID/hNclusters", "Nclusters;Nclusters", kTH1F, {{21, -0.5f, 20.5}}, false); + // fRegistry.add("MFTMCHMID/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1F, {{11, -0.5f, 10.5}}, false); + // fRegistry.add("MFTMCHMID/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1F, {{100, 0.0f, 100}}, false); + // fRegistry.add("MFTMCHMID/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); + // fRegistry.add("MFTMCHMID/hChi2", "chi2;chi2/ndf", kTH1F, {{200, 0.0f, 20}}, false); + // fRegistry.add("MFTMCHMID/hChi2MFT", "chi2 MFT;chi2 MFT/ndf", kTH1F, {{200, 0.0f, 20}}, false); + // fRegistry.add("MFTMCHMID/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{200, 0.0f, 20}}, false); + // fRegistry.add("MFTMCHMID/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{200, 0.0f, 100}}, false); + // fRegistry.add("MFTMCHMID/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -1, 1}, {200, -1, +1}}, false); + // fRegistry.add("MFTMCHMID/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); + // fRegistry.add("MFTMCHMID/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1F, {{100, 0, 1}}, false); + // fRegistry.add("MFTMCHMID/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{100, 0, 1}, {200, -0.1, 0.1}}, false); + // fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); + // fRegistry.add("MFTMCHMID/hDCAx_PosZ", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + // fRegistry.add("MFTMCHMID/hDCAy_PosZ", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + // fRegistry.add("MFTMCHMID/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); + // fRegistry.add("MFTMCHMID/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); + // fRegistry.add("MFTMCHMID/hNmu", "#mu multiplicity;N_{#mu} per collision", kTH1F, {{21, -0.5, 20.5}}, false); + + // fRegistry.addClone("MFTMCHMID/", "MCHMID/"); + // fRegistry.add("MFTMCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + // fRegistry.add("MFTMCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + // fRegistry.add("MFTMCHMID/hDCAxyResolutionvsPt", "DCA_{xy} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + // fRegistry.add("MCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); + // fRegistry.add("MCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); + // fRegistry.add("MCHMID/hDCAxyResolutionvsPt", "DCA_{xy} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); + + fRegistry.add("Pair/uls/gl_gl/hMvsPt", "dimuon;m_{#mu#mu} (GeV/c^{2});p_{T,#mu} (GeV/c);", kTH2F, {{380, 0.2, 4.f}, {100, 0, 10}}, false); + fRegistry.add("Pair/uls/gl_sa/hMvsPt", "dimuon;m_{#mu#mu} (GeV/c^{2});p_{T,#mu} (GeV/c);", kTH2F, {{380, 0.2, 4.f}, {100, 0, 10}}, false); + } + + struct Muon { + int globalIndex = -1; + int collisionId = -1; + int matchMCHTrackId = -1; + int matchMFTTrackId = -1; + uint8_t trackType = 99; + int8_t sign = 0; + float pt = 0; + float eta = 0; + float phi = 0; + float dcaX = 0; // in cm + float dcaY = 0; // in cm + float dcaXY = 0; // in cm + float cXX = 0; + float cYY = 0; + float cXY = 0; + float rAtAbsorberEnd = 0; + float pDCA = 0; + float chi2ndf = 0; + float chi2MatchMCHMID = 0; + + // only for global muons + float ptMatchedMCHMID = 0; + float etaMatchedMCHMID = 0; + float phiMatchedMCHMID = 0; + float chi2MatchMCHMFT = 0; + float chi2mft = -999.f; + uint64_t mftClusterSizesAndTrackFlags = 0; + }; + + bool isSelected(Muon const& muon) + { + if (muon.pt < probeMuonCut.minPt || probeMuonCut.maxPt < muon.pt) { + return false; + } + + if (muon.rAtAbsorberEnd < probeMuonCut.minRabs || probeMuonCut.maxRabs < muon.rAtAbsorberEnd) { + return false; + } + + if (muon.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (muon.eta < probeMuonCut.minEtaGL || probeMuonCut.maxEtaGL < muon.eta) { + return false; + } + if (probeMuonCut.maxDCAxy < muon.dcaXY) { + return false; + } + if (probeMuonCut.maxMatchingChi2MCHMFT < muon.chi2MatchMCHMFT) { + return false; + } + } else if (muon.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (muon.eta < probeMuonCut.minEtaSA || probeMuonCut.maxEtaSA < muon.eta) { + return false; + } + if (muon.rAtAbsorberEnd < probeMuonCut.midRabs ? muon.pDCA > probeMuonCut.maxPDCAforSmallR : muon.pDCA > probeMuonCut.maxPDCAforLargeR) { + return false; + } + } else { + return false; + } + + return true; + } + + bool isSelectedTight(Muon const& muon) + { + if (muon.trackType != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { // tag muon should be tight. + return false; + } + + if (muon.pt < tagMuonCut.minPt || tagMuonCut.maxPt < muon.pt) { + return false; + } + + if (muon.rAtAbsorberEnd < tagMuonCut.minRabs || tagMuonCut.maxRabs < muon.rAtAbsorberEnd) { + return false; + } + + if (muon.chi2ndf < 0.f || tagMuonCut.maxChi2 < muon.chi2ndf) { + return false; + } + + if (muon.eta < tagMuonCut.minEta || tagMuonCut.maxEta < muon.eta) { + return false; + } + + if (tagMuonCut.maxDCAxy < muon.dcaXY) { + return false; + } + + if (tagMuonCut.maxMatchingChi2MCHMFT < muon.chi2MatchMCHMFT) { + return false; + } + + float deta = muon.etaMatchedMCHMID - muon.eta; + float dphi = muon.phiMatchedMCHMID - muon.phi; + // LOGF(info, "muon.trackType = %d, deta = %f, dphi = %f", muon.trackType, deta, dphi); + if (std::sqrt(std::pow(deta / tagMuonCut.maxDEta, 2) + std::pow(dphi / tagMuonCut.maxDPhi, 2)) > 1.f) { + return false; + } + + return true; + } + + template + bool fillMuonInfo(TCollision const& collision, TFwdTrack fwdtrack) + { + if (fwdtrack.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && fwdtrack.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + return false; + } + + if (fwdtrack.chi2MatchMCHMID() < 0.f) { // this should never happen. only for protection. + return false; + } + + if (fwdtrack.chi2() < 0.f) { // this should never happen. only for protection. + return false; + } + + o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); + float pt = propmuonAtPV.getPt(); + float eta = propmuonAtPV.getEta(); + float phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + float dcaX = propmuonAtPV.getX() - collision.posX(); + float dcaY = propmuonAtPV.getY() - collision.posY(); + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + float cXX = propmuonAtPV.getSigma2X(); + float cYY = propmuonAtPV.getSigma2Y(); + float cXY = propmuonAtPV.getSigmaXY(); + + float pDCA = propmuonAtPV.getP() * dcaXY; + int nClustersMFT = 0; + float ptMatchedMCHMID = propmuonAtPV.getPt(); + float etaMatchedMCHMID = propmuonAtPV.getEta(); + float phiMatchedMCHMID = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + float chi2mft = -999.f; + uint64_t mftClusterSizesAndTrackFlags = 0; + int ndf_mchmft = 1; + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + if (fwdtrack.chi2MatchMCHMFT() < 0.f) { + return false; + } // Users have to decide the best match between MFT and MCH-MID at analysis level. The same global muon is repeatedly stored. + + auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID + auto mfttrack = fwdtrack.template matchMFTTrack_as(); // MFTsa + if (mfttrack.chi2() < 0.f) { + return false; + } + + if constexpr (isMC) { + if (!mfttrack.has_mcParticle() || !mchtrack.has_mcParticle() || !fwdtrack.has_mcParticle()) { + return false; + } + // auto mcParticle_MFTMCHMID = fwdtrack.template mcParticle_as(); // this is identical to mcParticle_MCHMID + auto mcParticle_MCHMID = mchtrack.template mcParticle_as(); // this is identical to mcParticle_MFTMCHMID + auto mcParticle_MFT = mfttrack.template mcParticle_as(); + } + + nClustersMFT = mfttrack.nClusters(); + mftClusterSizesAndTrackFlags = mfttrack.mftClusterSizesAndTrackFlags(); + ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; + chi2mft = mfttrack.chi2(); + + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); + ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); + etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); + phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); + float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); + float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); + float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); + pDCA = mchtrack.p() * dcaXY_Matched; + + if (refitGlobalMuon) { + pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); + } + } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz, mZShift); // this is necessary only for MuonStandaloneTrack + float xAbs = propmuonAtRabs.getX(); + float yAbs = propmuonAtRabs.getY(); + rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); // Redo propagation only for muon tracks // propagation of MFT tracks alredy done in reconstruction + ndf_mchmft = 1; // chi2 is already normalized by ndf for MCH-MID tracks. + + o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); + cXX = propmuonAtDCA.getSigma2X(); + cYY = propmuonAtDCA.getSigma2Y(); + cXY = propmuonAtDCA.getSigmaXY(); + dcaX = propmuonAtDCA.getX() - collision.posX(); + dcaY = propmuonAtDCA.getY() - collision.posY(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + pDCA = fwdtrack.p() * dcaXY; + } else { + return false; + } + + Muon muon; + muon.globalIndex = fwdtrack.globalIndex(); + muon.collisionId = collision.globalIndex(); + muon.trackType = fwdtrack.trackType(); + muon.sign = fwdtrack.sign(); + muon.pt = pt; + muon.eta = eta; + muon.phi = phi; + muon.dcaX = dcaX; + muon.dcaY = dcaY; + muon.dcaXY = dcaXY; + muon.cXX = cXX; + muon.cYY = cYY; + muon.cXY = cXY; + muon.rAtAbsorberEnd = rAtAbsorberEnd; + muon.pDCA = pDCA; + muon.chi2ndf = fwdtrack.chi2() / ndf_mchmft; + muon.ptMatchedMCHMID = ptMatchedMCHMID; + muon.etaMatchedMCHMID = etaMatchedMCHMID; + muon.phiMatchedMCHMID = phiMatchedMCHMID; + muon.chi2mft = chi2mft; + muon.matchMCHTrackId = fwdtrack.matchMCHTrackId(); + muon.matchMFTTrackId = fwdtrack.matchMFTTrackId(); + muon.mftClusterSizesAndTrackFlags = mftClusterSizesAndTrackFlags; + + vecMuons.emplace_back(muon); + return true; + } + + template + bool fillFwdTrackTable(TCollision const& collision, TMuon const& muon, TFwdTrack const& fwdtrack) + { + emprimarymuons(collision.globalIndex(), fwdtrack.globalIndex(), fwdtrack.matchMFTTrackId(), fwdtrack.matchMCHTrackId(), fwdtrack.trackType(), + muon.pt, muon.eta, muon.phi, fwdtrack.sign(), muon.dcaX, muon.dcaY, muon.cXX, muon.cYY, muon.cXY, muon.ptMatchedMCHMID, muon.etaMatchedMCHMID, muon.phiMatchedMCHMID, + fwdtrack.nClusters(), muon.pDCA, muon.rAtAbsorberEnd, fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), fwdtrack.chi2MatchMCHMFT(), + fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards(), muon.mftClusterSizesAndTrackFlags, muon.chi2mft, true, false); + + // if (fillQAHistograms) { + // fRegistry.fill(HIST("hMuonType"), fwdtrack.trackType()); + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + // fRegistry.fill(HIST("MFTMCHMID/hPt"), pt); + // fRegistry.fill(HIST("MFTMCHMID/hEtaPhi"), phi, eta); + // fRegistry.fill(HIST("MFTMCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + // fRegistry.fill(HIST("MFTMCHMID/hDeltaPt_Pt"), pt, dpt); + // fRegistry.fill(HIST("MFTMCHMID/hDeltaEta_Pt"), pt, deta); + // fRegistry.fill(HIST("MFTMCHMID/hDeltaPhi_Pt"), pt, dphi); + // fRegistry.fill(HIST("MFTMCHMID/hSign"), fwdtrack.sign()); + // fRegistry.fill(HIST("MFTMCHMID/hNclusters"), fwdtrack.nClusters()); + // fRegistry.fill(HIST("MFTMCHMID/hNclustersMFT"), nClustersMFT); + // fRegistry.fill(HIST("MFTMCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + // fRegistry.fill(HIST("MFTMCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); + // fRegistry.fill(HIST("MFTMCHMID/hChi2"), fwdtrack.chi2() / ndf_mchmft); + // fRegistry.fill(HIST("MFTMCHMID/hChi2MFT"), chi2mft / ndf_mft); + // fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + // fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + // fRegistry.fill(HIST("MFTMCHMID/hDCAxy2D"), dcaX, dcaY); + // fRegistry.fill(HIST("MFTMCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + // fRegistry.fill(HIST("MFTMCHMID/hDCAxy"), dcaXY); + // fRegistry.fill(HIST("MFTMCHMID/hDCAxyz"), dcaXY, dcaZ); + // fRegistry.fill(HIST("MFTMCHMID/hDCAxyinSigma"), dcaXYinSigma); + // fRegistry.fill(HIST("MFTMCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + // fRegistry.fill(HIST("MFTMCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um + // fRegistry.fill(HIST("MFTMCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + // fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ"), collision.posZ(), dcaX); + // fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ"), collision.posZ(), dcaY); + // fRegistry.fill(HIST("MFTMCHMID/hDCAx_Phi"), phi, dcaX); + // fRegistry.fill(HIST("MFTMCHMID/hDCAy_Phi"), phi, dcaY); + // } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + // fRegistry.fill(HIST("MCHMID/hPt"), pt); + // fRegistry.fill(HIST("MCHMID/hEtaPhi"), phi, eta); + // fRegistry.fill(HIST("MCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + // fRegistry.fill(HIST("MCHMID/hDeltaPt_Pt"), pt, dpt); + // fRegistry.fill(HIST("MCHMID/hDeltaEta_Pt"), pt, deta); + // fRegistry.fill(HIST("MCHMID/hDeltaPhi_Pt"), pt, dphi); + // fRegistry.fill(HIST("MCHMID/hSign"), fwdtrack.sign()); + // fRegistry.fill(HIST("MCHMID/hNclusters"), fwdtrack.nClusters()); + // fRegistry.fill(HIST("MCHMID/hNclustersMFT"), nClustersMFT); + // fRegistry.fill(HIST("MCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + // fRegistry.fill(HIST("MCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); + // fRegistry.fill(HIST("MCHMID/hChi2"), fwdtrack.chi2()); + // fRegistry.fill(HIST("MCHMID/hChi2MFT"), chi2mft / ndf_mft); + // fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + // fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + // fRegistry.fill(HIST("MCHMID/hDCAxy2D"), dcaX, dcaY); + // fRegistry.fill(HIST("MCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + // fRegistry.fill(HIST("MCHMID/hDCAxy"), dcaXY); + // fRegistry.fill(HIST("MCHMID/hDCAxyz"), dcaXY, dcaZ); + // fRegistry.fill(HIST("MCHMID/hDCAxyinSigma"), dcaXYinSigma); + // fRegistry.fill(HIST("MCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + // fRegistry.fill(HIST("MCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um + // fRegistry.fill(HIST("MCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + // } + // } + return true; + } + + SliceCache cache; + Preslice perCollision = o2::aod::fwdtrack::collisionId; + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; + PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; + PresliceUnsorted fwdtracksPerMCHTrack = aod::fwdtrack::matchMCHTrackId; + + // Filter trackFilter = o2::aod::fwdtrack::trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) || o2::aod::fwdtrack::trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack); + // using filteredMyFwdTracks = soa::Filtered; + // Partition posTracks = o2::aod::fwdtrack::signed1Pt > 0.f; + // Partition negTracks = o2::aod::fwdtrack::signed1Pt < 0.f; + + std::vector vecMuons; + + void processRec(MyCollisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) + { + vecMuons.reserve(fwdtracks.size()); + + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& fwdtrack : fwdtracks_per_coll) { + fillMuonInfo(collision, fwdtrack); + } + + auto pos_muons_per_col = std::views::filter(vecMuons, [](Muon muon) { return muon.sign > 0; }); + auto neg_muons_per_col = std::views::filter(vecMuons, [](Muon muon) { return muon.sign < 0; }); + + // ULS + for (const auto& pos : pos_muons_per_col) { + if (!isSelectedTight(pos)) { // pos is tag, neg is probe + continue; + } + for (const auto& neg : neg_muons_per_col) { + if (!isSelected(neg)) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1(pos.pt, pos.eta, pos.phi, o2::constants::physics::MassMuon); // tag + ROOT::Math::PtEtaPhiMVector v2(neg.pt, neg.eta, neg.phi, o2::constants::physics::MassMuon); // probe + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (neg.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (pos.matchMCHTrackId == neg.matchMCHTrackId || pos.matchMFTTrackId == neg.matchMFTTrackId) { // this should not happen in ULS. only for protection. + continue; + } + fRegistry.fill(HIST("Pair/uls/gl_gl/hMvsPt"), v12.M(), v2.Pt()); + } else if (neg.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (pos.matchMCHTrackId == neg.globalIndex) { // this should not happen in ULS. only for protection. + continue; + } + fRegistry.fill(HIST("Pair/uls/gl_sa/hMvsPt"), v12.M(), v2.Pt()); + } + if (pairCuts.minMass < v12.M() && v12.M() < pairCuts.maxMass) { + fillFwdTrackTable(collision, neg, fwdtracks.rawIteratorAt(neg.globalIndex)); + } + } // end of neg + } // end of pos + + // ULS + for (const auto& neg : neg_muons_per_col) { + if (!isSelectedTight(neg)) { // neg is tag, pos is probe + continue; + } + for (const auto& pos : pos_muons_per_col) { + if (!isSelected(pos)) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1(neg.pt, neg.eta, neg.phi, o2::constants::physics::MassMuon); // tag + ROOT::Math::PtEtaPhiMVector v2(pos.pt, pos.eta, pos.phi, o2::constants::physics::MassMuon); // probe + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (pos.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (pos.matchMCHTrackId == neg.matchMCHTrackId || pos.matchMFTTrackId == neg.matchMFTTrackId) { // this should not happen in ULS. only for protection. + continue; + } + fRegistry.fill(HIST("Pair/uls/gl_gl/hMvsPt"), v12.M(), v2.Pt()); + } else if (pos.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (neg.matchMCHTrackId == pos.globalIndex) { // this should not happen in ULS. only for protection. + continue; + } + fRegistry.fill(HIST("Pair/uls/gl_sa/hMvsPt"), v12.M(), v2.Pt()); + } + if (pairCuts.minMass < v12.M() && v12.M() < pairCuts.maxMass) { + fillFwdTrackTable(collision, pos, fwdtracks.rawIteratorAt(pos.globalIndex)); + } + } // end of pos + } // end of neg + + } // end of collision loop + + vecMuons.clear(); + vecMuons.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuonQC, processRec, "process reconstructed info", false); + + void processRec_SWT(MyCollisionsWithSWT const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) + { + vecMuons.reserve(fwdtracks.size()); + + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + if (collision.swtaliastmp_raw() == 0) { + continue; + } + + // const auto& fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); + // for (const auto& fwdtrack : fwdtracks_per_coll) { + // if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + // continue; + // } + + // if (!fillFwdTrackTable(collision, fwdtrack, false)) { + // continue; + // } + + // } // end of fwdtrack loop + } // end of collision loop + + vecMuons.clear(); + vecMuons.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuonQC, processRec_SWT, "process reconstructed info only with standalone", false); + + using filteredMyFwdTracksMC = soa::Filtered; + void processMC(soa::Join const& collisions, MyFwdTracksMC const& fwdtracks, MFTTracksMC const&, aod::BCsWithTimestamps const&, aod::McParticles const&) + { + vecMuons.reserve(fwdtracks.size()); + + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + if (!collision.has_mcCollision()) { + continue; + } + + // auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); + // for (const auto& fwdtrack : fwdtracks_per_coll) { + // if (!fwdtrack.has_mcParticle()) { + // continue; + // } + // if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + // continue; + // } + + // if (!fillFwdTrackTable(collision, fwdtrack, false)) { + // continue; + // } + + // } // end of fwdtrack loop + } // end of collision loop + + vecMuons.clear(); + vecMuons.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuonQC, processMC, "process reconstructed and MC info", false); + + void processDummy(aod::Collisions const&) {} + PROCESS_SWITCH(skimmerPrimaryMuonQC, processDummy, "process dummy", true); +}; +struct associateAmbiguousMuon { + Produces em_amb_muon_ids; + + SliceCache cache; + PresliceUnsorted perTrack = o2::aod::emprimarymuon::fwdtrackId; + std::vector ambmuon_self_Ids; + + void process(aod::EMPrimaryMuons const& muons) + { + for (const auto& muon : muons) { + auto muons_with_same_trackId = muons.sliceBy(perTrack, muon.fwdtrackId()); + ambmuon_self_Ids.reserve(muons_with_same_trackId.size()); + for (const auto& amb_muon : muons_with_same_trackId) { + if (amb_muon.globalIndex() == muon.globalIndex()) { // don't store myself. + continue; + } + ambmuon_self_Ids.emplace_back(amb_muon.globalIndex()); + } + em_amb_muon_ids(ambmuon_self_Ids); + ambmuon_self_Ids.clear(); + ambmuon_self_Ids.shrink_to_fit(); + } + } +}; + +struct associateSameMuonElement { + Produces glmuon_same_ids; + + SliceCache cache; + PresliceUnsorted perMFTTrack = o2::aod::emprimarymuon::mfttrackId; + PresliceUnsorted perMCHTrack = o2::aod::emprimarymuon::mchtrackId; + std::vector selfIds_per_MFT; + std::vector selfIds_per_MCHMID; + + // Multiple MCH-MID tracks can match with the same MFTsa. This function is to reject such global muons. + void process(aod::EMPrimaryMuons const& muons) + { + for (const auto& muon : muons) { + if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + auto muons_with_same_mfttrackId = muons.sliceBy(perMFTTrack, muon.mfttrackId()); + auto muons_with_same_mchtrackId = muons.sliceBy(perMCHTrack, muon.mchtrackId()); + selfIds_per_MFT.reserve(muons_with_same_mfttrackId.size()); + selfIds_per_MCHMID.reserve(muons_with_same_mchtrackId.size()); + // LOGF(info, "muons_with_same_mchtrackId.size() = %d, muons_with_same_mfttrackId.size() = %d", muons_with_same_mchtrackId.size(), muons_with_same_mfttrackId.size()); + + for (const auto& global_muon : muons_with_same_mfttrackId) { + // LOGF(info, "same MFT: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); + if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. + continue; + } + if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. + selfIds_per_MFT.emplace_back(global_muon.globalIndex()); + } + } + + for (const auto& global_muon : muons_with_same_mchtrackId) { + // LOGF(info, "same MCH: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); + if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. + continue; + } + if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. + selfIds_per_MCHMID.emplace_back(global_muon.globalIndex()); + } + } + + glmuon_same_ids(selfIds_per_MCHMID, selfIds_per_MFT); + selfIds_per_MFT.clear(); + selfIds_per_MFT.shrink_to_fit(); + selfIds_per_MCHMID.clear(); + selfIds_per_MCHMID.shrink_to_fit(); + } else { + glmuon_same_ids(std::vector{}, std::vector{}); // empty for standalone muons + selfIds_per_MFT.clear(); + selfIds_per_MFT.shrink_to_fit(); + selfIds_per_MCHMID.clear(); + selfIds_per_MCHMID.shrink_to_fit(); + } + } // end of muon loop + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-muon-qc"}), + adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-muon"}), + adaptAnalysisTask(cfgc, TaskName{"associate-same-muon-element"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryTrack.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryTrack.cxx index 7dba6b78b36..bc88fd7fef0 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryTrack.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryTrack.cxx @@ -18,7 +18,6 @@ #include "Common/Core/TableHelper.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/DataModel/PIDResponseITS.h" #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" @@ -45,19 +44,19 @@ using namespace o2::framework::expressions; using namespace o2::constants::physics; using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; -using MyCollisions = soa::Join; -using MyCollisionsWithSWT = soa::Join; +struct skimmerPrimaryTrack { + using MyCollisions = soa::Join; + using MyCollisionsWithSWT = soa::Join; -using MyTracks = soa::Join; -using MyTrack = MyTracks::iterator; -using MyTracksMC = soa::Join; -using MyTrackMC = MyTracksMC::iterator; + using MyTracks = soa::Join; + using MyTrack = MyTracks::iterator; + using MyTracksMC = soa::Join; + using MyTrackMC = MyTracksMC::iterator; -struct skimmerPrimaryTrack { SliceCache cache; Preslice perCol = o2::aod::track::collisionId; Produces emprimarytracks; - // Produces prmtrackeventidtmp; + Produces prmtrackeventidtmp; // Configurables Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -212,10 +211,6 @@ struct skimmerPrimaryTrack { return false; } - if (track.tpcNClsFound() < 0) { - return false; - } - if (track.tpcNClsCrossedRows() < 50) { return false; } @@ -241,16 +236,10 @@ struct skimmerPrimaryTrack { if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { return false; } - if (std::fabs(dcaZ) > 3.f) { - return false; - } if (std::fabs(trackParCov.getEta()) > maxeta || trackParCov.getPt() < minpt || maxpt < trackParCov.getPt()) { return false; } - if (trackParCov.getPt() > 5.f) { - return false; - } return true; } @@ -258,107 +247,102 @@ struct skimmerPrimaryTrack { template void fillTrackTable(TCollision const& collision, TTrack const& track) { - if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::pair{collision.globalIndex(), track.globalIndex()}) == stored_trackIds.end()) { - o2::dataformats::DCA mDcaInfoCov; - mDcaInfoCov.set(999, 999, 999, 999, 999); - auto trackParCov = getTrackParCov(track); - trackParCov.setPID(track.pidForTracking()); - mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); - mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); - float dcaXY = mDcaInfoCov.getY(); - float dcaZ = mDcaInfoCov.getZ(); - - float pt = trackParCov.getPt(); - float eta = trackParCov.getEta(); - float phi = trackParCov.getPhi(); - o2::math_utils::bringTo02Pi(phi); - uint16_t trackBit = 0; - - // As minimal cuts, following cuts are applied. The cut values are hardcoded on the purpose for consistent bit operation. - // has info on ITS and TPC - // a hit on ITSib any - // Ncls ITS >= 4 - // chi2/Ncls ITS < 36 - // Ncr TPC >= 50 - // chi2/Ncls TPC < 5 - // Ncr/Nf ratio in TPC > 0.8 - - if (track.itsNCls() >= 5) { - trackBit |= static_cast(RefTrackBit::kNclsITS5); - } - if (track.itsNCls() >= 6) { - trackBit |= static_cast(RefTrackBit::kNclsITS6); - } + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(track.pidForTracking()); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); - if (track.tpcNClsCrossedRows() >= 70) { - trackBit |= static_cast(RefTrackBit::kNcrTPC70); - } - if (track.tpcNClsCrossedRows() >= 90) { - trackBit |= static_cast(RefTrackBit::kNcrTPC90); - } - if (track.tpcNClsFound() >= 50) { - trackBit |= static_cast(RefTrackBit::kNclsTPC50); - } - if (track.tpcNClsFound() >= 70) { - trackBit |= static_cast(RefTrackBit::kNclsTPC70); - } - if (track.tpcNClsFound() >= 90) { - trackBit |= static_cast(RefTrackBit::kNclsTPC90); - } - if (track.tpcChi2NCl() < 4.f) { - trackBit |= static_cast(RefTrackBit::kChi2TPC4); - } - if (track.tpcChi2NCl() < 3.f) { - trackBit |= static_cast(RefTrackBit::kChi2TPC3); - } - if (track.tpcFractionSharedCls() < 0.7) { - trackBit |= static_cast(RefTrackBit::kFracSharedTPC07); - } + float pt = trackParCov.getPt(); + float eta = trackParCov.getEta(); + float phi = trackParCov.getPhi(); + o2::math_utils::bringTo02Pi(phi); + uint16_t trackBit = 0; + + // As minimal cuts, following cuts are applied. The cut values are hardcoded on the purpose for consistent bit operation. + // has info on ITS and TPC + // a hit on ITSib any + // Ncls ITS >= 4 + // chi2/Ncls ITS < 36 + // Ncr TPC >= 50 + // chi2/Ncls TPC < 5 + // Ncr/Nf ratio in TPC > 0.8 + + if (track.itsNCls() >= 5) { + trackBit |= static_cast(RefTrackBit::kNclsITS5); + } + if (track.itsNCls() >= 6) { + trackBit |= static_cast(RefTrackBit::kNclsITS6); + } - if (std::fabs(dcaZ) < 0.5) { - trackBit |= static_cast(RefTrackBit::kDCAz05cm); - } - if (std::fabs(dcaZ) < 0.3) { - trackBit |= static_cast(RefTrackBit::kDCAz03cm); - } + if (track.tpcNClsCrossedRows() >= 70) { + trackBit |= static_cast(RefTrackBit::kNcrTPC70); + } + if (track.tpcNClsCrossedRows() >= 90) { + trackBit |= static_cast(RefTrackBit::kNcrTPC90); + } + if (track.tpcNClsFound() >= 50) { + trackBit |= static_cast(RefTrackBit::kNclsTPC50); + } + if (track.tpcNClsFound() >= 70) { + trackBit |= static_cast(RefTrackBit::kNclsTPC70); + } + if (track.tpcNClsFound() >= 90) { + trackBit |= static_cast(RefTrackBit::kNclsTPC90); + } + if (track.tpcChi2NCl() < 4.f) { + trackBit |= static_cast(RefTrackBit::kChi2TPC4); + } + if (track.tpcChi2NCl() < 3.f) { + trackBit |= static_cast(RefTrackBit::kChi2TPC3); + } + if (track.tpcFractionSharedCls() < 0.7) { + trackBit |= static_cast(RefTrackBit::kFracSharedTPC07); + } - if (std::fabs(dcaXY) < 0.5) { - trackBit |= static_cast(RefTrackBit::kDCAxy05cm); - } - if (std::fabs(dcaXY) < 0.3) { - trackBit |= static_cast(RefTrackBit::kDCAxy03cm); - } + if (std::fabs(dcaZ) < 0.5) { + trackBit |= static_cast(RefTrackBit::kDCAz05cm); + } + if (std::fabs(dcaZ) < 0.3) { + trackBit |= static_cast(RefTrackBit::kDCAz03cm); + } - emprimarytracks(collision.globalIndex(), track.globalIndex(), track.sign() / pt, eta, phi, trackBit); - // prmtrackeventidtmp(collision.globalIndex()); - - stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); - - if (fillQAHistogram) { - fRegistry.fill(HIST("Track/hPt"), pt); - fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / pt); - fRegistry.fill(HIST("Track/hEtaPhi"), phi, eta); - fRegistry.fill(HIST("Track/hDCAxyz"), dcaXY, dcaZ); - fRegistry.fill(HIST("Track/hDCAxyzSigma"), dcaXY / std::sqrt(trackParCov.getSigmaY2()), dcaZ / std::sqrt(trackParCov.getSigmaZ2())); - fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt, std::sqrt(trackParCov.getSigmaY2()) * 1e+4); // convert cm to um - fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt, std::sqrt(trackParCov.getSigmaZ2()) * 1e+4); // convert cm to um - fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); - fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); - fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); - fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); - fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); - fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); - fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); - fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); - fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); - fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); - } + if (std::fabs(dcaXY) < 0.5) { + trackBit |= static_cast(RefTrackBit::kDCAxy05cm); + } + if (std::fabs(dcaXY) < 0.3) { + trackBit |= static_cast(RefTrackBit::kDCAxy03cm); + } + + emprimarytracks(/*collision.globalIndex(),*/ /*track.globalIndex(),*/ track.sign() / pt, eta, phi, trackBit); + prmtrackeventidtmp(collision.globalIndex()); + + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hPt"), pt); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / pt); + fRegistry.fill(HIST("Track/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("Track/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), dcaXY / std::sqrt(trackParCov.getSigmaY2()), dcaZ / std::sqrt(trackParCov.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt, std::sqrt(trackParCov.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt, std::sqrt(trackParCov.getSigmaZ2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); } } Preslice trackIndicesPerCollision = aod::track_association::collisionId; - std::vector> stored_trackIds; Filter trackFilter = o2::aod::track::itsChi2NCl < 36.f && o2::aod::track::tpcChi2NCl < 5.f && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; using MyFilteredTracks = soa::Filtered; @@ -366,8 +350,6 @@ struct skimmerPrimaryTrack { void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) { - stored_trackIds.reserve(tracks.size()); - for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); @@ -387,16 +369,11 @@ struct skimmerPrimaryTrack { } } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); } PROCESS_SWITCH(skimmerPrimaryTrack, processRec, "process reconstructed info only", true); // standalone void processRec_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) { - stored_trackIds.reserve(tracks.size()); - for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); @@ -420,9 +397,6 @@ struct skimmerPrimaryTrack { } } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); } PROCESS_SWITCH(skimmerPrimaryTrack, processRec_SWT, "process reconstructed info only", false); // standalone with swt @@ -431,8 +405,6 @@ struct skimmerPrimaryTrack { using MyFilteredTracksMC = soa::Filtered; void processMC(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks) { - stored_trackIds.reserve(tracks.size()); - for (const auto& collision : collisions) { if (!collision.has_mcCollision()) { continue; @@ -455,9 +427,6 @@ struct skimmerPrimaryTrack { fillTrackTable(collision, track); } } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); } PROCESS_SWITCH(skimmerPrimaryTrack, processMC, "process reconstructed and MC info ", false); }; diff --git a/PWGEM/Dilepton/TableProducer/treeCreatorMuonML.cxx b/PWGEM/Dilepton/TableProducer/treeCreatorMuonML.cxx index 8415711a1dc..ed35f705f3a 100644 --- a/PWGEM/Dilepton/TableProducer/treeCreatorMuonML.cxx +++ b/PWGEM/Dilepton/TableProducer/treeCreatorMuonML.cxx @@ -350,7 +350,8 @@ struct TreeCreatorMuonML { xMatchedMCHMIDatMP, yMatchedMCHMIDatMP, xMatchedMFTatMP, yMatchedMFTatMP, fwdtrack.nClusters(), pDCA, rAtAbsorberEnd, chi2, fwdtrack.chi2MatchMCHMID(), fwdtrack.chi2MatchMCHMFT(), // fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards(), - mfttrack.mftClusterSizesAndTrackFlags(), chi2mft, mfttrack.nClusters(), pdgCode, isPrimary, isMatched); + mfttrack.mftClusterSizesAndTrackFlags(), chi2mft, mfttrack.nClusters(), pdgCode, isPrimary, isMatched, + mcParticle_MCHMID.pt(), mcParticle_MCHMID.eta(), mcParticle_MCHMID.phi()); fRegistry.fill(HIST("hMuonType"), fwdtrack.trackType()); fRegistry.fill(HIST("MFTMCHMID/hPt"), pt); diff --git a/PWGEM/Dilepton/Tasks/CMakeLists.txt b/PWGEM/Dilepton/Tasks/CMakeLists.txt index 3424bda2a24..a32c3768bd5 100644 --- a/PWGEM/Dilepton/Tasks/CMakeLists.txt +++ b/PWGEM/Dilepton/Tasks/CMakeLists.txt @@ -40,6 +40,11 @@ o2physics_add_dpl_workflow(create-resolution-map PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(create-resolution-map-derived + SOURCES createResolutionMapDerived.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(test-bremsstrahlung SOURCES testBremsstrahlung.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -57,12 +62,12 @@ o2physics_add_dpl_workflow(event-qc o2physics_add_dpl_workflow(single-electron-qc SOURCES singleElectronQC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(single-electron-qc-mc SOURCES singleElectronQCMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(single-muon-qc @@ -77,12 +82,12 @@ o2physics_add_dpl_workflow(single-muon-qc-mc o2physics_add_dpl_workflow(dielectron SOURCES dielectron.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(dielectron-mc SOURCES dielectronMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(dimuon @@ -97,7 +102,7 @@ o2physics_add_dpl_workflow(dimuon-mc o2physics_add_dpl_workflow(prefilter-dielectron SOURCES prefilterDielectron.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(associate-mccollision-to-collision @@ -122,12 +127,12 @@ o2physics_add_dpl_workflow(tagging-hfe o2physics_add_dpl_workflow(dielectron-hadron-mpc SOURCES dielectronHadronMPC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(dimuon-hadron-mpc SOURCES dimuonHadronMPC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(mc-particle-predictions-otf @@ -157,5 +162,5 @@ o2physics_add_dpl_workflow(check-mc-template o2physics_add_dpl_workflow(check-mc-pair-template SOURCES checkMCPairTemplate.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) diff --git a/PWGEM/Dilepton/Tasks/checkMCPairTemplate.cxx b/PWGEM/Dilepton/Tasks/checkMCPairTemplate.cxx index 2c7ebf754c4..83777d2dbc1 100644 --- a/PWGEM/Dilepton/Tasks/checkMCPairTemplate.cxx +++ b/PWGEM/Dilepton/Tasks/checkMCPairTemplate.cxx @@ -21,13 +21,10 @@ #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" #include "PWGEM/Dilepton/Utils/EventHistograms.h" #include "PWGEM/Dilepton/Utils/MCUtilities.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "Tools/ML/MlResponse.h" #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" @@ -266,6 +263,9 @@ struct checkMCPairTemplate { Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 muons (elliptic cut)"}; Configurable cfg_min_dphi{"cfg_min_dphi", 0.02, "min dphi between 2 muons (elliptic cut)"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter set in derived data"}; + Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; @@ -810,7 +810,6 @@ struct checkMCPairTemplate { fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); } - o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -868,31 +867,6 @@ struct checkMCPairTemplate { thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); } fDielectronCut.SetMLThresholds(binsML, thresholdsML); - - // static constexpr int nClassesMl = 2; - // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; - // const std::vector labelsClasses = {"Background", "Signal"}; - // const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; - // const std::vector labelsBins(nBinsMl, "bin"); - // double cutsMlArr[nBinsMl][nClassesMl]; - // for (uint32_t i = 0; i < nBinsMl; i++) { - // cutsMlArr[i][0] = 0.; - // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; - // } - // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; - - // mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); - // if (dielectroncuts.loadModelsFromCCDB) { - // ccdbApi.init(ccdburl); - // mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); - // } else { - // mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); - // } - // mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); - // mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); - // mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); - - // fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); } // end of PID ML } @@ -3101,6 +3075,10 @@ struct checkMCPairTemplate { Preslice perCollision_muon = aod::emprimarymuon::emeventId; Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type; Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Filter prefilter_derived_muon = ifnode(dimuoncuts.cfg_apply_cuts_from_prefilter_derived.node() && dimuoncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) <= static_cast(0), true) && + ifnode((dimuoncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) > static_cast(0), (o2::aod::emprimarymuon::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) <= static_cast(0), true), + o2::aod::emprimarymuon::pfbderived >= static_cast(0)); Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); Filter collisionFilter_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; diff --git a/PWGEM/Dilepton/Tasks/createResolutionMap.cxx b/PWGEM/Dilepton/Tasks/createResolutionMap.cxx index 891667627a1..003b1b6bfa4 100644 --- a/PWGEM/Dilepton/Tasks/createResolutionMap.cxx +++ b/PWGEM/Dilepton/Tasks/createResolutionMap.cxx @@ -146,6 +146,8 @@ struct CreateResolutionMap { Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; + Configurable checkPIDforTracking{"checkPIDforTracking", false, "check for PID in tracking"}; + Configurable PartIdentifier{"PartIdentifier", 2, "Particle identifier for selected particle; 0: electron, 1: muon, 2: pion, 3: kaon, 4: proton, 5: deuteron, 6: triton, 7: helium3, 8: alpha"}; } electroncuts; struct : ConfigurableGroup { @@ -498,6 +500,10 @@ struct CreateResolutionMap { } } + if (electroncuts.checkPIDforTracking && track.pidForTracking() != static_cast(std::abs(electroncuts.PartIdentifier))) { + return false; + } + return true; } @@ -628,8 +634,8 @@ struct CreateResolutionMap { if constexpr (withMFTCov) { auto mfttrackcov = mftCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, muoncuts.matchingZ, mBzMFT, 0.0); // propagated to matching plane - o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update - mftsaAtMP.propagateToZhelix(muoncuts.matchingZ, mBzMFT); // propagated to matching plane + o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update + mftsaAtMP.propagateToZhelix(muoncuts.matchingZ, mBzMFT); // propagated to matching plane etaMatchedMFTatMP = mftsaAtMP.getEta(); phiMatchedMFTatMP = mftsaAtMP.getPhi(); etaMatchedMCHMIDatMP = muonAtMP.getEta(); diff --git a/PWGEM/Dilepton/Tasks/createResolutionMapDerived.cxx b/PWGEM/Dilepton/Tasks/createResolutionMapDerived.cxx new file mode 100644 index 00000000000..f0a35f7c814 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/createResolutionMapDerived.cxx @@ -0,0 +1,568 @@ +// 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. +// +// +// Analysis task to produce resolution map for electrons/muons over derived data. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" + +#include "Common/CCDB/RCTSelectionFlags.h" + +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; +using namespace o2::soa; + +struct createResolutionMapDerived { + + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + Configurable cfg_require_true_mc_collision_association{"cfg_require_true_mc_collision_association", false, "flag to require true mc collision association"}; + + ConfigurableAxis ConfPtGenBins{"ConfPtGenBins", {VARIABLE_WIDTH, 0.00, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.80, 2.90, 3.00, 3.10, 3.20, 3.30, 3.40, 3.50, 3.60, 3.70, 3.80, 3.90, 4.00, 4.10, 4.20, 4.30, 4.40, 4.50, 4.60, 4.70, 4.80, 4.90, 5.00, 5.50, 6.00, 6.50, 7.00, 7.50, 8.00, 8.50, 9.00, 9.50, 10.00, 11.00, 12.00, 13.00, 14.00, 15.00, 16.00, 17.00, 18.00, 19.00, 20.00}, "gen. pT bins for output histograms"}; + ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0, 10, 30, 50, 110}, "centrality (%) bins for output histograms"}; + + ConfigurableAxis ConfEtaCBGenBins{"ConfEtaCBGenBins", {30, -1.5, +1.5}, "gen. eta bins at midrapidity for output histograms"}; + ConfigurableAxis ConfEtaFWDGenBins{"ConfEtaFWDGenBins", {40, -5.5, -1.5}, "gen. eta bins at forward rapidity for output histograms"}; + ConfigurableAxis ConfPhiGenBins{"ConfPhiGenBins", {36, 0, 2.f * M_PI}, "gen. phi bins at forward rapidity for output histograms"}; + Configurable cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + + ConfigurableAxis ConfRelDeltaPtCBBins{"ConfRelDeltaPtCBBins", {200, -1.f, +1.f}, "rel. dpt for output histograms at midrapidity"}; + ConfigurableAxis ConfRelDeltaPtFWDBins{"ConfRelDeltaPtFWDBins", {200, -1.f, +1.f}, "rel. dpt for output histograms at fwd rapidity"}; + + ConfigurableAxis ConfDeltaEtaCBBins{"ConfDeltaEtaCBBins", {200, -0.5f, +0.5f}, "deta bins for output histograms at midrapidity"}; + ConfigurableAxis ConfDeltaEtaFWDBins{"ConfDeltaEtaFWDBins", {200, -0.5f, +0.5f}, "deta bins for output histograms at fwd rapidity"}; + ConfigurableAxis ConfDeltaPhiBins{"ConfDeltaPhiBins", {200, -0.5f, +0.5f}, "dphi bins for output histograms"}; + + Configurable cfgFillTHnSparse{"cfgFillTHnSparse", true, "fill THnSparse for output"}; + Configurable cfgFillTH2{"cfgFillTH2", false, "fill TH2 for output"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT_hadronPID, CBT_muon_glo, CBT_muon]. see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb/OO"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "electroncut_group"; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.05, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -2, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +2, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "min phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_mirror_phi_track{"cfg_mirror_phi_track", false, "mirror the phi cut around Pi, min and max Phi should be in 0-Pi"}; + Configurable cfg_reject_phi_track{"cfg_reject_phi_track", false, "reject the phi interval"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1.0, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 1.0, "max dca Z for single track in cm"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; + Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; + Configurable acceptOnlyCorrectMatch{"acceptOnlyCorrectMatch", false, "flag to accept only correct match between ITS and TPC"}; // this is only for MC study, as we don't know correct match in data. + Configurable acceptOnlyWrongMatch{"acceptOnlyWrongMatch", false, "flag to accept only wrong match between ITS and TPC"}; // this is only for MC study, as we don't know correct match in data. + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif = 4, kPIDML = 5]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + // Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + // Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + Configurable checkPIDForTracking{"checkPIDForTracking", false, "check PID for tracking"}; + Configurable PartIdentifier{"PartIdentifier", 2, "Particle identifier for selected particle; 0: electron, 1: muon, 2: pion, 3: kaon, 4: proton, 5: deuteron, 6: triton, 7: helium3, 8: alpha"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } electroncuts; + + DimuonCut fDimuonCut; + struct : ConfigurableGroup { + std::string prefix = "muoncut_group"; + + Configurable cfg_track_type{"cfg_track_type", 0, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -10, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 0, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "max phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_mft{"cfg_min_ncluster_mft", 5, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + // Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_border_pt_for_chi2mchmft{"cfg_border_pt_for_chi2mchmft", 0, "border pt for different max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mftmch_lowPt{"cfg_max_matching_chi2_mftmch_lowPt", 8, "max chi2 for MFT-MCH matching for low pT"}; + Configurable cfg_max_matching_chi2_mftmch_highPt{"cfg_max_matching_chi2_mftmch_highPt", 40, "max chi2 for MFT-MCH matching for high pT"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; + Configurable cfg_max_rabs{"cfg_max_rabs", 89.5, "max Radius at the absorber end"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + Configurable acceptOnlyCorrectMatch{"acceptOnlyCorrectMatch", false, "flag to accept only correct match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. + Configurable acceptOnlyWrongMatch{"acceptOnlyWrongMatch", false, "flag to accept only wrong match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. + } muoncuts; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + o2::aod::rctsel::RCTFlagsChecker rctChecker; + + ~createResolutionMapDerived() {} + + void init(o2::framework::InitContext&) + { + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); + + DefineEMEventCut(); + + if (doprocessElectron) { + DefineDielectronCut(); + } + if (doprocessMuon) { + DefineDimuonCut(); + } + addHistograms(); + } + + void addHistograms() + { + // registry.add("Event/Electron/hImpPar_Centrality", "true imapact parameter vs. estimated centrality;impact parameter (fm);centrality (%)", kTH2F, {{200, 0, 20}, {110, 0, 110}}, true); + // registry.add("Event/Electron/hImpPar_Centrality", "true imapact parameter vs. estimated centrality;impact parameter (fm);centrality (%)", kTH2F, {{200, 0, 20}, {110, 0, 110}}, true); + + if (doprocessGen) { + registry.add("Event/hGenID", "generator ID;generator ID;Number of mc collisions", kTH1F, {{7, -1.5, 5.5}}, true); + } + + const AxisSpec axis_cent{ConfCentBins, "centrality (%)"}; + const AxisSpec axis_pt_gen{ConfPtGenBins, "p_{T,l}^{gen} (GeV/c)"}; + const AxisSpec axis_eta_cb_gen{ConfEtaCBGenBins, "#eta_{l}^{gen}"}; + const AxisSpec axis_eta_fwd_gen{ConfEtaFWDGenBins, "#eta_{l}^{gen}"}; + const AxisSpec axis_phi_gen{ConfPhiGenBins, "#varphi_{l}^{gen} (rad.)"}; + const AxisSpec axis_dpt_cb{ConfRelDeltaPtCBBins, "(p_{T,l}^{gen} - p_{T,l}^{rec})/p_{T,l}^{gen}"}; + const AxisSpec axis_dpt_fwd{ConfRelDeltaPtFWDBins, "(p_{T,l}^{gen} - p_{T,l}^{rec})/p_{T,l}^{gen}"}; + const AxisSpec axis_deta_cb{ConfDeltaEtaCBBins, "#eta_{l}^{gen} - #eta_{l}^{rec}"}; + const AxisSpec axis_deta_fwd{ConfDeltaEtaFWDBins, "#eta_{l}^{gen} - #eta_{l}^{rec}"}; + const AxisSpec axis_dphi{ConfDeltaPhiBins, "#varphi_{l}^{gen} - #varphi_{l}^{rec} (rad.)"}; + const AxisSpec axis_charge_gen{3, -1.5, +1.5, "true sign"}; + + if (doprocessElectron) { + registry.add("Electron/hPIDForTracking", "PID for trackng", kTH1F, {{9, -0.5, 8.5}}, false); // see numbering in O2/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h + if (cfgFillTH2) { + registry.add("Electron/hPt", "rec. p_{T,e};p_{T,e} (GeV/c)", kTH1F, {{1000, 0, 10}}, false); + registry.add("Electron/hEtaPhi", "rec. #eta vs. #varphi;#varphi_{e} (rad.);#eta_{e}", kTH2F, {{90, 0, 2 * M_PI}, {40, -2, +2}}, false); + registry.add("Electron/Ptgen_RelDeltaPt", "resolution", kTH2F, {{axis_pt_gen}, {axis_dpt_cb}}, true); + registry.add("Electron/Ptgen_DeltaEta", "resolution", kTH2F, {{axis_pt_gen}, {axis_deta_cb}}, true); + registry.add("Electron/Ptgen_DeltaPhi_Pos", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + registry.add("Electron/Ptgen_DeltaPhi_Neg", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + } + if (cfgFillTHnSparse) { + registry.add("Electron/hs_reso", "8D resolution", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_cb_gen, axis_phi_gen, axis_charge_gen, axis_dpt_cb, axis_deta_cb, axis_dphi}, true); + } + } + + if (doprocessMuon) { + if (muoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (cfgFillTH2) { + registry.add("GlobalMuon/hPt", "rec. p_{T,#mu};p_{T,#mu} (GeV/c)", kTH1F, {{1000, 0, 10}}, false); + registry.add("GlobalMuon/hEtaPhi", "rec. #eta vs. #varphi;#varphi_{#mu} (rad.);#eta_{#mu}", kTH2F, {{90, 0, 2 * M_PI}, {60, -6, 0}}, false); + registry.add("GlobalMuon/Ptgen_RelDeltaPt", "resolution", kTH2F, {{axis_pt_gen}, {axis_dpt_fwd}}, true); + registry.add("GlobalMuon/Ptgen_DeltaEta", "resolution", kTH2F, {{axis_pt_gen}, {axis_deta_fwd}}, true); + registry.add("GlobalMuon/Ptgen_DeltaPhi_Pos", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + registry.add("GlobalMuon/Ptgen_DeltaPhi_Neg", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + } + if (cfgFillTHnSparse) { + registry.add("GlobalMuon/hs_reso", "8D resolution", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_fwd_gen, axis_phi_gen, axis_charge_gen, axis_dpt_fwd, axis_deta_fwd, axis_dphi}, true); + } + } else if (muoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (cfgFillTH2) { + registry.add("StandaloneMuon/hPt", "rec. p_{T,#mu};p_{T,#mu} (GeV/c)", kTH1F, {{1000, 0, 10}}, false); + registry.add("StandaloneMuon/hEtaPhi", "rec. #eta vs. #varphi;#varphi_{#mu} (rad.);#eta_{#mu}", kTH2F, {{90, 0, 2 * M_PI}, {60, -6, 0}}, false); + registry.add("StandaloneMuon/Ptgen_RelDeltaPt", "resolution", kTH2F, {{axis_pt_gen}, {axis_dpt_fwd}}, true); + registry.add("StandaloneMuon/Ptgen_DeltaEta", "resolution", kTH2F, {{axis_pt_gen}, {axis_deta_fwd}}, true); + registry.add("StandaloneMuon/Ptgen_DeltaPhi_Pos", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + registry.add("StandaloneMuon/Ptgen_DeltaPhi_Neg", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + } + if (cfgFillTHnSparse) { + registry.add("StandaloneMuon/hs_reso", "8D resolution", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_fwd_gen, axis_phi_gen, axis_charge_gen, axis_dpt_fwd, axis_deta_fwd, axis_dphi}, true); + } + } + } + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireVertexTOFmatched(eventcuts.cfgRequireVertexTOFmatched); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); + fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); + fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); + } + + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for track + fDielectronCut.SetTrackPtRange(electroncuts.cfg_min_pt_track, electroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(electroncuts.cfg_min_eta_track, +electroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackPhiRange(electroncuts.cfg_min_phi_track, electroncuts.cfg_max_phi_track, electroncuts.cfg_mirror_phi_track, electroncuts.cfg_reject_phi_track); + fDielectronCut.SetMinNClustersTPC(electroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(electroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(electroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, electroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, electroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(electroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(electroncuts.cfg_min_its_cluster_size, electroncuts.cfg_max_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(electroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(electroncuts.cfg_max_dcaz); + fDielectronCut.RequireITSibAny(electroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(electroncuts.cfg_require_itsib_1st); + fDielectronCut.SetChi2TOF(0.0, electroncuts.cfg_max_chi2tof); + // fDielectronCut.SetRelDiffPin(electroncuts.cfg_min_rel_diff_pin, electroncuts.cfg_max_rel_diff_pin); + fDielectronCut.EnableTTCA(electroncuts.enableTTCA); + + // for eID + fDielectronCut.SetPIDScheme(electroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(electroncuts.cfg_min_TPCNsigmaEl, electroncuts.cfg_max_TPCNsigmaEl); + // fDielectronCut.SetTPCNsigmaMuRange(electroncuts.cfg_min_TPCNsigmaMu, electroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(electroncuts.cfg_min_TPCNsigmaPi, electroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(electroncuts.cfg_min_TPCNsigmaKa, electroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(electroncuts.cfg_min_TPCNsigmaPr, electroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(electroncuts.cfg_min_TOFNsigmaEl, electroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetPinRangeForPionRejectionTPC(electroncuts.cfg_min_pin_pirejTPC, electroncuts.cfg_max_pin_pirejTPC); + + if (electroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + std::vector binsML{}; + binsML.reserve(electroncuts.binsMl.value.size()); + for (size_t i = 0; i < electroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(electroncuts.binsMl.value[i]); + } + std::vector thresholdsML{}; + thresholdsML.reserve(electroncuts.cutsMl.value.size()); + for (size_t i = 0; i < electroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(electroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // static constexpr int nClassesMl = 2; + // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + // const std::vector labelsClasses = {"Background", "Signal"}; + // const uint32_t nBinsMl = electroncuts.binsMl.value.size() - 1; + // const std::vector labelsBins(nBinsMl, "bin"); + // double cutsMlArr[nBinsMl][nClassesMl]; + // for (uint32_t i = 0; i < nBinsMl; i++) { + // cutsMlArr[i][0] = 0.; + // cutsMlArr[i][1] = electroncuts.cutsMl.value[i]; + // } + // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + // mlResponseSingleTrack.configure(electroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + // if (electroncuts.loadModelsFromCCDB) { + // ccdbApi.init(ccdburl); + // mlResponseSingleTrack.setModelPathsCCDB(electroncuts.onnxFileNames.value, ccdbApi, electroncuts.onnxPathsCCDB.value, electroncuts.timestampCCDB.value); + // } else { + // mlResponseSingleTrack.setModelPathsLocal(electroncuts.onnxFileNames.value); + // } + // mlResponseSingleTrack.cacheInputFeaturesIndices(electroncuts.namesInputFeatures); + // mlResponseSingleTrack.cacheBinningIndex(electroncuts.nameBinningFeature); + // mlResponseSingleTrack.init(electroncuts.enableOptimizations.value); + + } // end of PID ML + } + + void DefineDimuonCut() + { + fDimuonCut = DimuonCut("fDimuonCut", "fDimuonCut"); + + // for track + fDimuonCut.SetTrackType(muoncuts.cfg_track_type); + fDimuonCut.SetTrackPtRange(muoncuts.cfg_min_pt_track, muoncuts.cfg_max_pt_track); + fDimuonCut.SetTrackEtaRange(muoncuts.cfg_min_eta_track, muoncuts.cfg_max_eta_track); + fDimuonCut.SetTrackPhiRange(muoncuts.cfg_min_phi_track, muoncuts.cfg_max_phi_track); + fDimuonCut.SetNClustersMFT(muoncuts.cfg_min_ncluster_mft, 10); + fDimuonCut.SetNClustersMCHMID(muoncuts.cfg_min_ncluster_mch, 20); + fDimuonCut.SetChi2(0.f, muoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, muoncuts.cfg_max_chi2mft); + // fDimuonCut.SetMatchingChi2MCHMFT(0.f, muoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMaxMatchingChi2MCHMFTPtDep([&](float pt) { return (pt < muoncuts.cfg_border_pt_for_chi2mchmft ? muoncuts.cfg_max_matching_chi2_mftmch_lowPt : muoncuts.cfg_max_matching_chi2_mftmch_highPt); }); + fDimuonCut.SetMatchingChi2MCHMID(0.f, muoncuts.cfg_max_matching_chi2_mchmid); + fDimuonCut.SetDCAxy(0.f, muoncuts.cfg_max_dcaxy); + fDimuonCut.SetRabs(muoncuts.cfg_min_rabs, muoncuts.cfg_max_rabs); + fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(muoncuts.cfg_max_relDPt_wrt_matchedMCHMID, muoncuts.cfg_max_DEta_wrt_matchedMCHMID, muoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(muoncuts.requireMFTHitMap, muoncuts.requiredMFTDisks); + fDimuonCut.EnableTTCA(muoncuts.enableTTCA); + } + + template + void create(TCollisions const& collisions, TTracks const& tracks, TPerCollision const& perCollision, TCut const& cut) + { + for (const auto& collision : collisions) { + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}[eventcuts.cfgCentEstimator]; + if (centrality < eventcuts.cfgCentMin || eventcuts.cfgCentMax < centrality) { + continue; + } + + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + return; + } + + auto tracks_per_coll = tracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!cut.IsSelectedTrack(track)) { + continue; + } + + auto mcParticle = track.template emmcparticle_as(); + auto mcCollision = mcParticle.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + if (cfg_require_true_mc_collision_association && mcParticle.emmceventId() != collision.emmceventId()) { + return; + } + + if constexpr (std::is_same_v, MyMCElectrons>) { + if (std::abs(mcParticle.pdgCode()) != 11) { + continue; + } + + if (electroncuts.acceptOnlyCorrectMatch && o2::aod::pwgem::dilepton::utils::mcutil::hasFakeMatchITSTPC(track)) { + continue; + } + if (electroncuts.acceptOnlyWrongMatch && !o2::aod::pwgem::dilepton::utils::mcutil::hasFakeMatchITSTPC(track)) { + continue; + } + + registry.fill(HIST("Electron/hPIDForTracking"), track.pidForTracking()); + if (electroncuts.checkPIDForTracking && track.pidForTracking() != static_cast(electroncuts.PartIdentifier)) { + continue; + } + + if (cfgFillTHnSparse) { + registry.fill(HIST("Electron/hs_reso"), centrality, mcParticle.pt(), mcParticle.eta(), mcParticle.phi(), -mcParticle.pdgCode() / 11, (mcParticle.pt() - track.pt()) / mcParticle.pt(), mcParticle.eta() - track.eta(), mcParticle.phi() - track.phi()); + } + if (cfgFillTH2) { + registry.fill(HIST("Electron/hPt"), track.pt()); + registry.fill(HIST("Electron/hEtaPhi"), track.phi(), track.eta()); + registry.fill(HIST("Electron/Ptgen_RelDeltaPt"), mcParticle.pt(), (mcParticle.pt() - track.pt()) / mcParticle.pt()); + registry.fill(HIST("Electron/Ptgen_DeltaEta"), mcParticle.pt(), mcParticle.eta() - track.eta()); + if (mcParticle.pdgCode() == -11) { // positron + registry.fill(HIST("Electron/Ptgen_DeltaPhi_Pos"), mcParticle.pt(), mcParticle.phi() - track.phi()); + } else if (mcParticle.pdgCode() == 11) { // electron + registry.fill(HIST("Electron/Ptgen_DeltaPhi_Neg"), mcParticle.pt(), mcParticle.phi() - track.phi()); + } + } + } else if constexpr (std::is_same_v, MyMCMuons>) { + if (std::abs(mcParticle.pdgCode()) != 13) { + continue; + } + + if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (muoncuts.acceptOnlyCorrectMatch) { + if (track.emmcparticleId() != track.emmftmcparticleId()) { + continue; + } + } + if (muoncuts.acceptOnlyWrongMatch) { // reject correctly matched MFT-MCH-MID for bkg estimation + if (track.emmcparticleId() == track.emmftmcparticleId()) { + continue; + } + } + + if (cfgFillTHnSparse) { + registry.fill(HIST("GlobalMuon/hs_reso"), centrality, mcParticle.pt(), mcParticle.eta(), mcParticle.phi(), -mcParticle.pdgCode() / 13, (mcParticle.pt() - track.pt()) / mcParticle.pt(), mcParticle.eta() - track.eta(), mcParticle.phi() - track.phi()); + } + + if (cfgFillTH2) { + registry.fill(HIST("GlobalMuon/hPt"), track.pt()); + registry.fill(HIST("GlobalMuon/hEtaPhi"), track.phi(), track.eta()); + registry.fill(HIST("GlobalMuon/Ptgen_RelDeltaPt"), mcParticle.pt(), (mcParticle.pt() - track.pt()) / mcParticle.pt()); + registry.fill(HIST("GlobalMuon/Ptgen_DeltaEta"), mcParticle.pt(), mcParticle.eta() - track.eta()); + if (mcParticle.pdgCode() == -13) { // positive muon + registry.fill(HIST("GlobalMuon/Ptgen_DeltaPhi_Pos"), mcParticle.pt(), mcParticle.phi() - track.phi()); + } else if (mcParticle.pdgCode() == 13) { // negative muon + registry.fill(HIST("GlobalMuon/Ptgen_DeltaPhi_Neg"), mcParticle.pt(), mcParticle.phi() - track.phi()); + } + } + } else if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (cfgFillTHnSparse) { + registry.fill(HIST("StandaloneMuon/hs_reso"), centrality, mcParticle.pt(), mcParticle.eta(), mcParticle.phi(), -mcParticle.pdgCode() / 13, (mcParticle.pt() - track.pt()) / mcParticle.pt(), mcParticle.eta() - track.eta(), mcParticle.phi() - track.phi()); + } + if (cfgFillTH2) { + registry.fill(HIST("StandaloneMuon/hPt"), track.pt()); + registry.fill(HIST("StandaloneMuon/hEtaPhi"), track.phi(), track.eta()); + registry.fill(HIST("StandaloneMuon/Ptgen_RelDeltaPt"), mcParticle.pt(), (mcParticle.pt() - track.pt()) / mcParticle.pt()); + registry.fill(HIST("StandaloneMuon/Ptgen_DeltaEta"), mcParticle.pt(), mcParticle.eta() - track.eta()); + if (mcParticle.pdgCode() == -13) { // positive muon + registry.fill(HIST("StandaloneMuon/Ptgen_DeltaPhi_Pos"), mcParticle.pt(), mcParticle.phi() - track.phi()); + } else if (mcParticle.pdgCode() == 13) { // negative muon + registry.fill(HIST("StandaloneMuon/Ptgen_DeltaPhi_Neg"), mcParticle.pt(), mcParticle.phi() - track.phi()); + } + } + } + } + } // end of track loop per collision + } // end of collisions + } + + using MyCollisions = soa::Join; + using MyCollision = MyCollisions::iterator; + + using MyMCElectrons = soa::Join; + using MyMCElectron = MyMCElectrons::iterator; + + using MyMCMuons = soa::Join; + using MyMCMuon = MyMCMuons::iterator; + + SliceCache cache; + Preslice perCollision_mid = aod::emprimaryelectron::emeventId; + Preslice perCollision_fwd = aod::emprimarymuon::emeventId; + + Filter collisionFilter_centrality = (eventcuts.cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcuts.cfgCentMax); + Filter collisionFilter_numContrib = eventcuts.cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < eventcuts.cfgNumContribMax; + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using filteredMyCollisions = soa::Filtered; + + template + void processReso(filteredMyCollisions const& collisions, TTracks const& tracks, aod::EMMCEvents const&, aod::EMMCParticles const&) + { + if constexpr (std::is_same_v, MyMCElectrons>) { + create(collisions, tracks, perCollision_mid, fDielectronCut); + } else if constexpr (std::is_same_v, MyMCMuons>) { + create(collisions, tracks, perCollision_fwd, fDimuonCut); + } + } + + PROCESS_SWITCH_FULL(createResolutionMapDerived, processReso, processElectron, "create resolution map for electrons at mid rapidity", false); + PROCESS_SWITCH_FULL(createResolutionMapDerived, processReso, processMuon, "create resolution map for global muons at fwd rapidity", false); // gl or sa can be selected in subwagons. + + void processGen(aod::EMMCEvents const& mcCollisions) + { + for (const auto& mccollision : mcCollisions) { + registry.fill(HIST("Event/hGenID"), mccollision.getSubGeneratorId()); + } + } + PROCESS_SWITCH(createResolutionMapDerived, processGen, "process generated info", true); + + void processDummy(aod::EMMCEvents const&) {} + PROCESS_SWITCH(createResolutionMapDerived, processDummy, "process dummy", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"create-resolution-map-derived"})}; +} diff --git a/PWGEM/Dilepton/Tasks/dileptonPolarization.cxx b/PWGEM/Dilepton/Tasks/dileptonPolarization.cxx index 478b48982e1..3afec6f363a 100644 --- a/PWGEM/Dilepton/Tasks/dileptonPolarization.cxx +++ b/PWGEM/Dilepton/Tasks/dileptonPolarization.cxx @@ -15,10 +15,7 @@ // Please write to: daiki.sekihata@cern.ch #include "PWGEM/Dilepton/DataModel/dileptonTables.h" -// #include "PWGEM/Dilepton/Utils/EMFwdTrack.h" #include "PWGEM/Dilepton/Utils/EMTrack.h" -// #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" -// #include "PWGEM/Dilepton/Utils/EventMixingHandler.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Common/Core/RecoDecay.h" @@ -27,10 +24,6 @@ #include "CommonConstants/LHCConstants.h" #include "DataFormatsParameters/GRPECSObject.h" #include "DataFormatsParameters/GRPLHCIFData.h" -// #include "DataFormatsParameters/GRPMagField.h" -// #include "DataFormatsParameters/GRPObject.h" -// #include "DetectorsBase/GeometryManager.h" -// #include "DetectorsBase/Propagator.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -56,16 +49,11 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::dilepton::utils; -// using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; using namespace o2::aod::pwgem::dilepton::utils::pairutil; struct DileptonPolarization { // Configurables 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 skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; - // Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; Configurable cfgPairType{"cfgPairType", 0, "0:dielectron, 1:dimuon"}; Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; diff --git a/PWGEM/Dilepton/Tasks/evaluateAcceptance.cxx b/PWGEM/Dilepton/Tasks/evaluateAcceptance.cxx index 9a552f407ae..5ad4d765e25 100644 --- a/PWGEM/Dilepton/Tasks/evaluateAcceptance.cxx +++ b/PWGEM/Dilepton/Tasks/evaluateAcceptance.cxx @@ -19,24 +19,10 @@ #include "Common/Core/RecoDecay.h" #include "Common/Core/TableHelper.h" -// #include "Common/Core/trackUtilities.h" -// #include "Common/DataModel/Centrality.h" -// #include "Common/DataModel/CollisionAssociationTables.h" -// #include "Common/DataModel/EventSelection.h" -// #include "Common/DataModel/Multiplicity.h" -// #include "Common/DataModel/TrackSelectionTables.h" - #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" #include "CommonConstants/PhysicsConstants.h" #include "DataFormatsParameters/GRPLHCIFData.h" - -// #include "DataFormatsCalibration/MeanVertexObject.h" -// #include "DataFormatsParameters/GRPMagField.h" -// #include "DataFormatsParameters/GRPObject.h" -// #include "DetectorsBase/GeometryManager.h" -// #include "DetectorsBase/Propagator.h" - #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" diff --git a/PWGEM/Dilepton/Tasks/eventQC.cxx b/PWGEM/Dilepton/Tasks/eventQC.cxx index 0b1f4b3e0ef..c21d08c6248 100644 --- a/PWGEM/Dilepton/Tasks/eventQC.cxx +++ b/PWGEM/Dilepton/Tasks/eventQC.cxx @@ -14,14 +14,11 @@ // This code is for event QC for PWG-EM. // Please write to: daiki.sekihata@cern.ch -// #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" - #include "Common/Core/RecoDecay.h" #include "Common/Core/Zorro.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/Qvectors.h" diff --git a/PWGEM/Dilepton/Tasks/matchingMFT.cxx b/PWGEM/Dilepton/Tasks/matchingMFT.cxx index e38648e48d0..ca2f912594e 100644 --- a/PWGEM/Dilepton/Tasks/matchingMFT.cxx +++ b/PWGEM/Dilepton/Tasks/matchingMFT.cxx @@ -16,7 +16,6 @@ #include "TableHelper.h" #include "Common/CCDB/RCTSelectionFlags.h" -#include "Common/Core/RecoDecay.h" #include "Common/Core/fwdtrackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" @@ -52,7 +51,7 @@ using namespace o2::constants::physics; using namespace o2::aod::fwdtrackutils; struct matchingMFT { - using MyCollisions = soa::Join; + using MyCollisions = soa::Join; using MyFwdTracks = soa::Join; using MyMFTTracks = soa::Join; @@ -97,17 +96,44 @@ struct matchingMFT { Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; Configurable cfgApplyPreselectionInBestMatch{"cfgApplyPreselectionInBestMatch", false, "flag to apply preselection in find best match function"}; - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", -1.f, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; - Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; - - // for RCT - Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; - Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_muon_glo", "select 1 [CBT_muon, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; - Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; - Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + + // Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + // Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + // Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + // Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + // Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + // Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + // Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + // Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_muon_glo", "select 1 [CBT_muon, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2, NTPV:3, NGlobal:4"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + // Configurable cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + // Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; + } eventcuts; o2::aod::rctsel::RCTFlagsChecker rctChecker; @@ -125,7 +151,7 @@ struct matchingMFT { ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); ccdbApi.init(ccdburl); - rctChecker.init(cfgRCTLabel.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); addHistograms(); } @@ -186,6 +212,8 @@ struct matchingMFT { fRegistry.add("Event/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); fRegistry.add("Event/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); fRegistry.add("Event/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/hCentNTPV", "hCentNTPV;centrality NTPV (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/hCentNGlo", "hCentNGlo;centrality NGlo (%)", kTH1F, {{110, 0, 110}}, false); fRegistry.add("Event/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {600, 0, 6000}}, false); fRegistry.add("Event/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", kTH2F, {{60, 0, 60000}, {600, 0, 6000}}, false); @@ -199,8 +227,8 @@ struct matchingMFT { const AxisSpec axis_pt{{0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10}, "p_{T}^{gl} (GeV/c)"}; fRegistry.add("MFTMCHMID/primary/correct/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{100, 0.0f, 10}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -5.f, -1.f}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -5.f, -1.f}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {200, -4.f, -2.f}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {200, -4.f, -2.f}}, false); fRegistry.add("MFTMCHMID/primary/correct/hsDelta", "diff. between GL and associated SA;p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl};#eta^{sa} - #eta^{gl};#varphi^{sa} - #varphi^{gl} (rad.);", kTHnSparseF, {axis_pt, {200, -0.5, +0.5}, {200, -1, +1}, {90, -M_PI / 4, M_PI / 4}}, false); fRegistry.add("MFTMCHMID/primary/correct/hsDeltaAtMP", "diff. XY between MFT and MCH-MID at MP;p_{T}^{gl} (GeV/c);X^{MCH-MID} - X^{MFT};Y^{MCH-MID} - Y^{MFT};", kTHnSparseF, {axis_pt, {100, -50, 50}, {100, -50, 50}}, false); fRegistry.add("MFTMCHMID/primary/correct/hDiffCollId", "difference in collision index;collisionId_{TTCA} - collisionId_{MP}", kTH1F, {{41, -20.5, +20.5}}, false); @@ -210,11 +238,11 @@ struct matchingMFT { fRegistry.add("MFTMCHMID/primary/correct/hMFTClusterMap", "MFT cluster map", kTH1F, {{1024, -0.5, 1023.5}}, false); fRegistry.add("MFTMCHMID/primary/correct/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1F, {{100, 0.0f, 100}}, false); fRegistry.add("MFTMCHMID/primary/correct/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hChi2", "chi2;chi2/ndf", kTH1F, {{100, 0.0f, 10}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hChi2MFT", "chi2 MFT/ndf;chi2 MFT/ndf", kTH1F, {{100, 0.0f, 10}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{100, 0.0f, 100}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{100, 0.0f, 100}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -0.5, 0.5}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2_Pt", "chi2;p_{T,#mu} (GeV/c);chi2/ndf", kTH2F, {{100, 0, 10}, {100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2MFT_Pt", "chi2 MFT/ndf;p_{T,#mu} (GeV/c);chi2 MFT/ndf", kTH2F, {{100, 0, 10}, {100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2MatchMCHMID_Pt", "chi2 match MCH-MID;p_{T,#mu} (GeV/c);chi2", kTH2F, {{100, 0, 10}, {100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2MatchMCHMFT_Pt", "chi2 match MCH-MFT;p_{T,#mu} (GeV/c);chi2", kTH2F, {{100, 0, 10}, {100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -0.1, 0.1}, {200, -0.1, +0.1}}, false); fRegistry.add("MFTMCHMID/primary/correct/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); fRegistry.add("MFTMCHMID/primary/correct/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1F, {{100, 0, 1}}, false); fRegistry.add("MFTMCHMID/primary/correct/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); @@ -227,7 +255,7 @@ struct matchingMFT { fRegistry.add("MFTMCHMID/primary/correct/hMIDBitMap", "MID bit map;MID bit map", kTH1F, {{256, -0.5, 255.5}}, false); fRegistry.add("MFTMCHMID/primary/correct/hdR_Chi2MatchMCHMFT", "dr vs. matching chi2 MCH-MFT;chi2 match MCH-MFT;#DeltaR;", kTH2F, {{200, 0, 50}, {200, 0, 0.5}}, false); fRegistry.add("MFTMCHMID/primary/correct/hCorrectAsocc", "correct fwdtrack-to-collision association", kTH1F, {{2, -0.5, +1.5}}, false); - fRegistry.add("MFTMCHMID/primary/correct/hIsCA", "cellular automaton;isCA", kTH1F, {{2, -0.5, 1.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hIsCA", "cellular automaton;p_{T,#mu} (GeV/c);isCA", kTH2F, {{100, 0, 10}, {2, -0.5, 1.5}}, false); fRegistry.add("MFTMCHMID/primary/correct/hProdVtxZ", "prod. vtx Z of muon;V_{z} (cm)", kTH1F, {{200, -100, 100}}, false); fRegistry.add("MFTMCHMID/primary/correct/hRelDeltaPt", "pT resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 10}, {200, -1, +1}}, false); fRegistry.add("MFTMCHMID/primary/correct/hDeltaEta_Pos", "#eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 10}, {400, -0.2, +0.2}}, false); @@ -238,12 +266,13 @@ struct matchingMFT { fRegistry.addClone("MFTMCHMID/primary/", "MFTMCHMID/secondary/"); fRegistry.add("MFT/primary/hPt", "pT;p_{T} (GeV/c)", kTH1D, {{1000, 0.0f, 10}}, false); - fRegistry.add("MFT/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2D, {{180, 0, 2 * M_PI}, {80, -5.f, -1.f}}, false); + fRegistry.add("MFT/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2D, {{180, 0, 2 * M_PI}, {200, -4.f, -2.f}}, false); + fRegistry.add("MFT/primary/hXY", "inner most XY;X (cm);Y (cm)", kTH2D, {{300, -15, 15}, {300, -15, 15}}, false); fRegistry.add("MFT/primary/hSign", "sign;sign", kTH1D, {{3, -1.5, +1.5}}, false); fRegistry.add("MFT/primary/hChi2MFT", "chi2 MFT/ndf;chi2 MFT/ndf", kTH1D, {{100, 0.0f, 10}}, false); fRegistry.add("MFT/primary/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1D, {{11, -0.5f, 10.5}}, false); fRegistry.add("MFT/primary/hMFTClusterMap", "MFT cluster map", kTH1D, {{1024, -0.5, 1023.5}}, false); - fRegistry.add("MFT/primary/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2D, {{200, -0.5, 0.5}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFT/primary/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2D, {{200, -0.1, 0.1}, {200, -0.1, +0.1}}, false); fRegistry.add("MFT/primary/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1D, {{100, 0, 1}}, false); fRegistry.add("MFT/primary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm);", kTH2D, {{100, 0, 1}, {200, -0.1, 0.1}}, false); fRegistry.add("MFT/primary/hProdVtxZ", "prod. vtx Z of track;V_{z} (cm)", kTH1D, {{200, -100, 100}}, false); @@ -253,10 +282,60 @@ struct matchingMFT { fRegistry.add("MFT/primary/hDeltaPhi_Pos", "#varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2D, {{200, 0, 10}, {400, -0.2, +0.2}}, false); fRegistry.add("MFT/primary/hDeltaPhi_Neg", "#varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2D, {{200, 0, 10}, {400, -0.2, +0.2}}, false); fRegistry.add("MFT/primary/hCorrectAsocc", "correct mfttrack-to-collision association", kTH1F, {{2, -0.5, +1.5}}, false); - fRegistry.add("MFT/primary/hIsCA", "cellular automaton;isCA", kTH1F, {{2, -0.5, 1.5}}, false); + fRegistry.add("MFT/primary/hIsCA", "cellular automaton;p_{T,#mu} (GeV/c);isCA", kTH2F, {{100, 0, 10}, {2, -0.5, 1.5}}, false); fRegistry.addClone("MFT/primary/", "MFT/secondary/"); } + template + bool isSelectedEvent(TCollision const& collision) + { + if (eventcuts.cfgRequireSel8 && !collision.sel8()) { + return false; + } + + if (collision.posZ() < eventcuts.cfgZvtxMin || eventcuts.cfgZvtxMax < collision.posZ()) { + return false; + } + + if (eventcuts.cfgRequireFT0AND && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + + if (eventcuts.cfgRequireNoTFB && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + if (eventcuts.cfgRequireNoITSROFB && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + + if (eventcuts.cfgRequireNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + + if (eventcuts.cfgRequireGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + + if (eventcuts.cfgRequireVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + + if (eventcuts.cfgRequireVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + + if (!(eventcuts.cfgTrackOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgTrackOccupancyMax)) { + return false; + } + + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + return false; + } + + return true; + } + bool isSelected(const float pt, const float eta, const float rAtAbsorberEnd, const float pDCA, const float chi2_per_ndf, const uint8_t trackType, const float dcaXY) { if (pt < minPt || maxPt < pt) { @@ -343,26 +422,6 @@ struct matchingMFT { // } // } - // template - // float cpaRZ(TCollision const& collision, TTrackParCovFwd const& fwdtrack) - // { - // float lx = fwdtrack.getX() - collision.posX(); // flight length X - // float ly = fwdtrack.getY() - collision.posY(); // flight length Y - // float lz = fwdtrack.getZ() - collision.posZ(); // flight length Z - // float lt = RecoDecay::sqrtSumOfSquares(lx, ly); // flight length R, i.e. transverse plane. - - // float pt = fwdtrack.getPt(); - // float pz = fwdtrack.getPz(); - - // float cpaRZ = RecoDecay::dotProd(std::array{lt, lz}, std::array{pt, pz}) / (RecoDecay::sqrtSumOfSquares(lt, lz) * RecoDecay::sqrtSumOfSquares(pt, pz)); - // if (cpaRZ < -1.f) { - // return -1.f; - // } else if (cpaRZ > 1.f) { - // return 1.f; - // } - // return cpaRZ; - // } - template void getDxDyAtMatchingPlane(TCollision const& collision, TFwdTrack const& fwdtrack, TMFTrackCov const& mftCovs, float& dx, float& dy) { @@ -571,10 +630,10 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/primary/correct/hMFTClusterMap"), mftClusterMap(mfttrack)); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hRatAbsorberEnd"), rAtAbsorberEnd); - fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2"), fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); - fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MFT"), chi2mft); - fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2_Pt"), pt, fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MFT_Pt"), pt, chi2mft); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MatchMCHMID_Pt"), pt, fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MatchMCHMFT_Pt"), pt, fwdtrack.chi2MatchMCHMFT()); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxy2D"), dcaX, dcaY); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxy"), dcaXY); @@ -584,7 +643,7 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/primary/correct/hMCHBitMap"), fwdtrack.mchBitMap()); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hMIDBitMap"), fwdtrack.midBitMap()); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hCorrectAsocc"), mcParticle_MCHMID.mcCollisionId() == collision.mcCollisionId()); - fRegistry.fill(HIST("MFTMCHMID/primary/correct/hIsCA"), mfttrack.isCA()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hIsCA"), pt, mfttrack.isCA()); fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um @@ -611,10 +670,10 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hMFTClusterMap"), mftClusterMap(mfttrack)); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hRatAbsorberEnd"), rAtAbsorberEnd); - fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2"), fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); - fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MFT"), chi2mft); - fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2_Pt"), pt, fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MFT_Pt"), pt, chi2mft); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MatchMCHMID_Pt"), pt, fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MatchMCHMFT_Pt"), pt, fwdtrack.chi2MatchMCHMFT()); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxy2D"), dcaX, dcaY); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxy"), dcaXY); @@ -624,7 +683,7 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hMCHBitMap"), fwdtrack.mchBitMap()); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hMIDBitMap"), fwdtrack.midBitMap()); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hCorrectAsocc"), mcParticle_MCHMID.mcCollisionId() == collision.mcCollisionId()); - fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hIsCA"), mfttrack.isCA()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hIsCA"), pt, mfttrack.isCA()); fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um @@ -653,10 +712,10 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hMFTClusterMap"), mftClusterMap(mfttrack)); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hRatAbsorberEnd"), rAtAbsorberEnd); - fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2"), fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); - fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MFT"), chi2mft); - fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2_Pt"), pt, fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MFT_Pt"), pt, chi2mft); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MatchMCHMID_Pt"), pt, fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MatchMCHMFT_Pt"), pt, fwdtrack.chi2MatchMCHMFT()); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxy2D"), dcaX, dcaY); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxy"), dcaXY); @@ -666,7 +725,7 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hMCHBitMap"), fwdtrack.mchBitMap()); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hMIDBitMap"), fwdtrack.midBitMap()); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hCorrectAsocc"), mcParticle_MCHMID.mcCollisionId() == collision.mcCollisionId()); - fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hIsCA"), mfttrack.isCA()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hIsCA"), pt, mfttrack.isCA()); fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um @@ -693,10 +752,10 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hMFTClusterMap"), mftClusterMap(mfttrack)); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hRatAbsorberEnd"), rAtAbsorberEnd); - fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2"), fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); - fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MFT"), chi2mft); - fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2_Pt"), pt, fwdtrack.chi2() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MFT_Pt"), pt, chi2mft); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MatchMCHMID_Pt"), pt, fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MatchMCHMFT_Pt"), pt, fwdtrack.chi2MatchMCHMFT()); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxy2D"), dcaX, dcaY); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxy"), dcaXY); @@ -706,7 +765,7 @@ struct matchingMFT { fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hMCHBitMap"), fwdtrack.mchBitMap()); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hMIDBitMap"), fwdtrack.midBitMap()); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hCorrectAsocc"), mcParticle_MCHMID.mcCollisionId() == collision.mcCollisionId()); - fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hIsCA"), mfttrack.isCA()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hIsCA"), pt, mfttrack.isCA()); fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um @@ -734,6 +793,8 @@ struct matchingMFT { fRegistry.fill(HIST("Event/hCentFT0A"), collision.centFT0A()); fRegistry.fill(HIST("Event/hCentFT0C"), collision.centFT0C()); fRegistry.fill(HIST("Event/hCentFT0M"), collision.centFT0M()); + fRegistry.fill(HIST("Event/hCentNTPV"), collision.centNTPV()); + fRegistry.fill(HIST("Event/hCentNGlo"), collision.centNGlobal()); fRegistry.fill(HIST("Event/hCentFT0CvsMultNTracksPV"), collision.centFT0C(), collision.multNTracksPV()); fRegistry.fill(HIST("Event/hMultFT0CvsMultNTracksPV"), collision.multFT0C(), collision.multNTracksPV()); } @@ -872,11 +933,11 @@ struct matchingMFT { if (!collision.has_mcCollision()) { continue; } - if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { continue; } - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + float centralities[5] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV(), collision.centNGlobal()}; + if (centralities[eventcuts.cfgCentEstimator] < eventcuts.cfgCentMin || eventcuts.cfgCentMax < centralities[eventcuts.cfgCentEstimator]) { continue; } @@ -946,6 +1007,7 @@ struct matchingMFT { if (isPrimary) { fRegistry.fill(HIST("MFT/primary/hPt"), pt); fRegistry.fill(HIST("MFT/primary/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFT/primary/hXY"), mfttrack.x(), mfttrack.y()); fRegistry.fill(HIST("MFT/primary/hSign"), mfttrack.sign()); fRegistry.fill(HIST("MFT/primary/hNclustersMFT"), mfttrack.nClusters()); fRegistry.fill(HIST("MFT/primary/hChi2MFT"), mfttrack.chi2() / ndf); @@ -954,7 +1016,7 @@ struct matchingMFT { fRegistry.fill(HIST("MFT/primary/hDCAxy"), dcaXY); fRegistry.fill(HIST("MFT/primary/hDCAxyz"), dcaXY, dcaZ); fRegistry.fill(HIST("MFT/primary/hCorrectAsocc"), mcParticle.mcCollisionId() == collision.mcCollisionId()); - fRegistry.fill(HIST("MFT/primary/hIsCA"), mfttrack.isCA()); + fRegistry.fill(HIST("MFT/primary/hIsCA"), pt, mfttrack.isCA()); fRegistry.fill(HIST("MFT/primary/hProdVtxZ"), mcParticle.vz()); fRegistry.fill(HIST("MFT/primary/hRelDeltaPt"), mcParticle.pt(), (pt - mcParticle.pt()) / mcParticle.pt()); @@ -969,6 +1031,7 @@ struct matchingMFT { } else { fRegistry.fill(HIST("MFT/secondary/hPt"), pt); fRegistry.fill(HIST("MFT/secondary/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFT/secondary/hXY"), mfttrack.x(), mfttrack.y()); fRegistry.fill(HIST("MFT/secondary/hSign"), mfttrack.sign()); fRegistry.fill(HIST("MFT/secondary/hNclustersMFT"), mfttrack.nClusters()); fRegistry.fill(HIST("MFT/secondary/hChi2MFT"), mfttrack.chi2() / ndf); @@ -977,7 +1040,7 @@ struct matchingMFT { fRegistry.fill(HIST("MFT/secondary/hDCAxy"), dcaXY); fRegistry.fill(HIST("MFT/secondary/hDCAxyz"), dcaXY, dcaZ); fRegistry.fill(HIST("MFT/secondary/hCorrectAsocc"), mcParticle.mcCollisionId() == collision.mcCollisionId()); - fRegistry.fill(HIST("MFT/secondary/hIsCA"), mfttrack.isCA()); + fRegistry.fill(HIST("MFT/secondary/hIsCA"), pt, mfttrack.isCA()); fRegistry.fill(HIST("MFT/secondary/hProdVtxZ"), mcParticle.vz()); fRegistry.fill(HIST("MFT/secondary/hRelDeltaPt"), mcParticle.pt(), (pt - mcParticle.pt()) / mcParticle.pt()); @@ -1002,8 +1065,8 @@ struct matchingMFT { Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; - Filter collisionFilter_evsel = o2::aod::evsel::sel8 == true && (cfgZvtxMin < o2::aod::collision::posZ && o2::aod::collision::posZ < cfgZvtxMax); - Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilter_evsel = eventcuts.cfgZvtxMin < o2::aod::collision::posZ && o2::aod::collision::posZ < eventcuts.cfgZvtxMax; + Filter collisionFilter_centrality = (eventcuts.cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcuts.cfgCentMax); using FilteredMyCollisions = soa::Filtered; void processWithoutFTTCA(FilteredMyCollisions const& collisions, MyFwdTracks const& fwdtracks, MyMFTTracks const& mfttracks, aod::BCsWithTimestamps const&, aod::McParticles const&) @@ -1028,11 +1091,16 @@ struct matchingMFT { if (!collision.has_mcCollision()) { continue; } - if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + + if (!isSelectedEvent(collision)) { + continue; + } + + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { continue; } - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + float centralities[5] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV(), collision.centNGlobal()}; + if (centralities[eventcuts.cfgCentEstimator] < eventcuts.cfgCentMin || eventcuts.cfgCentMax < centralities[eventcuts.cfgCentEstimator]) { continue; } fRegistry.fill(HIST("Event/hCollisionCounter"), 1); @@ -1045,9 +1113,9 @@ struct matchingMFT { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } fillHistograms(collision, fwdtrack, fwdtracks, mfttracks, nullptr); } // end of fwdtrack loop @@ -1081,11 +1149,14 @@ struct matchingMFT { if (!collision.has_mcCollision()) { continue; } - if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + if (!isSelectedEvent(collision)) { continue; } - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + float centralities[5] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV(), collision.centNGlobal()}; + if (centralities[eventcuts.cfgCentEstimator] < eventcuts.cfgCentMin || eventcuts.cfgCentMax < centralities[eventcuts.cfgCentEstimator]) { continue; } fRegistry.fill(HIST("Event/hCollisionCounter"), 1); @@ -1098,9 +1169,9 @@ struct matchingMFT { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } fillHistograms(collision, fwdtrack, fwdtracks, mfttracks, nullptr); } // end of fwdtrack loop @@ -1141,11 +1212,14 @@ struct matchingMFT { if (!collision.has_mcCollision()) { continue; } - if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + if (!isSelectedEvent(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { continue; } - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + float centralities[5] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV(), collision.centNGlobal()}; + if (centralities[eventcuts.cfgCentEstimator] < eventcuts.cfgCentMin || eventcuts.cfgCentMax < centralities[eventcuts.cfgCentEstimator]) { continue; } fRegistry.fill(HIST("Event/hCollisionCounter"), 1); @@ -1158,9 +1232,10 @@ struct matchingMFT { continue; } - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - continue; - } + // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + // continue; + // } + fillHistograms(collision, fwdtrack, fwdtracks, mfttracks, mftCovs); } // end of fwdtrack loop } // end of collision loop diff --git a/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx b/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx index c384f47a749..c2ac0b75d80 100644 --- a/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx +++ b/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx @@ -17,13 +17,8 @@ #include "PWGEM/Dilepton/Core/DielectronCut.h" #include "PWGEM/Dilepton/Core/EMEventCut.h" #include "PWGEM/Dilepton/DataModel/dileptonTables.h" -#include "PWGEM/Dilepton/Utils/EMTrack.h" -#include "PWGEM/Dilepton/Utils/EventHistograms.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" - #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" @@ -47,8 +42,6 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; -using namespace o2::aod::pwgem::dilepton::utils::pairutil; struct prefilterDielectron { using MyCollisions = soa::Join; @@ -129,8 +122,8 @@ struct prefilterDielectron { Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", false, "flag to require ITS ib 1st hit"}; Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; - Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; - Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + // Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + // Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; // Configurable cfgRefR{"cfgRefR", 1.2, "reference R (in m) for extrapolation"}; // https://cds.cern.ch/record/1419204 Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif : 4, kPIDML : 5, kTPChadrejORTOFreq_woTOFif : 6]"}; @@ -256,7 +249,6 @@ struct prefilterDielectron { fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); } - o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -289,8 +281,9 @@ struct prefilterDielectron { fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); fDielectronCut.SetChi2TOF(0, dielectroncuts.cfg_max_chi2tof); - fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + // fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + fDielectronCut.EnableTTCA(dielectroncuts.enableTTCA); // for eID fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); @@ -313,31 +306,6 @@ struct prefilterDielectron { thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); } fDielectronCut.SetMLThresholds(binsML, thresholdsML); - - // static constexpr int nClassesMl = 2; - // const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; - // const std::vector labelsClasses = {"Signal", "Background"}; - // const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; - // const std::vector labelsBins(nBinsMl, "bin"); - // double cutsMlArr[nBinsMl][nClassesMl]; - // for (uint32_t i = 0; i < nBinsMl; i++) { - // cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; - // cutsMlArr[i][1] = 0.; - // } - // o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; - - // mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); - // if (dielectroncuts.loadModelsFromCCDB) { - // ccdbApi.init(ccdburl); - // mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); - // } else { - // mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); - // } - // mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); - // mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); - // mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); - - // fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); } // end of PID ML } diff --git a/PWGEM/Dilepton/Tasks/testBremsstrahlung.cxx b/PWGEM/Dilepton/Tasks/testBremsstrahlung.cxx index 9897c101b5f..f5f01ae4cfe 100644 --- a/PWGEM/Dilepton/Tasks/testBremsstrahlung.cxx +++ b/PWGEM/Dilepton/Tasks/testBremsstrahlung.cxx @@ -37,8 +37,6 @@ #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" -// #include "TGeoGlobalMagField.h" - #include #include #include diff --git a/PWGEM/Dilepton/Utils/EMFwdTrack.h b/PWGEM/Dilepton/Utils/EMFwdTrack.h index 7f59bb67a1d..510aa5f3533 100644 --- a/PWGEM/Dilepton/Utils/EMFwdTrack.h +++ b/PWGEM/Dilepton/Utils/EMFwdTrack.h @@ -51,9 +51,9 @@ class EMFwdTrack float e() const { return std::hypot(fPt * std::cosh(fEta), fMass); } // e2 = p2 + m2 float signed1Pt() const { return fCharge * 1.f / fPt; } - float cXXatDCA() const { return fCXX; } - float cXYatDCA() const { return fCXY; } - float cYYatDCA() const { return fCYY; } + float cXX() const { return fCXX; } + float cXY() const { return fCXY; } + float cYY() const { return fCYY; } protected: float fPt; @@ -68,5 +68,73 @@ class EMFwdTrack float fCYY; }; +class EMFwdTrackWithCov : public EMFwdTrack +{ + public: + EMFwdTrackWithCov(float pt, float eta, float phi, float mass, int8_t charge, float dcaX, float dcaY, float cXX, float cXY, float cYY, + float X = 0.f, float Y = 0.f, float Z = 0.f, float tgl = 0.f, + float cPhiX = 0.f, float cPhiY = 0.f, float cPhiPhi = 0.f, + float cTglX = 0.f, float cTglY = 0.f, float cTglPhi = 0.f, float cTglTgl = 0.f, + float c1PtX = 0.f, float c1PtY = 0.f, float c1PtPhi = 0.f, float c1PtTgl = 0.f, float c1Pt21Pt2 = 0.f, float chi2 = 0.f) : EMFwdTrack(pt, eta, phi, mass, charge, dcaX, dcaY, cXX, cXY, cYY) + { + fX = X; + fY = Y; + fZ = Z; + fTgl = tgl; + fCPhiX = cPhiX; + fCPhiY = cPhiY; + fCPhiPhi = cPhiPhi; + fCTglX = cTglX; + fCTglY = cTglY; + fCTglPhi = cTglPhi; + fCTglTgl = cTglTgl; + fC1PtX = c1PtX; + fC1PtY = c1PtY; + fC1PtPhi = c1PtPhi; + fC1PtTgl = c1PtTgl; + fC1Pt21Pt2 = c1Pt21Pt2; + fChi2 = chi2; + } + + ~EMFwdTrackWithCov() {} + + float x() const { return fX; } + float y() const { return fY; } + float z() const { return fZ; } + float tgl() const { return fTgl; } + float cPhiX() const { return fCPhiX; } + float cPhiY() const { return fCPhiY; } + float cPhiPhi() const { return fCPhiPhi; } + float cTglX() const { return fCTglX; } + float cTglY() const { return fCTglY; } + float cTglPhi() const { return fCTglPhi; } + float cTglTgl() const { return fCTglTgl; } + float c1PtX() const { return fC1PtX; } + float c1PtY() const { return fC1PtY; } + float c1PtPhi() const { return fC1PtPhi; } + float c1PtTgl() const { return fC1PtTgl; } + float c1Pt21Pt2() const { return fC1Pt21Pt2; } + float chi2() const { return fChi2; } + + protected: + float fX; + float fY; + float fZ; + float fTgl; + float fCPhiX; + float fCPhiY; + float fCPhiPhi; + float fCTglX; + float fCTglY; + float fCTglPhi; + float fCTglTgl; + float fC1PtX; + float fC1PtY; + float fC1PtPhi; + float fC1PtTgl; + float fC1Pt21Pt2; + float fChi2; // chi2 not chi2/ndf +}; + } // namespace o2::aod::pwgem::dilepton::utils #endif // PWGEM_DILEPTON_UTILS_EMFWDTRACK_H_ diff --git a/PWGEM/Dilepton/Utils/EMTrack.h b/PWGEM/Dilepton/Utils/EMTrack.h index d50e9d1fe2c..1ac2f442f7e 100644 --- a/PWGEM/Dilepton/Utils/EMTrack.h +++ b/PWGEM/Dilepton/Utils/EMTrack.h @@ -75,11 +75,11 @@ class EMTrackWithCov : public EMTrack { public: EMTrackWithCov(float pt, float eta, float phi, float mass, int8_t charge = 0, float dcaXY = 0.f, float dcaZ = 0.f, - float X = 0.f, float Y = 0.f, float Z = 0.f, float Alpha = 0.f, float Snp = 0.f, float Tgl = 0.f, float CYY = 0.f, float CZY = 0.f, float CZZ = 0.f, + float X = 0.f, float Y = 0.f, float Z = 0.f, float Alpha = 0.f, float Snp = 0.f, float Tgl = 0.f, float CSnpY = 0.f, float CSnpZ = 0.f, float CSnpSnp = 0.f, float CTglY = 0.f, float CTglZ = 0.f, float CTglSnp = 0.f, float CTglTgl = 0.f, - float C1PtY = 0.f, float C1PtZ = 0.f, float C1PtSnp = 0.f, float C1PtTgl = 0.f, float C1Pt21Pt2 = 0.f) : EMTrack(pt, eta, phi, mass, charge, dcaXY, dcaZ) + float C1PtY = 0.f, float C1PtZ = 0.f, float C1PtSnp = 0.f, float C1PtTgl = 0.f, float C1Pt21Pt2 = 0.f) : EMTrack(pt, eta, phi, mass, charge, dcaXY, dcaZ, CYY, CZY, CZZ) { fX = X; fY = Y; diff --git a/PWGEM/Dilepton/Utils/EMTrackUtilities.h b/PWGEM/Dilepton/Utils/EMTrackUtilities.h index 414a7735bd4..88daecccb62 100644 --- a/PWGEM/Dilepton/Utils/EMTrackUtilities.h +++ b/PWGEM/Dilepton/Utils/EMTrackUtilities.h @@ -20,7 +20,9 @@ #include #include +#include #include +#include #include //_______________________________________________________________________ @@ -45,14 +47,16 @@ enum class RefTrackBit : uint16_t { // This is not for leptons, but charged trac }; enum class RefMFTTrackBit : uint16_t { // This is not for leptons, but charged tracks for reference flow. - kNclsMFT7 = 1, // default is 6 - kNclsMFT8 = 2, - kChi2MFT4 = 4, // default is 5 - kChi2MFT3 = 8, - kDCAxy004cm = 16, // default is 0.05 cm - kDCAxy003cm = 32, - kDCAxy002cm = 64, - kDCAxy001cm = 128, + kNclsMFT6 = 1, // default is 5 + kNclsMFT7 = 2, + kNclsMFT8 = 4, + kChi2MFT3 = 8, // default is 4 + kChi2MFT2 = 16, + kDCAxy005cm = 32, // default is 0.06 cm + kDCAxy004cm = 64, + kDCAxy003cm = 128, + kDCAxy002cm = 256, + kDCAxy001cm = 512, }; //_______________________________________________________________________ @@ -97,9 +101,9 @@ float dcaZinSigma(T const& track) template float fwdDcaXYinSigma(T const& track) { - float cXX = track.cXXatDCA(); // in cm^2 - float cYY = track.cYYatDCA(); // in cm^2 - float cXY = track.cXYatDCA(); // in cm^2 + float cXX = track.cXX(); // in cm^2 + float cYY = track.cYY(); // in cm^2 + float cXY = track.cXY(); // in cm^2 float dcaX = track.fwdDcaX(); // in cm float dcaY = track.fwdDcaY(); // in cm float det = cXX * cYY - cXY * cXY; // determinant @@ -134,37 +138,72 @@ bool checkMFTHitMap(T const& track) return (clmap > 0); } //_______________________________________________________________________ -template +template bool isBestMatch(TTrack const& track, TCut const& cut, TTracks const& tracks) { + // find the best glboal muon without pt, eta cut (ie. without single track acceptance cut) to keep possibility for unfolding. + // this is only for global muons at forward rapidity // Be careful! tracks are fwdtracks per DF. if (track.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + bool isBestFromMCHMID2MFT = false; + bool isBestFromMFT2MCHMID = false; std::map map_chi2MCHMFT; + + // 1 MFTsa track can match several MCH-MID tracks. find best global muon per MFTsa. map_chi2MCHMFT[track.globalIndex()] = track.chi2MatchMCHMFT(); // add myself for (const auto& glmuonId : track.globalMuonsWithSameMFTIds()) { - const auto& candidate = tracks.rawIteratorAt(glmuonId); - if (candidate.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && candidate.emeventId() == track.emeventId()) { - if (cut.template IsSelectedTrack(candidate)) { + auto candidate = tracks.rawIteratorAt(glmuonId); + if (candidate.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && candidate.emeventId() == track.emeventId() && candidate.mchtrackId() != track.mchtrackId()) { + if (cut.template IsSelectedTrack(candidate)) { map_chi2MCHMFT[candidate.globalIndex()] = candidate.chi2MatchMCHMFT(); } } } // end of glmuonId - auto it = std::min_element(map_chi2MCHMFT.begin(), map_chi2MCHMFT.end(), [](decltype(map_chi2MCHMFT)::value_type& l, decltype(map_chi2MCHMFT)::value_type& r) -> bool { return l.second < r.second; }); // search for minimum matching-chi2 + auto it0 = std::min_element(map_chi2MCHMFT.begin(), map_chi2MCHMFT.end(), [](decltype(map_chi2MCHMFT)::value_type& l, decltype(map_chi2MCHMFT)::value_type& r) -> bool { return l.second < r.second; }); // search for minimum matching-chi2 + if (it0->first == track.globalIndex()) { + isBestFromMFT2MCHMID = true; + } else { + isBestFromMFT2MCHMID = false; + } + map_chi2MCHMFT.clear(); - if (it->first == track.globalIndex()) { - map_chi2MCHMFT.clear(); - return true; + // find best global muon per MCH-MID tracks. Keep in mind that there are 5 global muons per MCH-MID in pp/OO and 20 global muons per MCH-MID in PbPb. + map_chi2MCHMFT[track.globalIndex()] = track.chi2MatchMCHMFT(); // add myself + for (const auto& glmuonId : track.globalMuonsWithSameMCHMIDIds()) { + auto candidate = tracks.rawIteratorAt(glmuonId); + if (candidate.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && candidate.emeventId() == track.emeventId() && candidate.mfttrackId() != track.mfttrackId()) { + if (cut.template IsSelectedTrack(candidate)) { + map_chi2MCHMFT[candidate.globalIndex()] = candidate.chi2MatchMCHMFT(); + } + } + } // end of glmuonId + + auto it1 = std::min_element(map_chi2MCHMFT.begin(), map_chi2MCHMFT.end(), [](decltype(map_chi2MCHMFT)::value_type& l, decltype(map_chi2MCHMFT)::value_type& r) -> bool { return l.second < r.second; }); // search for minimum matching-chi2 + if (it1->first == track.globalIndex()) { + isBestFromMCHMID2MFT = true; } else { - map_chi2MCHMFT.clear(); - return false; + isBestFromMCHMID2MFT = false; } + map_chi2MCHMFT.clear(); + + return isBestFromMCHMID2MFT && isBestFromMFT2MCHMID; } else { return true; } } //_______________________________________________________________________ +template +std::unordered_map findBestMatchMap(TTracks const& tracks, TCut const& cut) +{ + std::unordered_map map; + for (const auto& track : tracks) { + map[track.globalIndex()] = isBestMatch(track, cut, tracks); + } + return map; +} +//_______________________________________________________________________ // template // float sigmaPt(T const& track) // { diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h index 57ed3fb4a2b..3f10f83d55f 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h @@ -295,9 +295,9 @@ class EMCPhotonCut : public TNamed const bool doQA = mDoQA && fRegistry != nullptr; nTotClusterPerColl = 0; - currentCollID = clusters.iteratorAt(0).emphotoneventId(); + currentCollID = clusters.iteratorAt(0).pmeventId(); for (const auto& cluster : clusters) { - const auto collID = cluster.emphotoneventId(); + const auto collID = cluster.pmeventId(); if (doQA) { fillBeforeClusterHistogram(cluster, fRegistry); } @@ -376,7 +376,7 @@ class EMCPhotonCut : public TNamed } return false; } - if (currentCollID == cluster.emphotoneventId()) { + if (currentCollID == cluster.pmeventId()) { ++nAccClusterPerColl; } else { if (doQA) { diff --git a/PWGEM/PhotonMeson/Core/EMNonLin.cxx b/PWGEM/PhotonMeson/Core/EMNonLin.cxx index 571d7efbae8..5c44ecc9f0c 100644 --- a/PWGEM/PhotonMeson/Core/EMNonLin.cxx +++ b/PWGEM/PhotonMeson/Core/EMNonLin.cxx @@ -16,56 +16,40 @@ #include "EMNonLin.h" #include +#include using namespace o2::pwgem::nonlin; -float EMNonLin::getCorrectionFactor(float x, const Context& ctx) +float EMNonLin::getCorrectionFactor(float var, const Context& ctx) { - if (!ctx.params || x == 0.f) [[unlikely]] { - return x; + if (!ctx.params || var == 0.f) [[unlikely]] { + return 1.f; } int maxIter = std::min(ctx.nIter, MaxIter - 1); - - float scale = 1.f; // cumulative scale - float refVal = x; // reference value for computing next scale + float scale = 1.f; // cumulative scale + float refVal = var; // reference value updated each iteration for (int i = 0; i <= maxIter; ++i) { if (refVal == 0.f) { break; } - const auto& p = ctx.params[i]; - // scale function (x + a + b/x)/(x + c) which goes towards 1 for large x since x >> a,b,c -> x/x = 1 - float iterScale = - (refVal + p.par0 + p.par1 / refVal) / - (refVal + p.par2); + // evaluate pol1 for each parameter at this centrality + float a = p.a0 + p.a1 * ctx.cent; + float b = p.b0 + p.b1 * ctx.cent; + float c = p.c0 + p.c1 * ctx.cent; - scale *= iterScale; // total scale = product over itertaion scale - refVal = x * scale; // next iteration uses scaled original input - } - return scale; -} - -const EMNonLin::NonLinParams* EMNonLin::resolveParams(PhotonType type, float cent) -{ - int centBin = static_cast(cent / 10.f); - if (centBin < 0) - centBin = 0; - if (centBin >= CentBins) - centBin = CentBins - 1; - - return &kNonLinTable[static_cast(type)][centBin][0]; -} + // guard against c <= 0 which would make pow(x, -c) diverge + if (c <= 0.f) { + continue; + } -const EMNonLin::NonLinParams* EMNonLin::resolveParamsMC(PhotonType type, float cent) -{ - int centBin = static_cast(cent / 10.f); - if (centBin < 0) - centBin = 0; - if (centBin >= CentBins) - centBin = CentBins - 1; + float iterScale = a + b * std::pow(refVal, -c); + scale *= iterScale; + refVal = var * scale; // next iteration uses scaled original input + } - return &kNonLinTableMC[static_cast(type)][centBin][0]; + return scale; } diff --git a/PWGEM/PhotonMeson/Core/EMNonLin.h b/PWGEM/PhotonMeson/Core/EMNonLin.h index e9bce15c260..d272d9e5593 100644 --- a/PWGEM/PhotonMeson/Core/EMNonLin.h +++ b/PWGEM/PhotonMeson/Core/EMNonLin.h @@ -18,290 +18,134 @@ #include -#include // uint8_t +#include + +#include +#include namespace o2::pwgem::nonlin { +constexpr int MaxCent = 100.f; + /// \class EMNonLin /// \brief Class to obtain non linear correction factors for PbPb. +/// Parameters are loaded from CCDB (TMatrixD: rows = iterations, cols = 6 pol1 coefficients). +/// Falls back to hardcoded static table if CCDB object is not available. +/// The correction is of type a + b * refVal^(-c), where a, b and c are themselves described by linear functions over centrality. class EMNonLin { public: - static constexpr int MaxIter = 2; + static constexpr int MaxIter = 2; // hard cap on iterations static constexpr int PhotonN = 3; - static constexpr int CentBins = 10; + static constexpr int NCols = 6; // a0, a1, b0, b1, c0, c1 enum class PhotonType : uint8_t { kEMC = 0, kPCM = 1, - kPHOS = 2 // just in case + kPHOS = 2 }; struct NonLinParams { - float par0{0.f}; - float par1{0.f}; - float par2{0.f}; + float a0{1.f}, a1{0.f}; // pol1 params for a: asymptote + float b0{0.f}, b1{0.f}; // pol1 params for b: magnitude + float c0{0.f}, c1{0.f}; // pol1 params for c: exponent }; struct Context { const NonLinParams* params = nullptr; int nIter = 0; + float cent = 0.f; + /// \brief Sets parameters for the NonLin. Used with EMNonLin::resolveParams() + /// \param newParams pointer to new NonLinParams void setParams(const NonLinParams* newParams) { params = newParams; } + /// \brief Sets iteration used for the NonLin. + /// \param iter iteration void setIter(int iter) { - if (iter < 0 || iter >= MaxIter) { - nIter = MaxIter - 1; - return; - } + nIter = (iter < 0 || iter >= MaxIter) ? MaxIter - 1 : iter; + } - nIter = iter; + /// \brief Sets current centrality. + /// \param centrality centrality + void setCent(float centrality) + { + cent = (centrality >= MaxCent) ? MaxCent : centrality; } }; - /// \brief gets the correction value for energy or pT for a specific - /// \param inputCalibValue pT or energy of the photon that needs calibration - /// \param ctx Context which has the centrality, photontype and number of iterations stored inside - static float getCorrectionFactor(float inputCalibValue, const Context& ctx); - - /// \brief sets the parameters accordingly to the photon type, centrality and the wanted iteration level - /// \param photonType type of the photon (e.g. 0 for EMC) - /// \param cent centrality of the current collision in case the correction is centrality dependent - static const NonLinParams* resolveParams(PhotonType type, float cent); - - /// \brief sets the parameters accordingly to the photon type, centrality and the wanted iteration level for MC - /// \param photonType type of the photon (e.g. 0 for EMC) - /// \param cent centrality of the current collision in case the correction is centrality dependent - static const NonLinParams* resolveParamsMC(PhotonType type, float cent); + /// \brief Load parameters from a TMatrixD fetched from CCDB. + /// Rows = iterations, cols = {a0, a1, b0, b1, c0, c1}. + /// Overwrites the static fallback for this photon type. + /// \param mat pointer to TMatrixD from CCDB (may be nullptr) + /// \param type photon type to fill + void getFromCCDBObject(const TMatrixD* mat, PhotonType type) + { + int iType = static_cast(type); + if (!mat || mat->GetNcols() != NCols) { + mCCDBLoaded[iType] = false; + return; + } + int nIter = std::min(mat->GetNrows(), MaxIter); + for (int i = 0; i < nIter; ++i) { + mCCDBParams[iType][i] = { + static_cast((*mat)(i, 0)), static_cast((*mat)(i, 1)), + static_cast((*mat)(i, 2)), static_cast((*mat)(i, 3)), + static_cast((*mat)(i, 4)), static_cast((*mat)(i, 5))}; + } + mCCDBLoaded[iType] = true; + } + + /// \brief Compute the multiplicative correction factor for energy/pT. + /// \param par energy or pT of the photon + /// \param ctx context holding centrality, iteration level, and params pointer + static float getCorrectionFactor(float var, const Context& ctx); + + /// \brief Return pointer to the params array for a given photon type. + /// \returns CCDB-loaded params if available, otherwise the static fallback. + const NonLinParams* resolveParams(PhotonType type) const + { + int iType = static_cast(type); + return mCCDBLoaded[iType] ? &mCCDBParams[iType][0] : &FallbackTable[iType][0]; + } private: - static constexpr NonLinParams kNonLinTable - [PhotonN][CentBins][MaxIter] = - { - // ============================ - // PhotonType::kEMC (0) - // ============================ - { - // 00–10 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, // iter 0 - {0.f, 0.f, 0.f} // iter 1 - }, - // 10–20 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 20–30 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 30–40 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 40–50 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 50–60 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 60–70 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 70–80 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 80–90 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 90–100 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}}, - - // ============================ - // PhotonType::kPCM (1) - // ============================ - { - // 00–10 - { - {10.7203f, 0.0383968f, 10.6025f}, // iter 0 - {7.84549f, 0.0250021f, 7.86976f} // iter 1 - }, - // 10–20 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 20–30 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 30–40 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 40–50 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 50–60 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 60–70 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 70–80 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 80–90 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 90–100 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}}, - - // ============================ - // PhotonType::kPHOS (2) - // ============================ - { - // All centralities identical - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}}}; - - static constexpr NonLinParams kNonLinTableMC - [PhotonN][CentBins][MaxIter] = - { - // ============================ - // PhotonType::kEMC (0) - // ============================ - { - // 00–10 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, // iter 0 - {0.f, 0.f, 0.f} // iter 1 - }, - // 10–20 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 20–30 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 30–40 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 40–50 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 50–60 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 60–70 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 70–80 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 80–90 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}, - // 90–100 - { - {-5.33426e-01f, 1.40144e-02f, -5.24434e-01f}, - {0.f, 0.f, 0.f}}}, - - // ============================ - // PhotonType::kPCM (1) - // ============================ - { - // 00–10 - { - {10.7203f, 0.0383968f, 10.6025f}, // iter 0 - {7.84549f, 0.0250021f, 7.86976f} // iter 1 - }, - // 10–20 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 20–30 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 30–40 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 40–50 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 50–60 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 60–70 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 70–80 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 80–90 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}, - // 90–100 - { - {10.7203f, 0.0383968f, 10.6025f}, - {7.84549f, 0.0250021f, 7.86976f}}}, + NonLinParams mCCDBParams[PhotonN][MaxIter] = {}; // Runtime params loaded from CCDB (per photon type, per iteration) + bool mCCDBLoaded[PhotonN] = {false, false, false}; + + // ------------------------------------------------------- + // Static fallback tables (used when CCDB object is absent) + // ------------------------------------------------------- + static constexpr NonLinParams FallbackTable[PhotonN][MaxIter] = { + // kEMC + {{1.f, 0.f, 0.f, 0.f, 0.f, 0.f}, + {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}}, + // kPCM + {{1.f, 0.f, 0.010417f, -1.09508e-05f, 0.355795f, 0.00427618f}, + {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}}, + // kPHOS + {{1.f, 0.f, 0.f, 0.f, 0.f, 0.f}, + {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}}, + }; - // ============================ - // PhotonType::kPHOS (2) - // ============================ - { - // All centralities identical - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}, - {{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}}}}; + static constexpr NonLinParams FallbackTableMC[PhotonN][MaxIter] = { + // kEMC + {{1.f, 0.f, 0.f, 0.f, 0.f, 0.f}, + {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}}, + // kPCM + {{1.f, 0.f, 0.010417f, -1.09508e-05f, 0.355795f, 0.00427618f}, + {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}}, + // kPHOS + {{1.f, 0.f, 0.f, 0.f, 0.f, 0.f}, + {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}}, + }; }; + } // namespace o2::pwgem::nonlin #endif // PWGEM_PHOTONMESON_CORE_EMNONLIN_H_ diff --git a/PWGEM/PhotonMeson/Core/EmMlResponsePCM.h b/PWGEM/PhotonMeson/Core/EmMlResponsePCM.h index baa9330ad95..b46e258353c 100644 --- a/PWGEM/PhotonMeson/Core/EmMlResponsePCM.h +++ b/PWGEM/PhotonMeson/Core/EmMlResponsePCM.h @@ -53,20 +53,47 @@ namespace o2::analysis { enum class InputFeaturesPCM : uint8_t { + v0PhotonCandidatefVx, + v0PhotonCandidatefVy, + v0PhotonCandidatefVz, v0PhotonCandidatefDCAxyToPV, v0PhotonCandidatefDCAzToPV, v0PhotonCandidatefPCA, v0PhotonCandidatefAlpha, v0PhotonCandidatefQtArm, v0PhotonCandidatefChiSquareNDF, + v0PhotonCandidatefCosPARZ, + v0PhotonCandidatefCosPAXY, v0PhotonCandidatefCosPA, + v0PhotonCandidatefPsiPair, + v0PhotonCandidatefPhiV, + posV0LegfDCAXY, + posV0LegfDCAZ, + posV0LegfEta, + posV0LegfTPCNClsShared, + posV0LegfTPCNClsFindable, + posV0LegfTPCNClsFindableMinusFound, + posV0LegfTPCNClsFindableMinusCrossedRows, + posV0LegfTPCChi2NCl, + posV0LegfTPCSignal, posV0LegfTPCNSigmaEl, posV0LegfTPCNSigmaPi, + posV0LegfITSClusterSizes, + negV0LegfDCAXY, + negV0LegfDCAZ, + negV0LegfEta, + negV0LegfTPCNClsShared, + negV0LegfTPCNClsFindable, + negV0LegfTPCNClsFindableMinusFound, + negV0LegfTPCNClsFindableMinusCrossedRows, + negV0LegfTPCChi2NCl, + negV0LegfTPCSignal, negV0LegfTPCNSigmaEl, - negV0LegfTPCNSigmaPi + negV0LegfTPCNSigmaPi, + negV0LegfITSClusterSizes }; -template +template class EmMlResponsePCM : public EmMlResponse { public: @@ -85,17 +112,44 @@ class EmMlResponsePCM : public EmMlResponse for (const auto& idx : MlResponse::mCachedIndices) { switch (idx) { + CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefVx, getConversionPointX); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefVy, getConversionPointY); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefVz, getConversionPointZ); CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefDCAxyToPV, getDcaXYToPV); CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefDCAzToPV, getDcaZToPV); CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefPCA, getPCA); CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefAlpha, getAlpha); CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefQtArm, getQt); CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefChiSquareNDF, getChi2NDF); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefCosPARZ, getCosPARZ); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefCosPAXY, getCosPAXY); CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefCosPA, getCosPA); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefPsiPair, getPsiPair); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, v0PhotonCandidatefPhiV, getPhiV); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfDCAXY, getPosDcaXY); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfDCAZ, getPosDcaZ); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfEta, getPosEta); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfTPCNClsShared, getPosTPCNClsShared); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfTPCNClsFindable, getPosTPCNClsFindable); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfTPCNClsFindableMinusFound, getPosTPCNClsFindableMinusShared); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfTPCNClsFindableMinusCrossedRows, getPosTPCNClsFindableMinusCrossedRows); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfTPCChi2NCl, getPosTPCChi2NCl); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfTPCSignal, getPosTPCSignal); CHECK_AND_FILL_VEC_PCM_FULL(posLeg, posV0LegfTPCNSigmaEl, tpcNSigmaEl); CHECK_AND_FILL_VEC_PCM_FULL(posLeg, posV0LegfTPCNSigmaPi, tpcNSigmaPi); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, posV0LegfITSClusterSizes, getPosITSClusterSizes); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfDCAXY, getEleDcaXY); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfDCAZ, getEleDcaZ); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfEta, getEleEta); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfTPCNClsShared, getEleTPCNClsShared); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfTPCNClsFindable, getEleTPCNClsFindable); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfTPCNClsFindableMinusFound, getEleTPCNClsFindableMinusShared); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfTPCNClsFindableMinusCrossedRows, getEleTPCNClsFindableMinusCrossedRows); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfTPCChi2NCl, getEleTPCChi2NCl); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfTPCSignal, getEleTPCSignal); CHECK_AND_FILL_VEC_PCM_FULL(negLeg, negV0LegfTPCNSigmaEl, tpcNSigmaEl); CHECK_AND_FILL_VEC_PCM_FULL(negLeg, negV0LegfTPCNSigmaPi, tpcNSigmaPi); + CHECK_AND_FILL_VEC_PCM_FULL(candidate, negV0LegfITSClusterSizes, getEleITSClusterSizes); } } return inputFeatures; @@ -106,17 +160,44 @@ class EmMlResponsePCM : public EmMlResponse void setAvailableInputFeatures() { MlResponse::mAvailableInputFeatures = { + FILL_MAP_PCM(v0PhotonCandidatefVx), + FILL_MAP_PCM(v0PhotonCandidatefVy), + FILL_MAP_PCM(v0PhotonCandidatefVz), FILL_MAP_PCM(v0PhotonCandidatefDCAxyToPV), FILL_MAP_PCM(v0PhotonCandidatefDCAzToPV), FILL_MAP_PCM(v0PhotonCandidatefPCA), FILL_MAP_PCM(v0PhotonCandidatefAlpha), FILL_MAP_PCM(v0PhotonCandidatefQtArm), FILL_MAP_PCM(v0PhotonCandidatefChiSquareNDF), + FILL_MAP_PCM(v0PhotonCandidatefCosPARZ), + FILL_MAP_PCM(v0PhotonCandidatefCosPAXY), FILL_MAP_PCM(v0PhotonCandidatefCosPA), + FILL_MAP_PCM(v0PhotonCandidatefPsiPair), + FILL_MAP_PCM(v0PhotonCandidatefPhiV), + FILL_MAP_PCM(posV0LegfDCAXY), + FILL_MAP_PCM(posV0LegfDCAZ), + FILL_MAP_PCM(posV0LegfEta), + FILL_MAP_PCM(posV0LegfTPCNClsShared), + FILL_MAP_PCM(posV0LegfTPCNClsFindable), + FILL_MAP_PCM(posV0LegfTPCNClsFindableMinusFound), + FILL_MAP_PCM(posV0LegfTPCNClsFindableMinusCrossedRows), + FILL_MAP_PCM(posV0LegfTPCChi2NCl), + FILL_MAP_PCM(posV0LegfTPCSignal), FILL_MAP_PCM(posV0LegfTPCNSigmaEl), FILL_MAP_PCM(posV0LegfTPCNSigmaPi), + FILL_MAP_PCM(posV0LegfITSClusterSizes), + FILL_MAP_PCM(negV0LegfDCAXY), + FILL_MAP_PCM(negV0LegfDCAZ), + FILL_MAP_PCM(negV0LegfEta), + FILL_MAP_PCM(negV0LegfTPCNClsShared), + FILL_MAP_PCM(negV0LegfTPCNClsFindable), + FILL_MAP_PCM(negV0LegfTPCNClsFindableMinusFound), + FILL_MAP_PCM(negV0LegfTPCNClsFindableMinusCrossedRows), + FILL_MAP_PCM(negV0LegfTPCChi2NCl), + FILL_MAP_PCM(negV0LegfTPCSignal), FILL_MAP_PCM(negV0LegfTPCNSigmaEl), - FILL_MAP_PCM(negV0LegfTPCNSigmaPi)}; + FILL_MAP_PCM(negV0LegfTPCNSigmaPi), + FILL_MAP_PCM(negV0LegfITSClusterSizes)}; } }; diff --git a/PWGEM/PhotonMeson/Core/MaterialBudgetWeights.h b/PWGEM/PhotonMeson/Core/MaterialBudgetWeights.h new file mode 100644 index 00000000000..094f86ceb8a --- /dev/null +++ b/PWGEM/PhotonMeson/Core/MaterialBudgetWeights.h @@ -0,0 +1,108 @@ +// 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 MaterialBudgetWeights.h +/// \brief This code produces a table to retrieve material budget weights. The table is to be join with V0PhotonKF +/// \author Youssef El Mard (youssef.el.mard.bouziani@cern.ch) + +#ifndef PWGEM_PHOTONMESON_CORE_MATERIALBUDGETWEIGHTS_H_ +#define PWGEM_PHOTONMESON_CORE_MATERIALBUDGETWEIGHTS_H_ + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using MyV0PhotonsMB = o2::soa::Join; +using MyV0PhotonMB = MyV0PhotonsMB::iterator; + +struct MaterialBudgetWeights { + o2::framework::Produces omegaMBWeight; + + o2::framework::Configurable ccdbUrl{"ccdbUrl", "http://ccdb-test.cern.ch:8080", "CCDB url"}; + o2::framework::Configurable mbWeightsPath{"mbWeightsPath", "Users/y/yelmard/MaterialBudget/OmegaMBWeights", "Path of the mb weights"}; + + o2::ccdb::CcdbApi ccdbApi; + TH1F* hOmegaMBFromCCDB = nullptr; + + void init(o2::framework::InitContext&) + { + // Load CCDB object only when the real process is enabled + if (!doprocessMC) { + LOG(info) << "MaterialBudgetWeights: dummy mode enabled -> no CCDB query, will write weight=1"; + return; + } + + ccdbApi.init(ccdbUrl.value); + std::map metadata; + LOG(info) << "MaterialBudgetWeights: loading Omega MB histogram from CCDB at path: " << mbWeightsPath.value; + + hOmegaMBFromCCDB = ccdbApi.retrieveFromTFileAny(mbWeightsPath, metadata, -1); + + if (!hOmegaMBFromCCDB) { + LOG(fatal) << "MaterialBudgetWeights: CCDB object is missing. Path=" << mbWeightsPath.value; + } + } + + float computeMBWeight(float v0Rxy) + { + if (!hOmegaMBFromCCDB) { + return 1.f; + } + + int binMBWeight = hOmegaMBFromCCDB->FindBin(v0Rxy); + if (binMBWeight < 1 || binMBWeight > hOmegaMBFromCCDB->GetNbinsX()) { + LOG(debug) << "MaterialBudgetWeights: v0Rxy out of histogram range, returning 1"; + return 1.f; + } + + return hOmegaMBFromCCDB->GetBinContent(binMBWeight); + } + + // real process (weights from CCDB) + void processMC(MyV0PhotonMB const& v0) + { + static bool once = false; + if (!once) { + LOG(info) << "MaterialBudgetWeights: standard process running"; + once = true; + } + if (!hOmegaMBFromCCDB) { // histogram not loaded => behave like dummy + omegaMBWeight(1.f); + return; + } + omegaMBWeight(computeMBWeight(v0.v0radius())); + } + + // dummy process (always weight = 1) + void processDummy(MyV0PhotonMB const&) + { + static bool once = false; + if (!once) { + LOG(info) << "MaterialBudgetWeights: processDummy running"; + once = true; + } + omegaMBWeight(1.f); + } + + PROCESS_SWITCH(MaterialBudgetWeights, processMC, "Fill MB weights from CCDB", false); + PROCESS_SWITCH(MaterialBudgetWeights, processDummy, "Fill dummy MB weights (=1)", true); +}; + +#endif // PWGEM_PHOTONMESON_CORE_MATERIALBUDGETWEIGHTS_H_ diff --git a/PWGEM/PhotonMeson/Core/PhotonHBT.h b/PWGEM/PhotonMeson/Core/PhotonHBT.h deleted file mode 100644 index 060768cdfde..00000000000 --- a/PWGEM/PhotonMeson/Core/PhotonHBT.h +++ /dev/null @@ -1,694 +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 PhotonHBT.h -/// \brief This code loops over v0 photons and makes pairs for photon HBT analysis. -/// \author Daiki Sekihata, daiki.sekihata@cern.ch - -#ifndef PWGEM_PHOTONMESON_CORE_PHOTONHBT_H_ -#define PWGEM_PHOTONMESON_CORE_PHOTONHBT_H_ - -#include "PWGEM/Dilepton/Utils/EMTrack.h" -#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" -#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" -// -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include // IWYU pragma: keep -#include -#include // IWYU pragma: keep -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace o2::aod::pwgem::photon::core::photonhbt -{ -enum class ggHBTPairType : int { - kPCMPCM = 0, -}; -} // namespace o2::aod::pwgem::photon::core::photonhbt - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::pwgem::dilepton::utils; -using namespace o2::aod::pwgem::photon::core::photonhbt; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyV0Photons = soa::Join; -using MyV0Photon = MyV0Photons::iterator; - -template -struct PhotonHBT { - // Configurables - - // 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 skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; - // Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; - - Configurable cfgDo3D{"cfgDo3D", false, "enable 3D analysis"}; - Configurable cfgEP2Estimator_for_Mix{"cfgEP2Estimator_for_Mix", 3, "FT0M:0, FT0A:1, FT0C:2, BTot:3, BPos:4, BNeg:5"}; - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; - Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; - Configurable maxY{"maxY", 0.8, "maximum rapidity for reconstructed particles"}; - Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; - Configurable ndepth{"ndepth", 100, "depth for event mixing"}; - Configurable ndiff_bc_mix{"ndiff_bc_mix", 594, "difference in global BC required in mixed events"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {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 ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f, 999.f}, "Mixing bins - centrality"}; - ConfigurableAxis ConfEPBins{"ConfEPBins", {16, -o2::constants::math::PIHalf, +o2::constants::math::PIHalf}, "Mixing bins - event plane angle"}; - ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; - Configurable cfgUseLCMS{"cfgUseLCMS", true, "measure relative momentum in LCMS for 1D"}; // always in LCMS for 3D - - ConfigurableAxis ConfQBins{"ConfQBins", {60, 0, +0.3f}, "q bins for output histograms"}; - ConfigurableAxis ConfKtBins{"ConfKtBins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0}, "kT bins for output histograms"}; - - EMPhotonEventCut fEMEventCut; - struct : ConfigurableGroup { - std::string prefix = "eventcut_group"; - Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; - Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; - Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; - Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; - Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; - Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border in event cut"}; - Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; - Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. - Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; - Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; - Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; - Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; - Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; - Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; - Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; - Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; - Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; - Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; - Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; - Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; - Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; - } eventcuts; - - V0PhotonCut fV0PhotonCut; - struct : ConfigurableGroup { - std::string prefix = "pcmcut_group"; - Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; - Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; - Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; - Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; - Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; - Configurable cfg_min_v0radius{"cfg_min_v0radius", 16.0, "min v0 radius"}; - Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; - Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; - Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; - Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; - Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; - Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; - Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; - - Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; - Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; - Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; - Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; - Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; - Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; - Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; - Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; - Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; - } pcmcuts; - - struct : ConfigurableGroup { - std::string prefix = "ggpaircut_group"; - Configurable cfgMinDR_CosOA{"cfgMinDR_CosOA", -1, "min. dr/cosOA for kPCMPCM"}; - } ggpaircuts; - - ~PhotonHBT() - { - delete emh1; - emh1 = 0x0; - delete emh2; - emh2 = 0x0; - - map_mixed_eventId_to_globalBC.clear(); - - used_photonIds_per_col.clear(); - used_photonIds_per_col.shrink_to_fit(); - } - - HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - // static constexpr std::string_view event_types[2] = {"before", "after"}; - static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; - - std::mt19937 engine; - std::uniform_int_distribution dist01; - - // o2::ccdb::CcdbApi ccdbApi; - // Service ccdb; - int mRunNumber; - // float d_bz; - - std::vector zvtx_bin_edges; - std::vector cent_bin_edges; - std::vector ep_bin_edges; - std::vector occ_bin_edges; - - void init(InitContext& /*context*/) - { - mRunNumber = 0; - // d_bz = 0; - - // ccdb->setURL(ccdburl); - // ccdb->setCaching(true); - // ccdb->setLocalObjectValidityChecking(); - // ccdb->setFatalWhenNull(false); - - if (ConfVtxBins.value[0] == VARIABLE_WIDTH) { - zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); - zvtx_bin_edges.erase(zvtx_bin_edges.begin()); - for (const auto& edge : zvtx_bin_edges) { - LOGF(info, "VARIABLE_WIDTH: zvtx_bin_edges = %f", edge); - } - } else { - int nbins = static_cast(ConfVtxBins.value[0]); - float xmin = static_cast(ConfVtxBins.value[1]); - float xmax = static_cast(ConfVtxBins.value[2]); - zvtx_bin_edges.resize(nbins + 1); - for (int i = 0; i < nbins + 1; i++) { - zvtx_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; - LOGF(info, "FIXED_WIDTH: zvtx_bin_edges[%d] = %f", i, zvtx_bin_edges[i]); - } - } - - if (ConfCentBins.value[0] == VARIABLE_WIDTH) { - cent_bin_edges = std::vector(ConfCentBins.value.begin(), ConfCentBins.value.end()); - cent_bin_edges.erase(cent_bin_edges.begin()); - for (const auto& edge : cent_bin_edges) { - LOGF(info, "VARIABLE_WIDTH: cent_bin_edges = %f", edge); - } - } else { - int nbins = static_cast(ConfCentBins.value[0]); - float xmin = static_cast(ConfCentBins.value[1]); - float xmax = static_cast(ConfCentBins.value[2]); - cent_bin_edges.resize(nbins + 1); - for (int i = 0; i < nbins + 1; i++) { - cent_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; - LOGF(info, "FIXED_WIDTH: cent_bin_edges[%d] = %f", i, cent_bin_edges[i]); - } - } - - if (ConfEPBins.value[0] == VARIABLE_WIDTH) { - ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); - ep_bin_edges.erase(ep_bin_edges.begin()); - for (const auto& edge : ep_bin_edges) { - LOGF(info, "VARIABLE_WIDTH: ep_bin_edges = %f", edge); - } - } else { - int nbins = static_cast(ConfEPBins.value[0]); - float xmin = static_cast(ConfEPBins.value[1]); - float xmax = static_cast(ConfEPBins.value[2]); - ep_bin_edges.resize(nbins + 1); - for (int i = 0; i < nbins + 1; i++) { - ep_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; - LOGF(info, "FIXED_WIDTH: ep_bin_edges[%d] = %f", i, ep_bin_edges[i]); - } - } - - LOGF(info, "cfgOccupancyEstimator = %d", cfgOccupancyEstimator.value); - if (ConfOccupancyBins.value[0] == VARIABLE_WIDTH) { - occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); - occ_bin_edges.erase(occ_bin_edges.begin()); - for (const auto& edge : occ_bin_edges) { - LOGF(info, "VARIABLE_WIDTH: occ_bin_edges = %f", edge); - } - } else { - int nbins = static_cast(ConfOccupancyBins.value[0]); - float xmin = static_cast(ConfOccupancyBins.value[1]); - float xmax = static_cast(ConfOccupancyBins.value[2]); - occ_bin_edges.resize(nbins + 1); - for (int i = 0; i < nbins + 1; i++) { - occ_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; - LOGF(info, "FIXED_WIDTH: occ_bin_edges[%d] = %f", i, occ_bin_edges[i]); - } - } - - emh1 = new MyEMH(ndepth); - emh2 = new MyEMH(ndepth); - - o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); - DefineEMEventCut(); - DefinePCMCut(); - - addhistograms(); - - std::random_device seed_gen; - engine = std::mt19937(seed_gen()); - dist01 = std::uniform_int_distribution(0, 1); - - fRegistry.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); - } - - template - void initCCDB(TCollision const& collision) - { - if (mRunNumber == collision.runNumber()) { - return; - } - - // // In case override, don't proceed, please - no CCDB access required - // if (d_bz_input > -990) { - // d_bz = d_bz_input; - // o2::parameters::GRPMagField grpmag; - // if (std::fabs(d_bz) > 1e-5) { - // grpmag.setL3Current(30000.f / (d_bz / 5.0f)); - // } - // mRunNumber = collision.runNumber(); - // return; - // } - - // auto run3grp_timestamp = collision.timestamp(); - // o2::parameters::GRPObject* grpo = 0x0; - // o2::parameters::GRPMagField* grpmag = 0x0; - // if (!skipGRPOquery) - // grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - // if (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; - // } - // // 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 = collision.runNumber(); - } - - void addhistograms() - { - // o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<-1>(&fRegistry); - static constexpr std::string_view qvec_det_names[6] = {"FT0M", "FT0A", "FT0C", "BTot", "BPos", "BNeg"}; - fRegistry.add("Event/before/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -o2::constants::math::PIHalf, +o2::constants::math::PIHalf}}, false); - fRegistry.add("Event/after/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -o2::constants::math::PIHalf, +o2::constants::math::PIHalf}}, false); - - // pair info - const AxisSpec axis_kt{ConfKtBins, "k_{T} (GeV/c)"}; - const AxisSpec axis_qinv{ConfQBins, "q_{inv} (GeV/c)"}; - const AxisSpec axis_qabs_lcms{ConfQBins, "|#bf{q}|^{LCMS} (GeV/c)"}; - const AxisSpec axis_qout{ConfQBins, "q_{out} (GeV/c)"}; // qout does not change between LAB and LCMS frame - const AxisSpec axis_qside{ConfQBins, "q_{side} (GeV/c)"}; // qside does not change between LAB and LCMS frame - const AxisSpec axis_qlong{ConfQBins, "q_{long} (GeV/c)"}; - - if (cfgDo3D) { // 3D - fRegistry.add("Pair/same/hs_3d", "diphoton correlation 3D LCMS", kTHnSparseD, {axis_qout, axis_qside, axis_qlong, axis_kt}, true); - } else { // 1D - if (cfgUseLCMS) { - fRegistry.add("Pair/same/hs_1d", "diphoton correlation 1D LCMS", kTHnSparseD, {axis_qabs_lcms, axis_kt}, true); - } else { - fRegistry.add("Pair/same/hs_1d", "diphoton correlation 1D", kTHnSparseD, {axis_qinv, axis_kt}, true); - } - } - - if constexpr (pairtype == ggHBTPairType::kPCMPCM) { - fRegistry.add("Pair/same/hDeltaRCosOA", "distance between 2 conversion points;#Deltar/cos(#theta_{op}/2) (cm)", kTH1D, {{100, 0, 100}}, true); // dr/cosOA of conversion points - } - - fRegistry.addClone("Pair/same/", "Pair/mix/"); - } - - void DefineEMEventCut() - { - fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); - fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); - fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); - fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); - fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); - fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); - fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); - fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); - fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); - fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); - fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); - fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); - fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); - fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); - fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); - } - - void DefinePCMCut() - { - fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); - - // for v0 - fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, 1e10f); - fV0PhotonCut.SetV0EtaRange(-pcmcuts.cfg_max_eta_v0, +pcmcuts.cfg_max_eta_v0); - fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); - fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); - fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); - fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); - fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); - fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); - - // for track - fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); - fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); - fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); - fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); - fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); - fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); - fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); - fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); - fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); - fV0PhotonCut.SetNClustersITS(0, 7); - fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); - fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); - fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); - fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); - } - - template - void fillPairHistogram(TCollision const&, const ROOT::Math::PtEtaPhiMVector v1, const ROOT::Math::PtEtaPhiMVector v2, const float weight = 1.f) - { - float rndm = std::pow(-1, dist01(engine) % 2); // +1 or -1 to randomize order between 1 and 2. - // Lab. frame - ROOT::Math::PtEtaPhiMVector q12 = (v1 - v2) * rndm; - ROOT::Math::PtEtaPhiMVector k12 = 0.5 * (v1 + v2); - float qinv = -q12.M(); // for identical particles -> qinv = 2 x kstar - float kt = k12.Pt(); - - ROOT::Math::XYZVector uv_out(k12.Px() / k12.Pt(), k12.Py() / k12.Pt(), 0); // unit vector for out. i.e. parallel to kt - ROOT::Math::XYZVector uv_long(0, 0, 1); // unit vector for long, beam axis - ROOT::Math::XYZVector uv_side = uv_out.Cross(uv_long); // unit vector for side - - ROOT::Math::PxPyPzEVector v1_cartesian(v1); - ROOT::Math::PxPyPzEVector v2_cartesian(v2); - ROOT::Math::PxPyPzEVector q12_cartesian = (v1_cartesian - v2_cartesian) * rndm; - float beta = (v1 + v2).Beta(); - // float beta_x = beta * std::cos((v1 + v2).Phi()) * std::sin((v1 + v2).Theta()); - // float beta_y = beta * std::sin((v1 + v2).Phi()) * std::sin((v1 + v2).Theta()); - float beta_z = beta * std::cos((v1 + v2).Theta()); - - // longitudinally co-moving system (LCMS) - ROOT::Math::Boost bst_z(0, 0, -beta_z); // Boost supports only PxPyPzEVector - ROOT::Math::PxPyPzEVector q12_lcms = bst_z(q12_cartesian); - ROOT::Math::XYZVector q_3d_lcms = q12_lcms.Vect(); // 3D q vector in LCMS - float qout_lcms = q_3d_lcms.Dot(uv_out); - float qside_lcms = q_3d_lcms.Dot(uv_side); - float qlong_lcms = q_3d_lcms.Dot(uv_long); - float qabs_lcms = q_3d_lcms.R(); - - // float qabs_lcms_tmp = std::sqrt(std::pow(qout_lcms, 2) + std::pow(qside_lcms, 2) + std::pow(qlong_lcms, 2)); - // LOGF(info, "qabs_lcms = %f, qabs_lcms_tmp = %f", qabs_lcms, qabs_lcms_tmp); - - // // pair rest frame (PRF) - // ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-beta_x, -beta_y, -beta_z); - // ROOT::Math::PxPyPzEVector v1_prf = boostPRF(v1_cartesian); - // ROOT::Math::PxPyPzEVector v2_prf = boostPRF(v2_cartesian); - // ROOT::Math::PxPyPzEVector rel_k = (v1_prf - v2_prf) * rndm; - // float kstar = 0.5 * rel_k.P(); - // // LOGF(info, "qabs_lcms = %f, qinv = %f, kstar = %f", qabs_lcms, qinv, kstar); - - // ROOT::Math::PxPyPzEVector v1_lcms_cartesian = bst_z(v1_cartesian); - // ROOT::Math::PxPyPzEVector v2_lcms_cartesian = bst_z(v2_cartesian); - // ROOT::Math::PxPyPzEVector q12_lcms_cartesian = bst_z(q12_cartesian); - // LOGF(info, "q12.Pz() = %f, q12_cartesian.Pz() = %f", q12.Pz(), q12_cartesian.Pz()); - // LOGF(info, "v1.Pz() = %f, v2.Pz() = %f", v1.Pz(), v2.Pz()); - // LOGF(info, "v1_lcms_cartesian.Pz() = %f, v2_lcms_cartesian.Pz() = %f", v1_lcms_cartesian.Pz(), v2_lcms_cartesian.Pz()); - // LOGF(info, "q12_lcms_cartesian.Pz() = %f", q12_lcms_cartesian.Pz()); - // LOGF(info, "q_3d_lcms.Dot(uv_out) = %f, q_3d_lcms.Dot(uv_side) = %f, q_3d.Dot(uv_out) = %f, q_3d.Dot(uv_side) = %f", q_3d_lcms.Dot(uv_out), q_3d_lcms.Dot(uv_side), q_3d.Dot(uv_out), q_3d.Dot(uv_side)); - // LOGF(info, "q12_lcms.Pz() = %f, q_3d_lcms.Dot(uv_long) = %f", q12_lcms.Pz(), q_3d_lcms.Dot(uv_long)); - // ROOT::Math::PxPyPzEVector q12_lcms_tmp = bst_z(v1_cartesian) - bst_z(v2_cartesian); - // LOGF(info, "q12_lcms.Px() = %f, q12_lcms.Py() = %f, q12_lcms.Pz() = %f, q12_lcms_tmp.Px() = %f, q12_lcms_tmp.Py() = %f, q12_lcms_tmp.Pz() = %f", q12_lcms.Px(), q12_lcms.Py(), q12_lcms.Pz(), q12_lcms_tmp.Px(), q12_lcms_tmp.Py(), q12_lcms_tmp.Pz()); - // float qabs_lcms_tmp = q12_lcms.P(); - // LOGF(info, "qabs_lcms = %f, qabs_lcms_tmp = %f", qabs_lcms, qabs_lcms_tmp); - - if (cfgDo3D) { - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_3d"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); // qosl can be [-inf, +inf] and CF is symmetric for pos and neg qosl. To reduce stat. unc. absolute value is taken here. - } else { - if (cfgUseLCMS) { - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_1d"), qabs_lcms, kt, weight); - } else { - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_1d"), qinv, kt, weight); - } - } - } - - template - void runPairing(TCollisions const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TSubInfos1 const&, TSubInfos2 const&, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCut1 const& cut1, TCut2 const& cut2) - { - for (const auto& collision : collisions) { - initCCDB(collision); - int ndiphoton = 0; - const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - const float eventplanes_2_for_mix[6] = {collision.ep2ft0m(), collision.ep2ft0a(), collision.ep2ft0c(), collision.ep2btot(), collision.ep2bpos(), collision.ep2bneg()}; - float ep2 = eventplanes_2_for_mix[cfgEP2Estimator_for_Mix]; - fRegistry.fill(HIST("Event/before/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); - - o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, 1.f); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, 1.f); - fRegistry.fill(HIST("Event/after/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); - - int zbin = lower_bound(zvtx_bin_edges.begin(), zvtx_bin_edges.end(), collision.posZ()) - zvtx_bin_edges.begin() - 1; - if (zbin < 0) { - zbin = 0; - } else if (static_cast(zvtx_bin_edges.size()) - 2 < zbin) { - zbin = static_cast(zvtx_bin_edges.size()) - 2; - } - - float centrality = centralities[cfgCentEstimator]; - int centbin = lower_bound(cent_bin_edges.begin(), cent_bin_edges.end(), centrality) - cent_bin_edges.begin() - 1; - if (centbin < 0) { - centbin = 0; - } else if (static_cast(cent_bin_edges.size()) - 2 < centbin) { - centbin = static_cast(cent_bin_edges.size()) - 2; - } - - int epbin = lower_bound(ep_bin_edges.begin(), ep_bin_edges.end(), ep2) - ep_bin_edges.begin() - 1; - if (epbin < 0) { - epbin = 0; - } else if (static_cast(ep_bin_edges.size()) - 2 < epbin) { - epbin = static_cast(ep_bin_edges.size()) - 2; - } - - int occbin = -1; - if (cfgOccupancyEstimator == 0) { - occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; - } else if (cfgOccupancyEstimator == 1) { - occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; - } else { - occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; - } - - if (occbin < 0) { - occbin = 0; - } else if (static_cast(occ_bin_edges.size()) - 2 < occbin) { - occbin = static_cast(occ_bin_edges.size()) - 2; - } - - // LOGF(info, "collision.globalIndex() = %d, collision.posZ() = %f, centrality = %f, ep2 = %f, collision.trackOccupancyInTimeRange() = %d, zbin = %d, centbin = %d, epbin = %d, occbin = %d", collision.globalIndex(), collision.posZ(), centrality, ep2, collision.trackOccupancyInTimeRange(), zbin, centbin, epbin, occbin); - - auto key_bin = std::make_tuple(zbin, centbin, epbin, occbin); - auto key_df_collision = std::make_pair(ndf, collision.globalIndex()); - - if constexpr (pairtype == ggHBTPairType::kPCMPCM) { - auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_coll, photons2_coll))) { - if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { - continue; - } - - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { // never happens. only for protection. - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - - float dr = std::sqrt(std::pow(g1.vx() - g2.vx(), 2) + std::pow(g1.vy() - g2.vy(), 2) + std::pow(g1.vz() - g2.vz(), 2)); - ROOT::Math::XYZVector cp1(g1.vx(), g1.vy(), g1.vz()); - ROOT::Math::XYZVector cp2(g2.vx(), g2.vy(), g2.vz()); - float opa = std::acos(cp1.Dot(cp2) / (std::sqrt(cp1.Mag2()) * std::sqrt(cp2.Mag2()))); // opening angle between 2 conversion points - o2::math_utils::bringTo02Pi(opa); - if (opa > o2::constants::math::PI) { - opa -= o2::constants::math::PI; - } - float cosOA = std::cos(opa / 2.f); - if (dr / cosOA < ggpaircuts.cfgMinDR_CosOA) { - continue; - } - fRegistry.fill(HIST("Pair/same/hDeltaRCosOA"), dr / cosOA); - - fillPairHistogram<0>(collision, v1, v2, 1.f); - ndiphoton++; - - if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { - EMPair g1tmp = EMPair(g1.pt(), g1.eta(), g1.phi(), 0); - g1tmp.setConversionPointXYZ(g1.vx(), g1.vy(), g1.vz()); - emh1->AddTrackToEventPool(key_df_collision, g1tmp); - used_photonIds_per_col.emplace_back(g1.globalIndex()); - } - if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g2.globalIndex()) == used_photonIds_per_col.end()) { - EMPair g2tmp = EMPair(g2.pt(), g2.eta(), g2.phi(), 0); - g2tmp.setConversionPointXYZ(g2.vx(), g2.vy(), g2.vz()); - emh1->AddTrackToEventPool(key_df_collision, g2tmp); - used_photonIds_per_col.emplace_back(g2.globalIndex()); - } - } // end of pairing loop - } - - used_photonIds_per_col.clear(); - used_photonIds_per_col.shrink_to_fit(); - - // event mixing - if (!cfgDoMix || !(ndiphoton > 0)) { - continue; - } - - // make a vector of selected photons in this collision. - auto selected_photons1_in_this_event = emh1->GetTracksPerCollision(key_df_collision); - auto selected_photons2_in_this_event = emh2->GetTracksPerCollision(key_df_collision); - - auto collisionIds1_in_mixing_pool = emh1->GetCollisionIdsFromEventPool(key_bin); - auto collisionIds2_in_mixing_pool = emh2->GetCollisionIdsFromEventPool(key_bin); - - if constexpr (pairtype == ggHBTPairType::kPCMPCM) { - for (const auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { - int mix_dfId = mix_dfId_collisionId.first; - int64_t mix_collisionId = mix_dfId_collisionId.second; - - if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. - continue; - } - - auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; - uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); - fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); - if (diffBC < ndiff_bc_mix) { - continue; - } - - auto photons1_from_event_pool = emh1->GetTracksPerCollision(mix_dfId_collisionId); - // LOGF(info, "Do event mixing: current event (%d, %d), ngamma = %d | event pool (%d, %d), ngamma = %d", ndf, collision.globalIndex(), selected_photons1_in_this_event.size(), mix_dfId, mix_collisionId, photons1_from_event_pool.size()); - - for (const auto& g1 : selected_photons1_in_this_event) { - for (const auto& g2 : photons1_from_event_pool) { - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - - float dr = std::sqrt(std::pow(g1.vx() - g2.vx(), 2) + std::pow(g1.vy() - g2.vy(), 2) + std::pow(g1.vz() - g2.vz(), 2)); - ROOT::Math::XYZVector cp1(g1.vx(), g1.vy(), g1.vz()); - ROOT::Math::XYZVector cp2(g2.vx(), g2.vy(), g2.vz()); - float opa = std::acos(cp1.Dot(cp2) / (std::sqrt(cp1.Mag2()) * std::sqrt(cp2.Mag2()))); // opening angle between 2 conversion points - o2::math_utils::bringTo02Pi(opa); - if (opa > o2::constants::math::PI) { - opa -= o2::constants::math::PI; - } - float cosOA = std::cos(opa / 2.f); - if (dr / cosOA < ggpaircuts.cfgMinDR_CosOA) { - continue; - } - fRegistry.fill(HIST("Pair/mix/hDeltaRCosOA"), dr / cosOA); - - fillPairHistogram<1>(collision, v1, v2, 1.f); - } - } - } // end of loop over mixed event pool - } - - if (ndiphoton > 0) { - emh1->AddCollisionIdAtLast(key_bin, key_df_collision); - emh2->AddCollisionIdAtLast(key_bin, key_df_collision); - map_mixed_eventId_to_globalBC[key_df_collision] = collision.globalBC(); - } - } // end of collision loop - } - - using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMPair>; - MyEMH* emh1 = nullptr; - MyEMH* emh2 = nullptr; - std::vector used_photonIds_per_col; // - std::map, uint64_t> map_mixed_eventId_to_globalBC; - - SliceCache cache; - Preslice perCollision_pcm = aod::v0photonkf::emphotoneventId; - - Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; - Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; - using FilteredMyCollisions = soa::Filtered; - - int ndf = 0; - void processAnalysis(FilteredMyCollisions const& collisions, Types const&... args) - { - if constexpr (pairtype == ggHBTPairType::kPCMPCM) { - auto v0photons = std::get<0>(std::tie(args...)); - auto v0legs = std::get<1>(std::tie(args...)); - runPairing(collisions, v0photons, v0photons, v0legs, v0legs, perCollision_pcm, perCollision_pcm, fV0PhotonCut, fV0PhotonCut); - } - ndf++; - } - PROCESS_SWITCH(PhotonHBT, processAnalysis, "pairing for analysis", false); - - void processDummy(MyCollisions const&) {} - PROCESS_SWITCH(PhotonHBT, processDummy, "Dummy function", true); -}; - -#endif // PWGEM_PHOTONMESON_CORE_PHOTONHBT_H_ diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h index 965d88ddcc0..1eb74391520 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h @@ -21,6 +21,7 @@ #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" #include "PWGEM/PhotonMeson/Utils/NMHistograms.h" @@ -69,6 +70,12 @@ #include #include +enum AlphaMesonCutOption { + Off = 0, + SpecificValue = 1, + PTDependent = 2 +}; + template struct Pi0EtaToGammaGamma { o2::framework::Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -91,6 +98,11 @@ struct Pi0EtaToGammaGamma { o2::framework::ConfigurableAxis ConfEPBins{"ConfEPBins", {o2::framework::VARIABLE_WIDTH, -o2::constants::math::PIHalf, -o2::constants::math::PIQuarter, 0.0f, +o2::constants::math::PIQuarter, +o2::constants::math::PIHalf}, "Mixing bins - event plane angle"}; o2::framework::ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {o2::framework::VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + o2::framework::Configurable cfgAlphaMesonCut{"cfgAlphaMesonCut", 0, "flag for photon energy asymmetry distribution cut: 0: no cut, 1: cut specific value, 2: cut depending on pT"}; + o2::framework::Configurable cfgAlphaMeson{"cfgAlphaMeson", 0.65, "photon energy asymmetry distribution parameter for specific value cut"}; + o2::framework::Configurable cfgAlphaMesonA{"cfgAlphaMesonA", 0.65, "photon energy asymmetry distribution parameter A for pT dependent cut (A * tanh(B*pT))"}; + o2::framework::Configurable cfgAlphaMesonB{"cfgAlphaMesonB", 1.2, "photon energy asymmetry distribution parameter B for pT dependent cut (A * tanh(B*pT))"}; + EMPhotonEventCut fEMEventCut; struct : o2::framework::ConfigurableGroup { std::string prefix = "eventcut_group"; @@ -226,10 +238,10 @@ struct Pi0EtaToGammaGamma { //--------------------------------------------------------------------------- // Preslices and partitions o2::framework::SliceCache cache; - o2::framework::PresliceOptional>> perCollision_pcm = o2::aod::v0photonkf::emphotoneventId; - o2::framework::PresliceOptional> perCollision_emc = o2::aod::emccluster::emphotoneventId; - o2::framework::PresliceOptional> perCollision_phos = o2::aod::phoscluster::emphotoneventId; - o2::framework::PresliceOptional>> perCollision_electron = o2::aod::emprimaryelectronda::emphotoneventId; + o2::framework::PresliceOptional>> perCollision_pcm = o2::aod::v0photonkf::pmeventId; + o2::framework::PresliceOptional> perCollision_emc = o2::aod::emccluster::pmeventId; + o2::framework::PresliceOptional> perCollision_phos = o2::aod::phoscluster::pmeventId; + o2::framework::PresliceOptional>> perCollision_electron = o2::aod::emprimaryelectronda::pmeventId; o2::framework::PresliceOptional perEMCClusterMT = o2::aod::trackmatching::emEmcClusterId; o2::framework::PresliceOptional perEMCClusterMS = o2::aod::trackmatching::emEmcClusterId; @@ -262,7 +274,7 @@ struct Pi0EtaToGammaGamma { static auto& perCollision() { - static auto slice{o2::aod::v0photonkf::emphotoneventId}; + static auto slice{o2::aod::v0photonkf::pmeventId}; return slice; } @@ -283,7 +295,7 @@ struct Pi0EtaToGammaGamma { static auto& perCollision() { - static auto slice{o2::aod::emccluster::emphotoneventId}; + static auto slice{o2::aod::emccluster::pmeventId}; return slice; } @@ -317,7 +329,7 @@ struct Pi0EtaToGammaGamma { static auto& perCollision() { - static auto slice{o2::aod::phoscluster::emphotoneventId}; + static auto slice{o2::aod::phoscluster::pmeventId}; return slice; } @@ -338,7 +350,7 @@ struct Pi0EtaToGammaGamma { static auto& perCollision() { - static auto slice{o2::aod::emprimaryelectronda::emphotoneventId}; + static auto slice{o2::aod::emprimaryelectronda::pmeventId}; return slice; } @@ -709,7 +721,7 @@ struct Pi0EtaToGammaGamma { } float weight = 1.f; - if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { + if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { weight = collision.weight(); } @@ -776,8 +788,8 @@ struct Pi0EtaToGammaGamma { if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMDalitzEE) { auto photons1_per_collision = photons1.sliceByCached(TDetectorTag1::perCollision(), collision.globalIndex(), cache); - auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); for (const auto& g1 : photons1_per_collision) { if constexpr (std::is_same_v) { @@ -879,7 +891,35 @@ struct Pi0EtaToGammaGamma { continue; } - fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt(), weight); + float alphaMeson = std::fabs(g1.e() - g2.e()) / (g1.e() + g2.e()); + float alphaCut = 999.f; + switch (static_cast(cfgAlphaMesonCut.value)) { + case AlphaMesonCutOption::Off: + break; + case AlphaMesonCutOption::SpecificValue: + alphaCut = cfgAlphaMeson; + break; + case AlphaMesonCutOption::PTDependent: { + alphaCut = cfgAlphaMesonA * std::tanh(cfgAlphaMesonB * v12.pt()); + break; + } + default: + LOGF(error, "Invalid option for alpha meson cut. No alpha cut will be applied."); + } + if (alphaMeson > alphaCut) { + continue; + } + + float wpair = weight; + + if constexpr (requires { g1.omegaMBWeight(); }) { + wpair *= g1.omegaMBWeight(); + } + if constexpr (requires { g2.omegaMBWeight(); }) { + wpair *= g2.omegaMBWeight(); + } + + fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt(), wpair); if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { emh1->AddTrackToEventPool(key_df_collision, o2::aod::pwgem::dilepton::utils::EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); @@ -1024,13 +1064,13 @@ struct Pi0EtaToGammaGamma { o2::framework::expressions::Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; o2::framework::expressions::Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; o2::framework::expressions::Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - // using FilteredMyCollisions = o2::soa::Filtered>; + // using FilteredMyCollisions = o2::soa::Filtered>; o2::framework::expressions::Filter prefilter_pcm = ifnode(pcmcuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::v0photonkf::pfbderived == static_cast(0), true); o2::framework::expressions::Filter prefilter_primaryelectron = ifnode(dileptoncuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::emprimaryelectron::pfbderived == static_cast(0), true); int ndf = 0; - void processAnalysis(o2::soa::Filtered> const& collisions, Types const&... args) + void processAnalysis(o2::soa::Filtered> const& collisions, Types const&... args) { // LOGF(info, "ndf = %d", ndf); if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM) { @@ -1066,8 +1106,8 @@ struct Pi0EtaToGammaGamma { } PROCESS_SWITCH(Pi0EtaToGammaGamma, processAnalysis, "process pair analysis", true); - // using FilteredMyCollisionsWithJJMC = o2::soa::Filtered, o2::aod::EMEventsWeight>>; - void processAnalysisJJMC(o2::soa::Filtered, o2::aod::EMEventsWeight>> const& collisions, Types const&... args) + // using FilteredMyCollisionsWithJJMC = o2::soa::Filtered, o2::aod::EMEventsWeight>>; + void processAnalysisJJMC(o2::soa::Filtered, o2::aod::EMEventsWeight>> const& collisions, Types const&... args) { // LOGF(info, "ndf = %d", ndf); if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM) { @@ -1094,7 +1134,7 @@ struct Pi0EtaToGammaGamma { } PROCESS_SWITCH(Pi0EtaToGammaGamma, processAnalysisJJMC, "process pair analysis", false); - void processDummy(o2::aod::EMEvents const&) {} + void processDummy(o2::aod::PMEvents const&) {} PROCESS_SWITCH(Pi0EtaToGammaGamma, processDummy, "Dummy function", false); }; #endif // PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMA_H_ diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h index a67295b4227..442cf9d13b6 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h @@ -21,6 +21,7 @@ #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" @@ -64,6 +65,12 @@ #include #include +enum AlphaMesonCutOption { + Off = 0, + SpecificValue = 1, + PTDependent = 2 +}; + template struct Pi0EtaToGammaGammaMC { o2::framework::Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -80,6 +87,11 @@ struct Pi0EtaToGammaGammaMC { o2::framework::Configurable fd_k0s_to_pi0{"fd_k0s_pi0", "1.0", "feed down correction to pi0"}; o2::framework::Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; + o2::framework::Configurable cfgAlphaMesonCut{"cfgAlphaMesonCut", 0, "flag for photon energy asymmetry distribution cut: 0: no cut, 1: cut specific value, 2: cut depending on pT"}; + o2::framework::Configurable cfgAlphaMeson{"cfgAlphaMeson", 0.65, "photon energy asymmetry distribution parameter for specific value cut"}; + o2::framework::Configurable cfgAlphaMesonA{"cfgAlphaMesonA", 0.65, "photon energy asymmetry distribution parameter A for pT dependent cut (A * tanh(B*pT))"}; + o2::framework::Configurable cfgAlphaMesonB{"cfgAlphaMesonB", 1.2, "photon energy asymmetry distribution parameter B for pT dependent cut (A * tanh(B*pT))"}; + EMPhotonEventCut fEMEventCut; struct : o2::framework::ConfigurableGroup { std::string prefix = "eventcut_group"; @@ -423,10 +435,10 @@ struct Pi0EtaToGammaGammaMC { } o2::framework::SliceCache cache; - o2::framework::PresliceOptional>> perCollision_pcm = o2::aod::v0photonkf::emphotoneventId; - o2::framework::PresliceOptional> perCollision_emc = o2::aod::emccluster::emphotoneventId; - o2::framework::PresliceOptional> perCollision_phos = o2::aod::phoscluster::emphotoneventId; - o2::framework::PresliceOptional>> perCollision_electron = o2::aod::emprimaryelectronda::emphotoneventId; + o2::framework::PresliceOptional>> perCollision_pcm = o2::aod::v0photonkf::pmeventId; + o2::framework::PresliceOptional> perCollision_emc = o2::aod::emccluster::pmeventId; + o2::framework::PresliceOptional> perCollision_phos = o2::aod::phoscluster::pmeventId; + o2::framework::PresliceOptional>> perCollision_electron = o2::aod::emprimaryelectronda::pmeventId; o2::framework::PresliceOptional perEMCClusterMT = o2::aod::trackmatching::emEmcClusterId; o2::framework::PresliceOptional perEMCClusterMS = o2::aod::trackmatching::emEmcClusterId; @@ -440,7 +452,7 @@ struct Pi0EtaToGammaGammaMC { static auto& perCollision() { - static auto slice{o2::aod::v0photonkf::emphotoneventId}; + static auto slice{o2::aod::v0photonkf::pmeventId}; return slice; } @@ -461,7 +473,7 @@ struct Pi0EtaToGammaGammaMC { static auto& perCollision() { - static auto slice{o2::aod::emccluster::emphotoneventId}; + static auto slice{o2::aod::emccluster::pmeventId}; return slice; } @@ -495,7 +507,7 @@ struct Pi0EtaToGammaGammaMC { static auto& perCollision() { - static auto slice{o2::aod::phoscluster::emphotoneventId}; + static auto slice{o2::aod::phoscluster::pmeventId}; return slice; } @@ -515,7 +527,7 @@ struct Pi0EtaToGammaGammaMC { struct DalitzEETag { static auto& perCollision() { - static auto slice{o2::aod::emprimaryelectronda::emphotoneventId}; + static auto slice{o2::aod::emprimaryelectronda::pmeventId}; return slice; } @@ -566,7 +578,7 @@ struct Pi0EtaToGammaGammaMC { } float weight = 1.f; - if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { + if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { weight = collision.weight(); } @@ -671,6 +683,34 @@ struct Pi0EtaToGammaGammaMC { continue; } + float alphaMeson = std::fabs(g1.e() - g2.e()) / (g1.e() + g2.e()); + float alphaCut = 999.f; + switch (static_cast(cfgAlphaMesonCut.value)) { + case AlphaMesonCutOption::Off: + break; + case AlphaMesonCutOption::SpecificValue: + alphaCut = cfgAlphaMeson; + break; + case AlphaMesonCutOption::PTDependent: { + alphaCut = cfgAlphaMesonA * std::tanh(cfgAlphaMesonB * v12.pt()); + break; + } + default: + LOGF(error, "Invalid option for alpha meson cut. No alpha cut will be applied."); + } + if (alphaMeson > alphaCut) { + continue; + } + + float wpair = weight; + + if constexpr (requires { g1.omegaMBWeight(); }) { + wpair *= g1.omegaMBWeight(); + } + if constexpr (requires { g2.omegaMBWeight(); }) { + wpair *= g2.omegaMBWeight(); + } + if (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kEMCEMC) { float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); if (openingAngle < emccuts.minOpenAngle) { @@ -680,9 +720,9 @@ struct Pi0EtaToGammaGammaMC { if (g1mc.globalIndex() == g2mc.globalIndex()) { if (o2::aod::pwgem::dilepton::utils::mcutil::getMotherPDGCode(g1mc, mcparticles) == 111) - fRegistry.fill(HIST("Pair/Pi0/hs_FromSameGamma"), v12.M(), v12.Pt(), weight); + fRegistry.fill(HIST("Pair/Pi0/hs_FromSameGamma"), v12.M(), v12.Pt(), wpair); else if (o2::aod::pwgem::dilepton::utils::mcutil::getMotherPDGCode(g1mc, mcparticles) == 221) - fRegistry.fill(HIST("Pair/Eta/hs_FromSameGamma"), v12.M(), v12.Pt(), weight); + fRegistry.fill(HIST("Pair/Eta/hs_FromSameGamma"), v12.M(), v12.Pt(), wpair); continue; } @@ -691,20 +731,20 @@ struct Pi0EtaToGammaGammaMC { if (cfgRequireTrueAssociation && (pi0mc.emmceventId() != collision.emmceventId())) { continue; } - o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, weight); + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, wpair); } else if (etaid > 0) { auto etamc = mcparticles.iteratorAt(etaid); if (cfgRequireTrueAssociation && (etamc.emmceventId() != collision.emmceventId())) { continue; } - o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, weight); + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, wpair); } } // end of pairing loop } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMDalitzEE) { auto photons1_per_collision = photons1.sliceByCached(TDetectorTag1::perCollision(), collision.globalIndex(), cache); - auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); for (const auto& g1 : photons1_per_collision) { if constexpr (std::is_same_v) { @@ -851,7 +891,7 @@ struct Pi0EtaToGammaGammaMC { } o2::framework::PresliceUnsorted perMcCollision = o2::aod::emmcparticle::emmceventId; - o2::framework::PresliceUnsorted> rec_perMcCollision = o2::aod::emmceventlabel::emmceventId; + o2::framework::PresliceUnsorted> rec_perMcCollision = o2::aod::emmceventlabel::emmceventId; template void runGenInfo(TCollisions const& collisions, TMCCollisions const& mccollisions, TMCParticles const& /*mcparticles*/) @@ -871,7 +911,7 @@ struct Pi0EtaToGammaGammaMC { } float weight = 1.f; - if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { + if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { weight = collision.weight(); } @@ -899,12 +939,12 @@ struct Pi0EtaToGammaGammaMC { o2::framework::expressions::Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; o2::framework::expressions::Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; o2::framework::expressions::Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - // using FilteredMyCollisions = o2::soa::Filtered>; + // using FilteredMyCollisions = o2::soa::Filtered>; o2::framework::expressions::Filter prefilter_pcm = ifnode(pcmcuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::v0photonkf::pfbderived == static_cast(0), true); o2::framework::expressions::Filter prefilter_primaryelectron = ifnode(dileptoncuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::emprimaryelectron::pfbderived == static_cast(0), true); - void processAnalysis(o2::soa::Filtered> const& collisions, o2::soa::Join const& mccollisions, o2::aod::EMMCParticles const& mcparticles, Types const&... args) + void processAnalysis(o2::soa::Filtered> const& collisions, o2::soa::Join const& mccollisions, o2::aod::EMMCParticles const& mcparticles, Types const&... args) { if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM) { auto&& [v0photons, v0legs] = std::forward_as_tuple(args...); @@ -939,8 +979,8 @@ struct Pi0EtaToGammaGammaMC { } PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processAnalysis, "process pair analysis", true); - // using FilteredMyCollisionsWithJJMC = o2::soa::Filtered, aod::EMEventsWeight>>; - void processAnalysisJJMC(o2::soa::Filtered, o2::aod::EMEventsWeight>> const& collisions, o2::soa::Join const& mccollisions, o2::aod::EMMCParticles const& mcparticles, Types const&... args) + // using FilteredMyCollisionsWithJJMC = o2::soa::Filtered, aod::EMEventsWeight>>; + void processAnalysisJJMC(o2::soa::Filtered, o2::aod::EMEventsWeight>> const& collisions, o2::soa::Join const& mccollisions, o2::aod::EMMCParticles const& mcparticles, Types const&... args) { if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM) { auto&& [v0photons, v0legs] = std::forward_as_tuple(args...); @@ -985,7 +1025,7 @@ struct Pi0EtaToGammaGammaMC { } PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processAnalysisJJMC, "process pair analysis", false); - void processDummy(o2::aod::EMEvents const&) {} + void processDummy(o2::aod::PMEvents const&) {} PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processDummy, "Dummy function", false); }; #endif // PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMAMC_H_ diff --git a/PWGEM/PhotonMeson/Core/TaggingPi0.h b/PWGEM/PhotonMeson/Core/TaggingPi0.h index 4dd43e290bf..71d7fb9f48b 100644 --- a/PWGEM/PhotonMeson/Core/TaggingPi0.h +++ b/PWGEM/PhotonMeson/Core/TaggingPi0.h @@ -23,6 +23,7 @@ #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" // #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" @@ -73,7 +74,7 @@ using namespace o2::aod::pwgem::photon; using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; using namespace o2::aod::pwgem::dilepton::utils; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyCollisionsWithJJMC = soa::Join; @@ -442,11 +443,11 @@ struct TaggingPi0 { // } SliceCache cache; - Preslice perCollision_pcm = aod::v0photonkf::emphotoneventId; - Preslice perCollision_emc = aod::emccluster::emphotoneventId; - // Preslice perCollision_phos = aod::phoscluster::emphotoneventId; + Preslice perCollision_pcm = aod::v0photonkf::pmeventId; + Preslice perCollision_emc = aod::emccluster::pmeventId; + // Preslice perCollision_phos = aod::phoscluster::pmeventId; - Preslice perCollision_electron = aod::emprimaryelectronda::emphotoneventId; + Preslice perCollision_electron = aod::emprimaryelectronda::pmeventId; Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt&& nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); @@ -534,9 +535,9 @@ struct TaggingPi0 { std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); if constexpr (pairtype == PairType::kPCMDalitzEE) { - auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); // PCM - auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); // positrons - auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); // electrons + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); // PCM + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); // positrons + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); // electrons for (const auto& g1 : photons1_per_collision) { if (!cut1.template IsSelected(g1)) { diff --git a/PWGEM/PhotonMeson/Core/TaggingPi0MC.h b/PWGEM/PhotonMeson/Core/TaggingPi0MC.h index 38d7a8e70d3..9dda549dc79 100644 --- a/PWGEM/PhotonMeson/Core/TaggingPi0MC.h +++ b/PWGEM/PhotonMeson/Core/TaggingPi0MC.h @@ -23,6 +23,7 @@ #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" // #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" @@ -70,7 +71,7 @@ using namespace o2::aod::pwgem::photonmeson::photonpair; using namespace o2::aod::pwgem::photonmeson::utils::mcutil; using namespace o2::aod::pwgem::dilepton::utils::mcutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyCollisionsWithJJMC = soa::Join; @@ -418,11 +419,11 @@ struct TaggingPi0MC { // } SliceCache cache; - Preslice perCollision_pcm = aod::v0photonkf::emphotoneventId; - Preslice perCollision_emc = aod::emccluster::emphotoneventId; - // Preslice perCollision_phos = aod::phoscluster::emphotoneventId; + Preslice perCollision_pcm = aod::v0photonkf::pmeventId; + Preslice perCollision_emc = aod::emccluster::pmeventId; + // Preslice perCollision_phos = aod::phoscluster::pmeventId; - Preslice perCollision_electron = aod::emprimaryelectronda::emphotoneventId; + Preslice perCollision_electron = aod::emprimaryelectronda::pmeventId; Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt&& nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); @@ -461,8 +462,8 @@ struct TaggingPi0MC { if constexpr (pairtype == PairType::kPCMDalitzEE) { auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); for (const auto& g1 : photons1_per_collision) { if (!cut1.template IsSelected(g1)) { diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h index d81c803ca2c..2e98a0396b5 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h @@ -16,7 +16,6 @@ #ifndef PWGEM_PHOTONMESON_CORE_V0PHOTONCANDIDATE_H_ #define PWGEM_PHOTONMESON_CORE_V0PHOTONCANDIDATE_H_ -#include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" #include "Common/Core/RecoDecay.h" @@ -35,41 +34,71 @@ struct V0PhotonCandidate { // Empty Constructor V0PhotonCandidate() = default; // Set method for photonconversionbuilder - void setPhotonCandidate(const KFParticle& v0, const KFParticle& pos, const KFParticle& ele, const auto& collision, float cospa, float psipair, float phiv, CentType centType) + template + void setPhotonCandidate(const KFParticle& v0DecayVtx, const KFParticle& v0PV, const TTrack& pos, const KFParticle& posDecayVtx, const TTrack& ele, const KFParticle& eleDecayVtx, const auto& collision, float cospa, float cospaRZ, float cospaXY, float psipair, float phiv, CentType centType, auto posdcaXY, auto eledcaXY, auto posdcaZ, auto eledcaZ) { - px = v0.GetPx(); - py = v0.GetPy(); - pz = v0.GetPz(); + conversionPointx = v0DecayVtx.GetX(); + conversionPointy = v0DecayVtx.GetY(); + conversionPointz = v0DecayVtx.GetZ(); + px = v0PV.GetPx(); + py = v0PV.GetPy(); + pz = v0PV.GetPz(); pT = RecoDecay::sqrtSumOfSquares(px, py); - posPx = pos.GetPx(); - posPy = pos.GetPy(); - posPz = pos.GetPz(); - elePx = ele.GetPx(); - elePy = ele.GetPy(); - elePz = ele.GetPz(); + posPx = posDecayVtx.GetPx(); + posPy = posDecayVtx.GetPy(); + posPz = posDecayVtx.GetPz(); + elePx = eleDecayVtx.GetPx(); + elePy = eleDecayVtx.GetPy(); + elePz = eleDecayVtx.GetPz(); posPT = RecoDecay::sqrtSumOfSquares(posPx, posPy); elePT = RecoDecay::sqrtSumOfSquares(elePx, elePy); + posEta = RecoDecay::eta(std::array{posPx, posPy, posPz}); + eleEta = RecoDecay::eta(std::array{elePx, elePy, elePz}); - chi2ndf = v0.GetChi2() / v0.GetNDF(); - pca = pos.GetDistanceFromParticle(ele); + posTPCNClsShared = pos.tpcNClsShared(); + posTPCNClsFindable = pos.tpcNClsFindable(); + posTPCNClsFindableMinusShared = pos.tpcNClsFindableMinusFound(); + posTPCNClsFindableMinusCrossedRows = pos.tpcNClsFindableMinusCrossedRows(); + posTPCChi2NCl = pos.tpcChi2NCl(); + posTPCSignal = pos.tpcSignal(); + posITSClusterSizes = pos.itsClusterSizes(); + eleTPCNClsShared = ele.tpcNClsShared(); + eleTPCNClsFindable = ele.tpcNClsFindable(); + eleTPCNClsFindableMinusShared = ele.tpcNClsFindableMinusFound(); + eleTPCNClsFindableMinusCrossedRows = ele.tpcNClsFindableMinusCrossedRows(); + eleTPCChi2NCl = ele.tpcChi2NCl(); + eleTPCSignal = ele.tpcSignal(); + eleITSClusterSizes = ele.itsClusterSizes(); - float v0mom = RecoDecay::sqrtSumOfSquares(v0.GetPx(), v0.GetPy(), v0.GetPz()); - float length = RecoDecay::sqrtSumOfSquares(v0.GetX() - collision.posX(), v0.GetY() - collision.posY(), v0.GetZ() - collision.posZ()); - float dcaXV0ToPV = (v0.GetX() - v0.GetPx() * cospa * length / v0mom) - collision.posX(); - float dcaYV0ToPV = (v0.GetY() - v0.GetPy() * cospa * length / v0mom) - collision.posY(); + chi2ndf = v0DecayVtx.GetChi2() / v0DecayVtx.GetNDF(); + pca = posDecayVtx.GetDistanceFromParticle(eleDecayVtx); + eta = RecoDecay::eta(std::array{px, py, pz}); + posEta = RecoDecay::eta(std::array{posPx, posPy, posPz}); + eleEta = RecoDecay::eta(std::array{elePx, elePy, elePz}); + + float v0mom = RecoDecay::sqrtSumOfSquares(v0DecayVtx.GetPx(), v0DecayVtx.GetPy(), v0DecayVtx.GetPz()); + float length = RecoDecay::sqrtSumOfSquares(v0DecayVtx.GetX() - collision.posX(), v0DecayVtx.GetY() - collision.posY(), v0DecayVtx.GetZ() - collision.posZ()); + float dcaXV0ToPV = (v0DecayVtx.GetX() - v0DecayVtx.GetPx() * cospa * length / v0mom) - collision.posX(); + float dcaYV0ToPV = (v0DecayVtx.GetY() - v0DecayVtx.GetPy() * cospa * length / v0mom) - collision.posY(); float tmpSign = (dcaXV0ToPV * dcaYV0ToPV > 0.f) ? +1.f : -1.f; dcaXYV0ToPV = RecoDecay::sqrtSumOfSquares(dcaXV0ToPV, dcaYV0ToPV) * tmpSign; - dcaZV0ToPV = (v0.GetZ() - v0.GetPz() * cospa * length / v0mom) - collision.posZ(); + dcaZV0ToPV = (v0DecayVtx.GetZ() - v0DecayVtx.GetPz() * cospa * length / v0mom) - collision.posZ(); alpha = v0_alpha(posPx, posPy, posPz, elePx, elePy, elePz); qt = v0_qt(posPx, posPy, posPz, elePx, elePy, elePz); this->cospa = cospa; + this->cospaRZ = cospaRZ; + this->cospaXY = cospaXY; this->psipair = psipair; this->phiv = phiv; this->centType = centType; + this->posdcaXY = posdcaXY; + this->eledcaXY = eledcaXY; + this->posdcaZ = posdcaZ; + this->eledcaZ = eledcaZ; switch (centType) { case CentType::CentFT0A: @@ -87,6 +116,9 @@ struct V0PhotonCandidate { // Set-Method for V0PhotonCut void setPhoton(const auto& v0, const auto& pos, const auto& ele, float cent, CentType centType) { + conversionPointx = v0.vx(); + conversionPointy = v0.vy(); + conversionPointz = v0.vz(); px = v0.px(); py = v0.py(); pz = v0.pz(); @@ -100,14 +132,37 @@ struct V0PhotonCandidate { elePz = ele.pz(); posPT = pos.pt(); elePT = ele.pt(); + posEta = pos.eta(); + eleEta = ele.eta(); + posdcaXY = pos.dcaXY(); + posdcaZ = pos.dcaZ(); + eledcaXY = ele.dcaXY(); + eledcaZ = ele.dcaZ(); + posTPCNClsShared = pos.tpcNClsShared(); + posTPCNClsFindable = pos.tpcNClsFindable(); + posTPCNClsFindableMinusShared = pos.tpcNClsFindableMinusFound(); + posTPCNClsFindableMinusCrossedRows = pos.tpcNClsFindableMinusCrossedRows(); + posTPCChi2NCl = pos.tpcChi2NCl(); + posTPCSignal = pos.tpcSignal(); + posITSClusterSizes = pos.itsClusterSizes(); + eleTPCNClsShared = ele.tpcNClsShared(); + eleTPCNClsFindable = ele.tpcNClsFindable(); + eleTPCNClsFindableMinusShared = ele.tpcNClsFindableMinusFound(); + eleTPCNClsFindableMinusCrossedRows = ele.tpcNClsFindableMinusCrossedRows(); + eleTPCChi2NCl = ele.tpcChi2NCl(); + eleTPCSignal = ele.tpcSignal(); + eleITSClusterSizes = ele.itsClusterSizes(); chi2ndf = v0.chiSquareNDF(); pca = v0.pca(); + eta = v0.eta(); dcaXYV0ToPV = v0.dcaXYtopv(); dcaZV0ToPV = v0.dcaZtopv(); cospa = v0.cospa(); + cospaRZ = v0.cospaRZ(); + cospaXY = v0.cospaXY(); alpha = v0.alpha(); qt = v0.qtarm(); psipair = 999.f; // default if V0PhotonPhiVPsi table is not included @@ -131,6 +186,14 @@ struct V0PhotonCandidate { float getPhiV() const { return phiv; } float getPsiPair() const { return psipair; } float getCosPA() const { return cospa; } + float getCosPARZ() const { return cospaRZ; } + float getCosPAXY() const { return cospaXY; } + float getEta() const { return eta; } + float getPosEta() const { return posEta; } + float getEleEta() const { return eleEta; } + float getConversionPointX() const { return conversionPointx; } + float getConversionPointY() const { return conversionPointy; } + float getConversionPointZ() const { return conversionPointz; } float getPx() const { return px; } float getPy() const { return py; } float getPz() const { return pz; } @@ -141,34 +204,78 @@ struct V0PhotonCandidate { float getElePx() const { return elePx; } float getElePy() const { return elePy; } float getElePz() const { return elePz; } + float getPosDcaXY() const { return posdcaXY; } + float getPosDcaZ() const { return posdcaZ; } + float getEleDcaXY() const { return eledcaXY; } + float getEleDcaZ() const { return eledcaZ; } + float getPosTPCNClsShared() const { return posTPCNClsShared; } + float getPosTPCNClsFindable() const { return posTPCNClsFindable; } + float getPosTPCNClsFindableMinusShared() const { return posTPCNClsFindableMinusShared; } + float getPosTPCNClsFindableMinusCrossedRows() const { return posTPCNClsFindableMinusCrossedRows; } + float getPosTPCChi2NCl() const { return posTPCChi2NCl; } + float getPosTPCSignal() const { return posTPCSignal; } + float getPosITSClusterSizes() const { return posITSClusterSizes; } + float getEleTPCNClsShared() const { return eleTPCNClsShared; } + float getEleTPCNClsFindable() const { return eleTPCNClsFindable; } + float getEleTPCNClsFindableMinusShared() const { return eleTPCNClsFindableMinusShared; } + float getEleTPCNClsFindableMinusCrossedRows() const { return eleTPCNClsFindableMinusCrossedRows; } + float getEleTPCChi2NCl() const { return eleTPCChi2NCl; } + float getEleTPCSignal() const { return eleTPCSignal; } + float getEleITSClusterSizes() const { return eleITSClusterSizes; } float getCent() const { return cent; } float getPCA() const { return pca; } CentType getCentType() const { return centType; } private: - float px; - float py; - float pz; - float posPx; - float posPy; - float posPz; - float elePx; - float elePy; - float elePz; - float pT; - float posPT; - float elePT; - float dcaXYV0ToPV; - float dcaZV0ToPV; - float alpha; - float qt; - float phiv; - float psipair; - float cospa; - float chi2ndf; - float cent; - float pca; - CentType centType; + float conversionPointx{0.f}; + float conversionPointy{0.f}; + float conversionPointz{0.f}; + float px{0.f}; + float py{0.f}; + float pz{0.f}; + float posPx{0.f}; + float posPy{0.f}; + float posPz{0.f}; + float elePx{0.f}; + float elePy{0.f}; + float elePz{0.f}; + float pT{0.f}; + float posPT{0.f}; + float elePT{0.f}; + float dcaXYV0ToPV{0.f}; + float dcaZV0ToPV{0.f}; + float alpha{0.f}; + float qt{0.f}; + float phiv{0.f}; + float psipair{0.f}; + float cospa{0.f}; + float cospaRZ{0.f}; + float cospaXY{0.f}; + float chi2ndf{0.f}; + float cent{0.f}; + float pca{0.f}; + float eta{0.f}; + float posEta{0.f}; + float eleEta{0.f}; + float posdcaXY{0.f}; + float posdcaZ{0.f}; + float eledcaXY{0.f}; + float eledcaZ{0.f}; + float posTPCNClsShared{0.f}; + float posTPCNClsFindable{0.f}; + float posTPCNClsFindableMinusShared{0.f}; + float posTPCNClsFindableMinusCrossedRows{0.f}; + float posTPCChi2NCl{0.f}; + float posTPCSignal{0.f}; + float posITSClusterSizes{0.f}; + float eleTPCNClsShared{0.f}; + float eleTPCNClsFindable{0.f}; + float eleTPCNClsFindableMinusShared{0.f}; + float eleTPCNClsFindableMinusCrossedRows{0.f}; + float eleTPCChi2NCl{0.f}; + float eleTPCSignal{0.f}; + float eleITSClusterSizes{0.f}; + CentType centType{CentFT0C}; }; #endif // PWGEM_PHOTONMESON_CORE_V0PHOTONCANDIDATE_H_ diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx b/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx index 5abc97c5d1c..0511e72d0c7 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx @@ -115,6 +115,28 @@ void V0PhotonCut::RejectITSib(bool flag) mRejectITSib = flag; LOG(info) << "V0 Photon Cut, reject photon on ITSib: " << mRejectITSib; } + +void V0PhotonCut::setTooCloseType(V0PhotonCut::TooCloseCuts type) +{ + mTooCloseType = type; + LOG(info) << "V0 Photon Cut, TooCloseV0 cut type: " << static_cast(mTooCloseType); +} +void V0PhotonCut::setMinV0DistSquared(float value) +{ + mMinV0DistSquared = value; + LOG(info) << "V0 Photon Cut, min V0 distance squared: " << mMinV0DistSquared; +} +void V0PhotonCut::setDeltaR(float value) +{ + mDeltaR = value; + LOG(info) << "V0 Photon Cut, delta R for too close V0: " << mDeltaR; +} +void V0PhotonCut::setMinOpeningAngle(float value) +{ + mMinOpeningAngle = value; + LOG(info) << "V0 Photon Cut, min opening angle for too close V0: " << mMinOpeningAngle; +} + void V0PhotonCut::SetTPCNsigmaElRange(float min, float max) { mMinTPCNsigmaEl = min; diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.h b/PWGEM/PhotonMeson/Core/V0PhotonCut.h index 1be295b3235..664981df21e 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.h @@ -27,6 +27,9 @@ #include #include +#include // IWYU pragma: keep +#include +#include #include #include @@ -183,6 +186,7 @@ class V0PhotonCut : public TNamed kRZLine, kOnWwireIB, kOnWwireOB, + kIsTooClose, // leg cut kTrackPtRange, kTrackEtaRange, @@ -206,6 +210,12 @@ class V0PhotonCut : public TNamed kNCuts }; + enum class TooCloseCuts : uint8_t { + kNoCut = 0, + kDistance3D = 1, + kRadAndAngle = 2 + }; + /// \brief add histograms to registry /// \param fRegistry pointer to histogram registry void addQAHistograms(o2::framework::HistogramRegistry* fRegistry = nullptr) const @@ -268,26 +278,27 @@ class V0PhotonCut : public TNamed hPhotonQualityCuts->GetXaxis()->SetBinLabel(12, "RZ_{line}"); hPhotonQualityCuts->GetXaxis()->SetBinLabel(13, "Wire_{IB}"); hPhotonQualityCuts->GetXaxis()->SetBinLabel(14, "Wire_{OB}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(15, "#it{p}_{T,leg}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(16, "#it{#eta}_{leg}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(17, "#it{N}_{cl,TPC}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(18, "#it{N}_{cr,TPC}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(19, "#it{N}_{cr,TPC}/#it{N}_{cl,TPC}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(20, "FracSharedCl"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(21, "#chi^{2}_{TPC}/NDF"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(22, "#it{N#sigma}_{e,TPC}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(23, "#it{N#sigma}_{#pi,TPC}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(24, "DCA_{xy}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(25, "DCA_{z}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(26, "#it{N}_{cl,ITS}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(27, "#chi^{2}_{ITS}/NDF"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(28, "size_{ITS}"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(29, "ITSTPC"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(30, "ITSOnly"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(31, "TPCOnly"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(32, "TPCTRD"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(33, "TPCTOF"); - hPhotonQualityCuts->GetXaxis()->SetBinLabel(34, "Out"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(15, "IsTooClose"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(16, "#it{p}_{T,leg}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(17, "#it{#eta}_{leg}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(18, "#it{N}_{cl,TPC}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(19, "#it{N}_{cr,TPC}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(20, "#it{N}_{cr,TPC}/#it{N}_{cl,TPC}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(21, "FracSharedCl"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(22, "#chi^{2}_{TPC}/NDF"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(23, "#it{N#sigma}_{e,TPC}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(24, "#it{N#sigma}_{#pi,TPC}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(25, "DCA_{xy}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(26, "DCA_{z}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(27, "#it{N}_{cl,ITS}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(28, "#chi^{2}_{ITS}/NDF"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(29, "size_{ITS}"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(30, "ITSTPC"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(31, "ITSOnly"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(32, "TPCOnly"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(33, "TPCTRD"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(34, "TPCTOF"); + hPhotonQualityCuts->GetXaxis()->SetBinLabel(35, "Out"); } } @@ -351,6 +362,119 @@ class V0PhotonCut : public TNamed fRegistry->fill(HIST("QA/V0Photon/after/Neg/hTPCHits"), ele.tpcNClsFound(), ele.tpcNClsCrossedRows()); } + /// \brief creates a mask for the V0s if they are too close to another V0 and have higher chi^2 + /// \param v0s V0 table + template + void createCloseV0CutMask(TV0 const& v0s) const + { + const bool useDistance3D = (mTooCloseType == TooCloseCuts::kDistance3D); + const float windowWidth = useDistance3D ? std::sqrt(mMinV0DistSquared) : mDeltaR; + const float cosMinAngle = std::cos(mMinOpeningAngle); + + int tableSize = v0s.size(); + std::vector rejectMask(tableSize, 0); + + if (mTooCloseType == TooCloseCuts::kNoCut) { + mRejectMask = rejectMask; + return; + } + + auto currentV0Iter = v0s.begin(); + auto otherV0Iter = v0s.begin(); + + int groupStart = 0; + while (groupStart < tableSize) { + + // --- find the end of this collision's group --- + int currentCollisionId = v0s.iteratorAt(groupStart).collisionId(); + int groupEnd = groupStart + 1; + while (groupEnd < tableSize && v0s.iteratorAt(groupEnd).collisionId() == currentCollisionId) { + groupEnd++; + } + + int groupSize = groupEnd - groupStart; + + std::vector> indexedRadii(groupSize); + for (int k = 0; k < groupSize; k++) { + currentV0Iter.setCursor(groupStart + k); + indexedRadii[k] = {groupStart + k, currentV0Iter.v0radius()}; + } + std::sort(indexedRadii.begin(), indexedRadii.end(), [](const auto& a, const auto& b) { + return a.second < b.second; + }); + // extract sorted indices and pre-sorted radii + std::vector sortedIndices(groupSize); + std::vector sortedRadii(groupSize); + for (int k = 0; k < groupSize; k++) { + sortedIndices[k] = indexedRadii[k].first; + sortedRadii[k] = indexedRadii[k].second; + } + + // --- sliding window within this group --- + int windowStart = 0; // reset per group + for (int i = 0; i < groupSize; i++) { + + float currentRadius = sortedRadii[i]; + while (windowStart < groupSize && sortedRadii[windowStart] < currentRadius - windowWidth) { + windowStart++; + } + + currentV0Iter.setCursor(sortedIndices[i]); + + float vx1 = currentV0Iter.vx(); + float vy1 = currentV0Iter.vy(); + float vz1 = currentV0Iter.vz(); + + float px1 = currentV0Iter.px(); + float py1 = currentV0Iter.py(); + float pz1 = currentV0Iter.pz(); + float chi2I = currentV0Iter.chiSquareNDF(); + + for (int j = windowStart; j < groupSize; j++) { + if (j == i) { + continue; + } + if (sortedRadii[j] > currentRadius + windowWidth) { + break; + } + + otherV0Iter.setCursor(sortedIndices[j]); + + bool tooClose = false; + if (useDistance3D) { + float dx = vx1 - otherV0Iter.vx(); + float dy = vy1 - otherV0Iter.vy(); + float dz = vz1 - otherV0Iter.vz(); + float distSquared = dx * dx + dy * dy + dz * dz; + tooClose = distSquared < mMinV0DistSquared; + } else { + float px2 = otherV0Iter.px(), py2 = otherV0Iter.py(), pz2 = otherV0Iter.pz(); + float dot = px1 * px2 + py1 * py2 + pz1 * pz2; + float mag1 = px1 * px1 + py1 * py1 + pz1 * pz1; + float mag2 = px2 * px2 + py2 * py2 + pz2 * pz2; + float denom = std::sqrt(mag1 * mag2); + if (denom > 0) { + float cosAngle = dot / denom; + cosAngle = std::clamp(cosAngle, -1.0f, 1.0f); + tooClose = cosAngle > cosMinAngle; + } + } + + if (tooClose) { + if (chi2I > otherV0Iter.chiSquareNDF()) { + rejectMask[sortedIndices[i]] = 1; + + } else { + rejectMask[sortedIndices[j]] = 1; + } + } + } + } + groupStart = groupEnd; + } + mRejectMask = rejectMask; + } + /// \brief check if given v0 photon survives all cuts /// \param flags EMBitFlags where results will be stored /// \param v0s v0 photon table to check @@ -360,6 +484,8 @@ class V0PhotonCut : public TNamed if (v0s.size() <= 0) { return; } + + createCloseV0CutMask(v0s); // auto legIter = legs.begin(); // auto legEnd = legs.end(); size_t iV0 = 0; @@ -367,10 +493,10 @@ class V0PhotonCut : public TNamed const bool doQA = mDoQA && fRegistry != nullptr; uint nTotV0PerColl = 0; - currentCollID = v0s.iteratorAt(0).emphotoneventId(); + currentCollID = v0s.iteratorAt(0).pmeventId(); for (const auto& v0 : v0s) { - const auto collID = v0.emphotoneventId(); + const auto collID = v0.pmeventId(); if (!IsSelected(v0, fRegistry)) { flags.set(iV0); } @@ -489,6 +615,13 @@ class V0PhotonCut : public TNamed } } + if (!IsSelectedV0(v0, V0PhotonCuts::kIsTooClose)) { + if (doQA) { + fRegistry->fill(HIST("QA/V0Photon/hPhotonQualityCuts"), static_cast(V0PhotonCuts::kIsTooClose) + 1, v0Pt); + } + return false; + } + for (const auto& track : {pos, ele}) { if (!IsSelectedTrack(track, V0PhotonCuts::kTrackPtRange)) { if (doQA) { @@ -604,7 +737,7 @@ class V0PhotonCut : public TNamed } if (doQA) { fillAfterPhotonHistogram(v0, pos, ele, fRegistry); - if (v0.emphotoneventId() != currentCollID) { + if (v0.pmeventId() != currentCollID) { fRegistry->fill(HIST("QA/V0Photon/after/hNgamma"), nAccV0PerColl); nAccV0PerColl = 0; } @@ -707,11 +840,24 @@ class V0PhotonCut : public TNamed case V0PhotonCuts::kAP: return std::pow(v0.alpha() / mMaxAlpha, 2) + std::pow(v0.qtarm() / mMaxQt, 2) < 1.0; - case V0PhotonCuts::kPsiPair: - return true; + // TODO: implement fully + case V0PhotonCuts::kPsiPair: { + if constexpr (requires { v0.psipair(); }) { + // return (std::fabs(v0.psipair() < 0.18f * std::exp( -0.55f * v0.chiSquareNDF()))); + return true; + } else { + return true; + } + } - case V0PhotonCuts::kPhiV: - return true; + // TODO: implement fully + case V0PhotonCuts::kPhiV: { + if constexpr (requires { v0.phiv(); }) { + return true; + } else { + return true; + } + } case V0PhotonCuts::kRxy: { if (v0.v0radius() < mMinRxy || mMaxRxy < v0.v0radius()) { @@ -775,6 +921,12 @@ class V0PhotonCut : public TNamed float dxy = std::sqrt(std::pow(x - x_exp, 2) + std::pow(y - y_exp, 2)); return !(dxy > margin_xy); } + case V0PhotonCuts::kIsTooClose: { + if (mRejectMask.size() == 0) { + return true; + } + return (mRejectMask[v0.globalIndex()] == 0); + } default: return false; } @@ -950,6 +1102,11 @@ class V0PhotonCut : public TNamed void SetOnWwireOB(bool flag = false); void RejectITSib(bool flag = false); + void setTooCloseType(V0PhotonCut::TooCloseCuts type); + void setMinV0DistSquared(float value); + void setDeltaR(float value); + void setMinOpeningAngle(float value); + void SetTrackPtRange(float minPt = 0.f, float maxPt = 1e10f); void SetTrackEtaRange(float minEta = -1e10f, float maxEta = 1e10f); void SetMinNClustersTPC(int minNClustersTPC); @@ -1017,6 +1174,11 @@ class V0PhotonCut : public TNamed bool mIsOnWwireIB{false}; bool mIsOnWwireOB{false}; bool mRejectITSib{false}; + TooCloseCuts mTooCloseType{V0PhotonCut::TooCloseCuts::kRadAndAngle}; // for TooCloseV0Cut: either squared distance between conversion points OR opening angle and deltaR + float mMinV0DistSquared{1.}; // for TooCloseV0Cut: cut value when using squared distance between conversion points + float mDeltaR{6.}; // for TooCloseV0Cut: V0PhotonCut::TooCloseCuts::kRadAndAngle when deltaR < this -> compare chi2 + float mMinOpeningAngle{0.02}; // for TooCloseV0Cut: V0PhotonCut::TooCloseCuts::kRadAndAngle when opening angle < this -> compare chi2 + mutable std::vector mRejectMask{}; // ML cuts bool mApplyMlCuts{false}; diff --git a/PWGEM/PhotonMeson/DataModel/EventTables.h b/PWGEM/PhotonMeson/DataModel/EventTables.h new file mode 100644 index 00000000000..d902e82562a --- /dev/null +++ b/PWGEM/PhotonMeson/DataModel/EventTables.h @@ -0,0 +1,78 @@ +// 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 EventTables.h +/// \brief This header provides the table definitions to store photon meson event tables +/// \author Marvin Hemmer (marvin.hemmer@cern.ch) - Goethe University Frankfurt + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include + +#include + +#include +#include + +#ifndef PWGEM_PHOTONMESON_DATAMODEL_EVENTTABLES_H_ +#define PWGEM_PHOTONMESON_DATAMODEL_EVENTTABLES_H_ + +namespace o2::aod +{ + +namespace pmevsel +{ +// Event selection criteria. See O2Physics/Common/CCDB/EventSelectionParams.h +enum EventSelectionFlags { + kIsTriggerTVX = 0, // FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level + kNoITSROFrameBorder, // bunch crossing is far from ITS RO Frame border + kNoTimeFrameBorder, // bunch crossing is far from Time Frame borders + kNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC + kIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 + kIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) + kIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF + kIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD + kNoCollInTimeRangeNarrow, // no other collisions in specified time range (narrower than Strict) + kNoCollInTimeRangeStrict, // no other collisions in specified time range + kNoCollInTimeRangeStandard, // no other collisions in specified time range with per-collision multiplicity above threshold + kNoCollInRofStrict, // no other collisions in this Readout Frame + kNoCollInRofStandard, // no other collisions in this Readout Frame with per-collision multiplicity above threshold + kNoHighMultCollInPrevRof, // veto an event if FT0C amplitude in previous ITS ROF is above threshold + kIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value + kIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values + kIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values + kNsel // counter +}; + +DECLARE_SOA_BITMAP_COLUMN(Selection, selection, 32); //! Bitmask of selection flags +DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint32_t selection_bit) -> bool { return (selection_bit & BIT(o2::aod::pmevsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::pmevsel::kNoTimeFrameBorder)) && (selection_bit & BIT(o2::aod::pmevsel::kNoITSROFrameBorder)); }); + +} // namespace pmevsel + +namespace pmevent +{ +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); + +DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint64_t selection_bit) -> bool { return (selection_bit & BIT(o2::aod::evsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::evsel::kNoTimeFrameBorder)) && (selection_bit & BIT(o2::aod::evsel::kNoITSROFrameBorder)); }); +} // namespace pmevent + +DECLARE_SOA_TABLE(PMEvents, "AOD", "PMEVENT", //! Main event information table + o2::soa::Index<>, pmevent::CollisionId, bc::RunNumber, bc::GlobalBC, evsel::Selection, evsel::Rct, timestamp::Timestamp, + collision::PosZ, + collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, pmevent::Sel8); + +using PMEvent = PMEvents::iterator; + +} // namespace o2::aod + +#endif // PWGEM_PHOTONMESON_DATAMODEL_EVENTTABLES_H_ diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index 9b680aed2c9..afb88c6694a 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -14,6 +14,7 @@ /// \author D. Sekihata, daiki.sekihata@cern.ch; Marvin Hemmer (marvin.hemmer@cern.ch) - Goethe University Frankfurt #include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/CaloClusters.h" @@ -36,9 +37,6 @@ namespace o2::aod { -using EMPhotonEvents = EMEvents_004; -using EMPhotonEvent = EMPhotonEvents::iterator; - namespace emmcbinnedgen { DECLARE_SOA_COLUMN(GeneratedGamma, generatedGamma, std::vector); //! gamma binned generated data @@ -266,7 +264,7 @@ using EMEventWeight = EMEventsWeight::iterator; namespace v0photonkf { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! DECLARE_SOA_COLUMN(V0Id, v0Id, int); //! DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, V0Legs, "_Pos"); //! @@ -345,8 +343,8 @@ using V0PhotonsKF = V0PhotonsKF_001; // iterators using V0PhotonKF = V0PhotonsKF::iterator; -DECLARE_SOA_TABLE(V0KFEMEventIds_000, "AOD", "V0KFEMEVENTID", v0photonkf::EMEventId); // To be joined with V0PhotonsKF table at analysis level. -DECLARE_SOA_TABLE_VERSIONED(V0KFEMEventIds_001, "AOD", "V0KFEMEVENTID", 1, v0photonkf::EMPhotonEventId); // To be joined with V0PhotonsKF table at analysis level. +DECLARE_SOA_TABLE(V0KFEMEventIds_000, "AOD", "V0KFEMEVENTID", v0photonkf::EMEventId); // To be joined with V0PhotonsKF table at analysis level. +DECLARE_SOA_TABLE_VERSIONED(V0KFEMEventIds_001, "AOD", "V0KFEMEVENTID", 1, v0photonkf::PMEventId); // To be joined with V0PhotonsKF table at analysis level. using V0KFEMEventIds = V0KFEMEventIds_001; using V0KFEMEventId = V0KFEMEventIds::iterator; @@ -423,18 +421,18 @@ using EMPrimaryElectronFromDalitz = EMPrimaryElectronsFromDalitz::iterator; namespace emprimaryelectronda { -DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! } // namespace emprimaryelectronda -DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectronDaEMEventIds_001, "AOD", "PRMELDAEVENTID", 1, emprimaryelectronda::EMPhotonEventId); // To be joined with EMPrimaryElectronsFromDalitz table at analysis level. +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectronDaEMEventIds_001, "AOD", "PRMELDAEVENTID", 1, emprimaryelectronda::PMEventId); // To be joined with EMPrimaryElectronsFromDalitz table at analysis level. using EMPrimaryElectronDaEMEventIds = EMPrimaryElectronDaEMEventIds_001; using EMPrimaryElectronDaEMEventId = EMPrimaryElectronDaEMEventIds::iterator; namespace v0photonsphivpsi { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! DECLARE_SOA_COLUMN(PhiV, phiv, float); //! DECLARE_SOA_COLUMN(PsiPair, psipair, float); } // namespace v0photonsphivpsi @@ -446,7 +444,7 @@ using V0PhotonsPhiVPsi = V0PhotonsPhiVPsi; namespace dalitzee { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, EMPrimaryElectrons, "_Pos"); //! DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, EMPrimaryElectrons, "_Neg"); //! DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! @@ -468,14 +466,15 @@ DECLARE_SOA_TABLE(DalitzEEs, "AOD", "DALITZEE", //! // iterators using DalitzEE = DalitzEEs::iterator; -DECLARE_SOA_TABLE(DalitzEEEMEventIds, "AOD", "EEEMEVENTID", dalitzee::EMEventId); // To be joined with DalitzEEs table at analysis level. -// iterators +DECLARE_SOA_TABLE(DalitzEEEMEventIds_000, "AOD", "EEEMEVENTID", dalitzee::EMEventId); // To be joined with DalitzEEs table at analysis level. +DECLARE_SOA_TABLE_VERSIONED(DalitzEEEMEventIds_001, "AOD", "EEEMEVENTID", 1, dalitzee::PMEventId); // To be joined with DalitzEEs table at analysis level. +using DalitzEEEMEventIds = DalitzEEEMEventIds_001; using DalitzEEEMEventId = DalitzEEEMEventIds::iterator; namespace pwgem::photon::swtinfo { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! DECLARE_SOA_INDEX_COLUMN_FULL(TriggerV0PhotonHighPt, triggerV0PhotonHighPt, int, V0PhotonsKF, "_TriggerV0PhotonHighPt"); //! high pT PCM trigger is fired by this v0 photon DECLARE_SOA_INDEX_COLUMN_FULL(TriggerV0PhotonPair, triggerV0PhotonPair, int, V0PhotonsKF, "_TriggerV0PhotonPair"); //! PCM+EE trigger is fired by this v0 photon and dielectron @@ -575,7 +574,7 @@ DECLARE_SOA_TABLE(McGammasTrue, "AOD", "MCGATRUE", namespace skimmedcluster { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! DECLARE_SOA_COLUMN(ID, id, int); //! cluster ID identifying cluster in event DECLARE_SOA_COLUMN(E, e, float); //! cluster energy (GeV) @@ -592,7 +591,7 @@ DECLARE_SOA_COLUMN(NLM, nlm, int); //! numbe namespace emccluster { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! DECLARE_SOA_COLUMN(CoreEnergy, coreEnergy, float); //! cluster core energy (GeV) DECLARE_SOA_COLUMN(Time, time, float); //! cluster time (ns) DECLARE_SOA_COLUMN(IsExotic, isExotic, bool); //! flag to mark cluster as exotic @@ -649,15 +648,15 @@ DECLARE_SOA_TABLE(EmEmcMTracks, "AOD", "EMEMCMTRACK", //! DECLARE_SOA_TABLE(EmEmcMSTracks, "AOD", "EMEMCMSTRACK", //! trackmatching::EmEmcClusterId, emctm::DeltaPhi, emctm::DeltaEta, emctm::TrackP, emctm::TrackPt); -DECLARE_SOA_TABLE(EMCEMEventIds_000, "AOD", "EMCEMEVENTID", emccluster::EMEventId); // To be joined with SkimEMCClusters table at analysis level. -DECLARE_SOA_TABLE_VERSIONED(EMCEMEventIds_001, "AOD", "EMCEMEVENTID", 1, emccluster::EMPhotonEventId); // To be joined with SkimEMCClusters table at analysis level. +DECLARE_SOA_TABLE(EMCEMEventIds_000, "AOD", "EMCEMEVENTID", emccluster::EMEventId); // To be joined with SkimEMCClusters table at analysis level. +DECLARE_SOA_TABLE_VERSIONED(EMCEMEventIds_001, "AOD", "EMCEMEVENTID", 1, emccluster::PMEventId); // To be joined with SkimEMCClusters table at analysis level. using EMCEMEventIds = EMCEMEventIds_001; using EMCEMEventId = EMCEMEventIds::iterator; namespace phoscluster { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN(EMPhotonEvent, emphotonevent); //! +DECLARE_SOA_INDEX_COLUMN(PMEvent, pmevent); //! DECLARE_SOA_INDEX_COLUMN_FULL(MatchedTrack, matchedTrack, int, Tracks, "_Matched"); //! matched track index DECLARE_SOA_COLUMN(X, x, float); //! cluster hit position in ALICE global coordinate DECLARE_SOA_COLUMN(Y, y, float); //! cluster hit position in ALICE global coordinate @@ -692,8 +691,8 @@ DECLARE_SOA_TABLE(PHOSClusters, "AOD", "PHOSCLUSTERS", //! phoscluster::Phi); using PHOSCluster = PHOSClusters::iterator; -DECLARE_SOA_TABLE(PHOSEMEventIds_000, "AOD", "PHOSEMEVENTID", phoscluster::EMEventId); // To be joined with PHOSClusters table at analysis level. -DECLARE_SOA_TABLE_VERSIONED(PHOSEMEventIds_001, "AOD", "PHOSEMEVENTID", 1, phoscluster::EMPhotonEventId); // To be joined with PHOSClusters table at analysis level. +DECLARE_SOA_TABLE(PHOSEMEventIds_000, "AOD", "PHOSEMEVENTID", phoscluster::EMEventId); // To be joined with PHOSClusters table at analysis level. +DECLARE_SOA_TABLE_VERSIONED(PHOSEMEventIds_001, "AOD", "PHOSEMEVENTID", 1, phoscluster::PMEventId); // To be joined with PHOSClusters table at analysis level. using PHOSEMEventIds = PHOSEMEventIds_001; using PHOSEMEventId = PHOSEMEventIds::iterator; @@ -720,6 +719,14 @@ DECLARE_SOA_TABLE(NonLinV0s, "AOD", "NONLINV0", //! table of non lin corrected v DECLARE_SOA_TABLE(NonLinEmcClusters, "AOD", "NONLINEMCCLUSTER", //! table of non lin corrected values for EMCal Photons (so far only E and pT) nonlin::CorrE, nonlin::CorrPt); //! +namespace v0photonMBweights +{ +DECLARE_SOA_COLUMN(OmegaMBWeight, omegaMBWeight, float); +} + +DECLARE_SOA_TABLE(V0PhotonOmegaMBWeights, "AOD", "V0PHOTONMBW", v0photonMBweights::OmegaMBWeight); // store MB weights. To be joined with V0PhotonsKF table at analysis level. + +using V0PhotonOmegaMBWeight = V0PhotonOmegaMBWeights::iterator; } // namespace o2::aod #endif // PWGEM_PHOTONMESON_DATAMODEL_GAMMATABLES_H_ diff --git a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt index 20db3ba057e..99bccdf5c49 100644 --- a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt +++ b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt @@ -70,3 +70,13 @@ o2physics_add_dpl_workflow(non-lin-producer SOURCES nonLinProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pm-qvector-dummy-otf + SOURCES pmQvectorDummyOtf.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(material-budget-weights + SOURCES materialBudgetWeights.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::CCDB ROOT::Hist ROOT::Core + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/TableProducer/Converters/CMakeLists.txt b/PWGEM/PhotonMeson/TableProducer/Converters/CMakeLists.txt index 8ee98eb4d36..63a2f1814c5 100644 --- a/PWGEM/PhotonMeson/TableProducer/Converters/CMakeLists.txt +++ b/PWGEM/PhotonMeson/TableProducer/Converters/CMakeLists.txt @@ -25,3 +25,7 @@ o2physics_add_dpl_workflow(phosid-converter1 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(converter-emevent-pmevent + SOURCES converterEmeventPmevent.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/TableProducer/Converters/converterEmeventPmevent.cxx b/PWGEM/PhotonMeson/TableProducer/Converters/converterEmeventPmevent.cxx new file mode 100644 index 00000000000..9147873fb71 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/Converters/converterEmeventPmevent.cxx @@ -0,0 +1,53 @@ +// 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 converterEmeventPmevent.cxx +/// \author Marvin Hemmer +/// \brief converter for EMEvents_004 to PMEvents + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct ConverterEmeventPmevent { + Produces pmEvents; + + void process(EMEvents_004 const& collisions) + { + for (const auto& collision : collisions) { + pmEvents( + collision.collisionId(), + collision.runNumber(), + collision.globalBC(), + collision.selection_raw(), + collision.rct_raw(), + collision.timestamp(), + collision.posZ(), + collision.numContrib(), + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange()); + } // end of collision loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx index 2c87cc3431d..d9365251277 100644 --- a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx @@ -13,6 +13,7 @@ /// \brief This code produces reduced events for photon analyses. /// \author Daiki Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" // #include "PWGJE/DataModel/Jet.h" @@ -66,7 +67,7 @@ using MyCollisionsMCCentQvec = soa::Join; struct CreateEMEventPhoton { // Produces embc; - Produces event; + Produces event; Produces eventalias; // Produces eventCov; Produces eventMult; @@ -362,13 +363,13 @@ struct AssociatePhotonToEMEvent { Produces prmeleventid; Produces phoseventid; Produces emceventid; - Produces prmtrackeventid; + // Produces prmtrackeventid; Preslice perCollisionPCM = aod::v0photonkf::collisionId; PresliceUnsorted perCollisionEl = aod::emprimaryelectron::collisionId; Preslice perCollisionPHOS = aod::skimmedcluster::collisionId; Preslice perCollisionEMC = aod::skimmedcluster::collisionId; - Preslice perCollision_track = aod::emprimarytrack::collisionId; + // Preslice perCollision_track = aod::emprimarytrack::collisionId; void init(o2::framework::InitContext&) {} @@ -387,32 +388,32 @@ struct AssociatePhotonToEMEvent { // This struct is for both data and MC. // Note that reconstructed collisions without mc collisions are already rejected in CreateEMEventPhoton in MC. - void processPCM(aod::EMEvents const& collisions, aod::V0PhotonsKF const& photons) + void processPCM(aod::PMEvents const& collisions, aod::V0PhotonsKF const& photons) { fillEventId(collisions, photons, v0kfeventid, perCollisionPCM); } - void processElectronFromDalitz(aod::EMEvents const& collisions, aod::EMPrimaryElectronsFromDalitz const& tracks) + void processElectronFromDalitz(aod::PMEvents const& collisions, aod::EMPrimaryElectronsFromDalitz const& tracks) { fillEventId(collisions, tracks, prmeleventid, perCollisionEl); } - void processPHOS(aod::EMEvents const& collisions, aod::PHOSClusters const& photons) + void processPHOS(aod::PMEvents const& collisions, aod::PHOSClusters const& photons) { fillEventId(collisions, photons, phoseventid, perCollisionPHOS); } - void processEMC(aod::EMEvents const& collisions, aod::SkimEMCClusters const& photons) + void processEMC(aod::PMEvents const& collisions, aod::SkimEMCClusters const& photons) { fillEventId(collisions, photons, emceventid, perCollisionEMC); } - // void processChargedTrack(aod::EMEvents const& collisions, aod::EMPrimaryTracks const& tracks) + // void processChargedTrack(aod::PMEvents const& collisions, aod::EMPrimaryTracks const& tracks) // { // fillEventId(collisions, tracks, prmtrackeventid, perCollision_track); // } - void processDummy(aod::EMEvents const&) {} + void processDummy(aod::PMEvents const&) {} PROCESS_SWITCH(AssociatePhotonToEMEvent, processPCM, "process pcm-event indexing", false); PROCESS_SWITCH(AssociatePhotonToEMEvent, processElectronFromDalitz, "process dalitzee-event indexing", false); diff --git a/PWGEM/PhotonMeson/Tasks/PhotonHBTPCMPCM.cxx b/PWGEM/PhotonMeson/TableProducer/materialBudgetWeights.cxx similarity index 58% rename from PWGEM/PhotonMeson/Tasks/PhotonHBTPCMPCM.cxx rename to PWGEM/PhotonMeson/TableProducer/materialBudgetWeights.cxx index 0fde469c55c..6d235b0db0c 100644 --- a/PWGEM/PhotonMeson/Tasks/PhotonHBTPCMPCM.cxx +++ b/PWGEM/PhotonMeson/TableProducer/materialBudgetWeights.cxx @@ -8,20 +8,20 @@ // 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 code loops over v0 photons and makes pairs for photon HBT analysis. -// Please write to: daiki.sekihata@cern.ch +/// +/// \file MaterialBudgetWeights.h +/// +/// \brief This code produces a table to retrieve material budget weights. The table is to be join with V0PhotonKF +/// +/// \author Youssef El Mard (youssef.el.mard.bouziani@cern.ch) -#include "PWGEM/PhotonMeson/Core/PhotonHBT.h" +#include "PWGEM/PhotonMeson/Core/MaterialBudgetWeights.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{ - adaptAnalysisTask>(cfgc, TaskName{"photon-hbt-pcmpcm"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx b/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx index 74ac6e4ed5e..3e8d6cb146f 100644 --- a/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx +++ b/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx @@ -15,10 +15,12 @@ /// dependencies: skimmer-gamma-calo #include "PWGEM/PhotonMeson/Core/EMNonLin.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h" +#include #include #include #include @@ -28,7 +30,10 @@ #include #include +#include + #include +#include #include using namespace o2; @@ -53,13 +58,16 @@ struct NonLinProducer { Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3)"}; Configurable emcIteration{"emcIteration", 0, "iteration number of the non lin correction for EMCal. 0 means first iteration 1 means second and so on!"}; Configurable pcmIteration{"pcmIteration", 0, "iteration number of the non lin correction for PCM. 0 means first iteration 1 means second and so on!"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathEmcal{"ccdbPathEmcal", "Users/m/mhemmer/EM/NonLin/EMC", "CCDB Path to Non Lin TMatrixD for EMCal"}; + Configurable ccdbPathPcm{"ccdbPathPcm", "Users/m/mhemmer/EM/NonLin/PCM", "CCDB Path to Non Lin TMatrixD for PCM"}; HistogramRegistry historeg{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; using EMCalPhotons = soa::Join; using PcmPhotons = soa::Join; - using Colls = soa::Join; + using Colls = soa::Join; EMNonLin emNonLinEMC; EMNonLin emNonLinPCM; @@ -67,6 +75,11 @@ struct NonLinProducer { EMNonLin::Context emNonLinContextEMC; EMNonLin::Context emNonLinContextPCM; + o2::framework::Service ccdb; + + TMatrixD* emcalMatrix = nullptr; + TMatrixD* pcmMatrix = nullptr; + void init(o2::framework::InitContext&) { historeg.add("QA/EMC/EIn", "Energy of EMC clusters before NonLin correction", gHistoSpecClusterE); @@ -80,6 +93,26 @@ struct NonLinProducer { emNonLinContextEMC.setIter(emcIteration); emNonLinContextPCM.setIter(pcmIteration); + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (doprocessEMC) { + emcalMatrix = ccdb->getForTimeStamp(ccdbPathEmcal, collision.timestamp()); + emNonLinEMC.getFromCCDBObject(emcalMatrix, o2::pwgem::nonlin::EMNonLin::PhotonType::kEMC); + emNonLinContextEMC.setParams(emNonLinEMC.resolveParams(o2::pwgem::nonlin::EMNonLin::PhotonType::kEMC)); + } + if (doprocessPCM) { + pcmMatrix = ccdb->getForTimeStamp(ccdbPathPcm, collision.timestamp()); + emNonLinPCM.getFromCCDBObject(pcmMatrix, o2::pwgem::nonlin::EMNonLin::PhotonType::kPCM); + emNonLinContextPCM.setParams(emNonLinPCM.resolveParams(o2::pwgem::nonlin::EMNonLin::PhotonType::kPCM)); + } } /// Get the centrality @@ -112,16 +145,16 @@ struct NonLinProducer { int32_t collIndex = collision.globalIndex(); float cent = getCentrality(collision); - emNonLinContextEMC.setParams(emNonLinEMC.resolveParams(o2::pwgem::nonlin::EMNonLin::PhotonType::kEMC, cent)); + emNonLinContextEMC.setCent(cent); for (const auto& cluster : clusters) { // check that we are at the correct collision - if (cluster.emphotoneventId() != collIndex) { - collIndex = cluster.emphotoneventId(); + if (cluster.pmeventId() != collIndex) { + collIndex = cluster.pmeventId(); collision.setCursor(collIndex); cent = getCentrality(collision); - emNonLinContextEMC.setParams(emNonLinEMC.resolveParams(o2::pwgem::nonlin::EMNonLin::PhotonType::kEMC, cent)); + emNonLinContextEMC.setCent(cent); } // fill before non lin histograms @@ -148,22 +181,22 @@ struct NonLinProducer { int32_t collIndex = collision.globalIndex(); float cent = getCentrality(collision); - emNonLinContextPCM.setParams(emNonLinPCM.resolveParams(o2::pwgem::nonlin::EMNonLin::PhotonType::kPCM, cent)); + emNonLinContextPCM.setCent(cent); for (const auto& v0 : v0s) { // check that we are at the correct collision - if (v0.emphotoneventId() != collIndex) { - collIndex = v0.emphotoneventId(); + if (v0.pmeventId() != collIndex) { + collIndex = v0.pmeventId(); collision.setCursor(collIndex); cent = getCentrality(collision); - emNonLinContextPCM.setParams(emNonLinPCM.resolveParams(o2::pwgem::nonlin::EMNonLin::PhotonType::kPCM, cent)); + emNonLinContextPCM.setCent(cent); } // fill before non lin histograms historeg.fill(HIST("QA/PCM/PtIn"), v0.pt()); // get NonLin factor from class dependent on the centrality - float nonLinFactor = emNonLinEMC.getCorrectionFactor(v0.pt(), emNonLinContextPCM); + float nonLinFactor = emNonLinPCM.getCorrectionFactor(v0.pt(), emNonLinContextPCM); float nonLinPt = nonLinFactor * v0.pt(); @@ -182,6 +215,7 @@ struct NonLinProducer { } auto collision = collisions.begin(); + initCCDB(collision); runEMC(emcclusters, collision); } PROCESS_SWITCH(NonLinProducer, processEMC, "Create Non Lin table for EMC.", false); @@ -192,6 +226,7 @@ struct NonLinProducer { return; } auto collision = collisions.begin(); + initCCDB(collision); runPCM(pcmPhotons, collision); } PROCESS_SWITCH(NonLinProducer, processPCM, "Create Non Lin table for PCM.", false); diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index d8f9edbf43a..9b2f9e0c411 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -18,6 +18,7 @@ #define HomogeneousField // needed for KFParticle::SetField(magneticField); #endif +#include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/Core/EmMlResponsePCM.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCandidate.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" @@ -237,23 +238,24 @@ struct PhotonConversionBuilder { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); - - if (useMatCorrType == MatCorrType::TGeo) { - LOGF(info, "TGeo correction requested, loading geometry"); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); - } - } - if (useMatCorrType == MatCorrType::LUT) { - LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - } - - if (useMatCorrType == MatCorrType::TGeo) { - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - } - if (useMatCorrType == MatCorrType::LUT) { - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + switch (useMatCorrType) { + case MatCorrType::TGeo: + LOGF(info, "TGeo correction requested, loading geometry"); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; + break; + case MatCorrType::LUT: + LOGF(info, "LUT correction requested, loading LUT"); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + break; + default: + LOGF(info, "no correction requested, loading LUT by default!"); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + break; } if (applyPCMMl) { @@ -722,8 +724,10 @@ struct PhotonConversionBuilder { kfp_pos_DecayVtx.TransportToPoint(xyz); // Don't set Primary Vertex kfp_ele_DecayVtx.TransportToPoint(xyz); // Don't set Primary Vertex + float cospaXYKF = cospaXY_KF(gammaKF_DecayVtx, KFPV); + float cospaRZKF = cospaRZ_KF(gammaKF_DecayVtx, KFPV); CentType centType = static_cast(centTypePCMMl.value); - v0photoncandidate.setPhotonCandidate(gammaKF_DecayVtx, kfp_pos_DecayVtx, kfp_ele_DecayVtx, collision, cospa_kf, psipair, phiv, centType); + v0photoncandidate.setPhotonCandidate(gammaKF_DecayVtx, gammaKF_PV, pos, kfp_pos_DecayVtx, ele, kfp_ele_DecayVtx, collision, cospaXYKF, cospaRZKF, cospaXYKF, psipair, phiv, centType, posdcaXY, posdcaZ, eledcaXY, eledcaZ); if (!ele.hasITS() && !pos.hasITS()) { // V0s with TPConly-TPConly if (max_r_itsmft_ss < rxy && rxy < maxX + margin_r_tpc) { @@ -821,11 +825,9 @@ struct PhotonConversionBuilder { registry.fill(HIST("V0/hPCA_diffX"), v0photoncandidate.getPCA(), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive registry.fill(HIST("V0/hPhiVPsiPair"), v0photoncandidate.getPsiPair(), v0photoncandidate.getPhiV()); - float cospaXY_kf = cospaXY_KF(gammaKF_DecayVtx, KFPV); - float cospaRZ_kf = cospaRZ_KF(gammaKF_DecayVtx, KFPV); // LOGF(info, "cospa_kf = %f, cospaXY_kf = %f, cospaRZ_kf = %f", cospa_kf, cospaXY_kf, cospaRZ_kf); - registry.fill(HIST("V0/hCosPAXY_Rxy"), rxy, cospaXY_kf); - registry.fill(HIST("V0/hCosPARZ_Rxy"), rxy, cospaRZ_kf); + registry.fill(HIST("V0/hCosPAXY_Rxy"), rxy, cospaXYKF); + registry.fill(HIST("V0/hCosPARZ_Rxy"), rxy, cospaRZKF); for (const auto& leg : {kfp_pos_DecayVtx, kfp_ele_DecayVtx}) { float legpt = RecoDecay::sqrtSumOfSquares(leg.GetPx(), leg.GetPy()); @@ -854,7 +856,7 @@ struct PhotonConversionBuilder { gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY(), gammaKF_DecayVtx.GetZ(), gammaKF_PV.GetPx(), gammaKF_PV.GetPy(), gammaKF_PV.GetPz(), v0_sv.M(), v0photoncandidate.getDcaXYToPV(), v0photoncandidate.getDcaZToPV(), - cospa_kf, cospaXY_kf, cospaRZ_kf, + cospa_kf, cospaXYKF, cospaRZKF, v0photoncandidate.getPCA(), v0photoncandidate.getAlpha(), v0photoncandidate.getQt(), v0photoncandidate.getChi2NDF()); v0photonsphivpsi(v0photoncandidate.getPhiV(), v0photoncandidate.getPsiPair()); diff --git a/PWGEM/PhotonMeson/TableProducer/pmQvectorDummyOtf.cxx b/PWGEM/PhotonMeson/TableProducer/pmQvectorDummyOtf.cxx new file mode 100644 index 00000000000..b67aeb53d41 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/pmQvectorDummyOtf.cxx @@ -0,0 +1,48 @@ +// 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 pmQvectorDummyOtf.cxx +/// \author Marvin Hemmer +/// \brief This code produces on-the-fly dummy qvector table. + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct PmQvectorDummyOtf { + Produces eventQvecs; + + void init(InitContext&) {} + + void process(aod::PMEvents const& collisions) + { + for (int i = 0; i < collisions.size(); i++) { + eventQvecs( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } // end of collision loop + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx index c33a1e2020e..0d7afd0a63e 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx @@ -13,6 +13,7 @@ /// \author daiki.sekihata@cern.ch #include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include @@ -37,7 +38,7 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::constants::physics; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyTracks = soa::Join; @@ -54,7 +55,7 @@ struct skimmerDalitzEE { }; SliceCache cache; - Preslice perCol = o2::aod::emprimaryelectronda::emphotoneventId; + Preslice perCol = o2::aod::emprimaryelectronda::pmeventId; SliceCache cache_cefp; PresliceUnsorted perCol_cefp = o2::aod::emprimaryelectron::collisionId; @@ -337,8 +338,8 @@ struct skimmerDalitzEE { continue; } - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); fRegistry.fill(HIST("hNpos"), collision.centFT0C(), posTracks_per_coll.size()); fRegistry.fill(HIST("hNele"), collision.centFT0C(), negTracks_per_coll.size()); // LOGF(info, "collision.centFT0C() = %f, posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", collision.centFT0C() , posTracks_per_coll.size(), negTracks_per_coll.size()); @@ -375,7 +376,7 @@ struct skimmerDalitzEE { } PROCESS_SWITCH(skimmerDalitzEE, processCEFP, "Process dalitz ee for CEFP", false); // for central event filter processing - void processOnlyNee(soa::Join const& collisions) + void processOnlyNee(soa::Join const& collisions) { for (auto& collision : collisions) { float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; diff --git a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt index e0ce318628f..fe155e91fe1 100644 --- a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt @@ -131,11 +131,6 @@ o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-emcemc PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(photon-hbt-pcmpcm - SOURCES PhotonHBTPCMPCM.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(tag-and-probe SOURCES TagAndProbe.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore @@ -200,3 +195,8 @@ o2physics_add_dpl_workflow(photon-reso-task SOURCES photonResoTask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::EMCALBase O2::EMCALCalib O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(photonhbt + SOURCES photonhbt.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx b/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx index a023826777b..0ee3d8e2f3e 100644 --- a/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx +++ b/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx @@ -17,6 +17,7 @@ #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "Common/CCDB/EventSelectionParams.h" @@ -70,10 +71,10 @@ using namespace o2::aod::pwgem::dilepton::utils::mcutil; using namespace o2::aod::pwgem::dilepton::utils; using o2::constants::math::TwoPI; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyCollisionsMC = soa::Join; +using MyCollisionsMC = soa::Join; using MyCollisionMC = MyCollisionsMC::iterator; using MyMCCollisions = soa::Join; @@ -831,8 +832,8 @@ struct MaterialBudget { } SliceCache cache; - Preslice perCollision = aod::v0photonkf::emphotoneventId; - Preslice perCollisionElectron = aod::emprimaryelectronda::emphotoneventId; + Preslice perCollision = aod::v0photonkf::pmeventId; + Preslice perCollisionElectron = aod::emprimaryelectronda::pmeventId; Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && dileptoncuts.cfgMinPtTrack < o2::aod::track::pt&& nabs(o2::aod::track::eta) < dileptoncuts.cfgMaxEtaTrack; Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && dileptoncuts.cfgMinPtTrack < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfgMaxEtaTrack; diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx b/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx index 7956146ae89..7e5d8d80fc6 100644 --- a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx @@ -18,6 +18,7 @@ #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" #include "PWGEM/PhotonMeson/Core/PairCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" @@ -57,7 +58,7 @@ using namespace o2::aod::pwgem::photonmeson::utils::mcutil; using namespace o2::aod::pwgem::dilepton::utils::mcutil; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -227,7 +228,7 @@ struct MaterialBudgetMC { LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); } - Preslice perCollision_pcm = aod::v0photonkf::emphotoneventId; + Preslice perCollision_pcm = aod::v0photonkf::pmeventId; template bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& tagcut, TCut2 const& probecut) diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx index 62c57593fd0..9ec33da1389 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx @@ -13,6 +13,7 @@ /// \brief This code loops over photons and makes pairs for neutral mesons analyses in MC for PCM-PCM. /// \author D. Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/Core/MaterialBudgetWeights.h" #include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" @@ -26,7 +27,7 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::aod::pwgem::photonmeson::photonpair; -using MyV0Photons = o2::soa::Filtered>; +using MyV0Photons = o2::soa::Filtered>; using MyMCV0Legs = soa::Join; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx index 6272af75da6..a19c2ac5be0 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx @@ -13,6 +13,7 @@ /// \brief This code loops over photons and makes pairs for neutral mesons analyses for PCM-PCM. /// \author D. Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/Core/MaterialBudgetWeights.h" #include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" @@ -26,7 +27,7 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::aod::pwgem::photonmeson::photonpair; -using MyV0Photons = o2::soa::Filtered>; +using MyV0Photons = o2::soa::Filtered>; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx b/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx index 1c536cf5751..62d2e47a234 100644 --- a/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx +++ b/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx @@ -21,6 +21,7 @@ #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "Common/CCDB/TriggerAliases.h" @@ -53,7 +54,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -241,7 +242,7 @@ struct SinglePhoton { LOGF(info, "Number of EMCal cuts = %d", fEMCCuts.size()); } - Preslice perCollision = aod::v0photonkf::emphotoneventId; + Preslice perCollision = aod::v0photonkf::pmeventId; // Preslice perCollision_phos = aod::skimmedcluster::collisionId; // Preslice perCollision_emc = aod::skimmedcluster::collisionId; diff --git a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx index f583890fd53..e8e083dca28 100644 --- a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx @@ -21,6 +21,7 @@ #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" @@ -52,7 +53,7 @@ using namespace o2::aod::pwgem::photonmeson::utils::mcutil; using namespace o2::aod::pwgem::dilepton::utils::mcutil; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -242,7 +243,7 @@ struct SinglePhotonMC { // LOGF(info, "Number of EMCal cuts = %d", fEMCCuts.size()); // } - Preslice perCollision = aod::v0photonkf::emphotoneventId; + Preslice perCollision = aod::v0photonkf::pmeventId; // Preslice perCollision_phos = aod::skimmedcluster::collisionId; // Preslice perCollision_emc = aod::skimmedcluster::collisionId; diff --git a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx index 91b46605947..ac3f50b594a 100644 --- a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx +++ b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx @@ -22,6 +22,7 @@ #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/PairCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" @@ -65,7 +66,7 @@ using namespace o2::soa; using namespace o2::aod::pwgem::photonmeson::photonpair; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -245,7 +246,7 @@ struct TagAndProbe { LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); } - Preslice perCollision = aod::v0photonkf::emphotoneventId; + Preslice perCollision = aod::v0photonkf::pmeventId; Preslice perCollision_phos = aod::skimmedcluster::collisionId; Preslice perCollision_emc = aod::skimmedcluster::collisionId; diff --git a/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx index 66d140bf308..8d0b0ee7b3a 100644 --- a/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx +++ b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx @@ -17,6 +17,7 @@ #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" @@ -182,6 +183,11 @@ struct CalibTaskEmc { o2::framework::Configurable rejectV0onITSib{"rejectV0onITSib", true, "flag to reject V0s on ITSib"}; o2::framework::Configurable applyPrefilter{"applyPrefilter", false, "flag to apply prefilter to V0"}; + o2::framework::Configurable mTooCloseType{"mTooCloseType", 2, "type of cut for too close (0 = no, 1 = squared distance, 2 = opening angle + dR) "}; + o2::framework::Configurable mMinV0DistSquared{"mMinV0DistSquared", 4.f, "min squared distance for mTooCloseType == 1"}; + o2::framework::Configurable mDeltaR{"mDeltaR", 6.f, "deltaR for mTooCloseType == 2"}; + o2::framework::Configurable mMinOpeningAngle{"mMinOpeningAngle", 0.02, "min opening angle for mTooCloseType == 2"}; + o2::framework::Configurable minNClusterTPC{"minNClusterTPC", 0, "min NCluster TPC"}; o2::framework::Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 40, "min ncrossed rows in TPC"}; o2::framework::Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "min fraction of crossed rows over findable clusters in TPC"}; @@ -228,12 +234,12 @@ struct CalibTaskEmc { Filter collisionFilter = (nabs(aod::collision::posZ) <= eventcuts.cfgZvtxMax) && (aod::evsel::ft0cOccupancyInTimeRange <= eventcuts.cfgFT0COccupancyMax) && (aod::evsel::ft0cOccupancyInTimeRange >= eventcuts.cfgFT0COccupancyMin); using EMCalPhotons = soa::Join; using PCMPhotons = soa::Join; - using FilteredCollsWithQvecs = soa::Filtered>; - using CollsWithQvecs = soa::Join; - using Colls = soa::Join; + using FilteredCollsWithQvecs = soa::Filtered>; + using CollsWithQvecs = soa::Join; + using Colls = soa::Join; - PresliceOptional perCollisionEMC = o2::aod::emccluster::emphotoneventId; - PresliceOptional perCollisionPCM = aod::v0photonkf::emphotoneventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; @@ -323,6 +329,10 @@ struct CalibTaskEmc { fV0PhotonCut.SetRxyRange(pcmcuts.minRV0, pcmcuts.maxRV0); fV0PhotonCut.SetAPRange(pcmcuts.maxAlphaAP, pcmcuts.maxQtAP); fV0PhotonCut.RejectITSib(pcmcuts.rejectV0onITSib); + fV0PhotonCut.setTooCloseType(static_cast(pcmcuts.mTooCloseType.value)); + fV0PhotonCut.setMinV0DistSquared(pcmcuts.mMinV0DistSquared); + fV0PhotonCut.setDeltaR(pcmcuts.mDeltaR); + fV0PhotonCut.setMinOpeningAngle(pcmcuts.mMinOpeningAngle); // for track fV0PhotonCut.SetMinNClustersTPC(pcmcuts.minNClusterTPC); @@ -363,20 +373,25 @@ struct CalibTaskEmc { const AxisSpec thAxisEnergy{1000, 0., 100., "#it{E}_{clus} (GeV)"}; const AxisSpec thAxisEta{320, -0.8, 0.8, "#eta"}; const AxisSpec thAxisPhi{500, 0, 2 * 3.14159, "phi"}; + const AxisSpec thAxisOpeningAngle{180, 0, o2::constants::math::PI, "opening angle (rad)"}; const AxisSpec thnAxisMixingVtx{mixingConfig.cfgVtxBins, "#it{z} (cm)"}; const AxisSpec thnAxisMixingCent{mixingConfig.cfgCentBins, "Centrality (%)"}; if (doprocessEMCal || doprocessEMCalPCMC) { - registry.add("hSparsePi0", "m_{inv} vs p_T vs cent for same event", HistType::kTH3D, {thnAxisInvMass, thAxisEnergyCalib, thnAxisCent}); + registry.add("hSparsePi0", "m_{inv} vs E vs cent for same event", HistType::kTH3D, {thnAxisInvMass, thAxisEnergyCalib, thnAxisCent}); + registry.add("hOpeningAngleSE", "opening vs E vs cent for same event", HistType::kTH3D, {thAxisOpeningAngle, thAxisEnergyCalib, thnAxisCent}); } else if (doprocessPCM) { registry.add("hSparsePi0", "m_{inv} vs p_T vs cent for same event", HistType::kTH3D, {thnAxisInvMass, thnAxisPtCalib, thnAxisCent}); + registry.add("hOpeningAngleSE", "opening vs p_T vs cent for same event", HistType::kTH3D, {thAxisOpeningAngle, thnAxisPtCalib, thnAxisCent}); } if (doprocessEMCalMixed || doprocessEMCalPCMMixed) { registry.add("hSparseBkgMix", "m_{inv} vs p_T vs cent for mixed event", HistType::kTH3D, {thnAxisInvMass, thAxisEnergyCalib, thnAxisCent}); + registry.add("hOpeningAngleME", "opening vs E vs cent for same event", HistType::kTH3D, {thAxisOpeningAngle, thAxisEnergyCalib, thnAxisCent}); } else if (doprocessPCMMixed) { registry.add("hSparseBkgMix", "m_{inv} vs p_T vs cent for mixed event", HistType::kTH3D, {thnAxisInvMass, thnAxisPtCalib, thnAxisCent}); + registry.add("hOpeningAngleME", "opening vs p_T vs cent for same event", HistType::kTH3D, {thAxisOpeningAngle, thnAxisPtCalib, thnAxisCent}); } if (doprocessEMCalMixed || doprocessEMCalPCMMixed || doprocessPCMMixed) { @@ -427,7 +442,6 @@ struct CalibTaskEmc { /// \param mass is the invariant mass of the candidate /// \param pt is the transverse momentum of the candidate /// \param cent is the centrality of the collision - /// \param sp is the scalar product template void fillThn(const float mass, const float pt, const float cent) { @@ -435,6 +449,17 @@ struct CalibTaskEmc { registry.fill(HIST(HistTypes[histType]), mass, pt, cent); } + /// Fill THnSparse + /// \param openingAngle opening angle between the two photons + /// \param pt is the transverse momentum of the candidate + /// \param cent is the centrality of the collision + template + void fillOpeningAngleHisto(const float openingAngle, const float pt, const float cent) + { + static constexpr std::string_view HistTypes[3] = {"hOpeningAngleSE", "hOpeningAngleRot", "hOpeningAngleME"}; + registry.fill(HIST(HistTypes[histType]), openingAngle, pt, cent); + } + /// Get the centrality /// \param collision is the collision with the centrality information template @@ -635,6 +660,8 @@ struct CalibTaskEmc { continue; } registry.fill(HIST("hMesonCuts"), 6); + float cent = getCentrality(collision); + fillOpeningAngleHisto<0>(openingAngle, vMeson.Pt(), cent); runFlowAnalysis<0>(collision, vMeson, g1.e()); } } @@ -746,6 +773,8 @@ struct CalibTaskEmc { continue; } registry.fill(HIST("hMesonCutsMixed"), 6); + float cent = getCentrality(c1); + fillOpeningAngleHisto<2>(openingAngle, vMeson.Pt(), cent); runFlowAnalysis<2>(c1, vMeson, g1.e()); } } @@ -822,6 +851,8 @@ struct CalibTaskEmc { registry.fill(HIST("hMesonCuts"), 5); continue; } + float cent = getCentrality(collision); + fillOpeningAngleHisto<0>(openingAngle, vMeson.Pt(), cent); runFlowAnalysis<0>(collision, vMeson, g1.corrE()); } } @@ -912,6 +943,8 @@ struct CalibTaskEmc { continue; } registry.fill(HIST("hMesonCutsMixed"), 6); + float cent = getCentrality(c1); + fillOpeningAngleHisto<2>(openingAngle, vMeson.Pt(), cent); runFlowAnalysis<2>(c1, vMeson, g1.corrE()); } } @@ -972,6 +1005,8 @@ struct CalibTaskEmc { registry.fill(HIST("mesonQA/hAlphaPt"), asymmetry, photon1Pt); } registry.fill(HIST("hMesonCuts"), 6); + float cent = getCentrality(collision); + fillOpeningAngleHisto<0>(openingAngle, vMeson.Pt(), cent); runFlowAnalysis<0>(collision, vMeson, photon1Pt); } } // end of loop over collisions @@ -1046,6 +1081,8 @@ struct CalibTaskEmc { registry.fill(HIST("mesonQA/hAlphaPtMixed"), asymmetry, photon1Pt); } registry.fill(HIST("hMesonCutsMixed"), 6); + float cent = getCentrality(c1); + fillOpeningAngleHisto<2>(openingAngle, vMeson.Pt(), cent); runFlowAnalysis<2>(c1, vMeson, photon1Pt); } } diff --git a/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx b/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx index be0e088e60d..22f05b2bec4 100644 --- a/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx +++ b/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx @@ -15,6 +15,7 @@ #include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGLF/DataModel/LFStrangenessMLTables.h" #include "PWGLF/DataModel/LFStrangenessPIDTables.h" @@ -57,7 +58,7 @@ using MyV0Photons = soa::Join; using MyMCV0Legs = soa::Join; using MyMCV0Leg = MyMCV0Legs::iterator; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyMCCollisions = soa::Join; @@ -128,7 +129,7 @@ struct Compconvbuilder { } // Link V0-photons to their collision - Preslice perV0PhotonCollision = aod::v0photonkf::emphotoneventId; + Preslice perV0PhotonCollision = aod::v0photonkf::pmeventId; void init(InitContext const& /*ctx*/) { @@ -656,7 +657,7 @@ struct Compconvbuilder { } } - Preslice perCollision = aod::v0photonkf::emphotoneventId; + Preslice perCollision = aod::v0photonkf::pmeventId; void processEMV0sMC(MyV0Photons const& v0s, aod::EMMCParticles const& mcparticles, MyMCV0Legs const&, MyCollisions const& collisions) { diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx index 4717c1d307b..e42b30e99cc 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx @@ -17,6 +17,7 @@ #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" @@ -43,7 +44,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyTracks = soa::Join; @@ -332,7 +333,7 @@ struct DalitzEEQC { using FilteredMyCollisions = soa::Filtered; SliceCache cache; - Preslice perCollision_track = aod::emprimaryelectronda::emphotoneventId; + Preslice perCollision_track = aod::emprimaryelectronda::pmeventId; Filter trackFilter = dileptoncuts.cfg_min_pt_track < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dileptoncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dileptoncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dileptoncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dileptoncuts.cfg_max_dcaz; Filter pidFilter = dileptoncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dileptoncuts.cfg_max_TPCNsigmaEl && (o2::aod::pidtpc::tpcNSigmaPi < dileptoncuts.cfg_min_TPCNsigmaPi || dileptoncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi); using FilteredMyTracks = soa::Filtered; @@ -360,8 +361,8 @@ struct DalitzEEQC { fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx index f5e202985be..7a32eddf6ab 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx @@ -18,6 +18,7 @@ #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" @@ -46,7 +47,7 @@ using namespace o2::soa; using namespace o2::aod::pwgem::photonmeson::utils::mcutil; using namespace o2::aod::pwgem::dilepton::utils::mcutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyMCTracks = soa::Join; @@ -487,7 +488,7 @@ struct DalitzEEQCMC { std::vector used_trackIds; SliceCache cache; - Preslice perCollision_track = aod::emprimaryelectronda::emphotoneventId; + Preslice perCollision_track = aod::emprimaryelectronda::pmeventId; Filter trackFilter = dileptoncuts.cfg_min_pt_track < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dileptoncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dileptoncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dileptoncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dileptoncuts.cfg_max_dcaz; Filter pidFilter = dileptoncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dileptoncuts.cfg_max_TPCNsigmaEl && (o2::aod::pidtpc::tpcNSigmaPi < dileptoncuts.cfg_min_TPCNsigmaPi || dileptoncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi); using FilteredMyMCTracks = soa::Filtered; @@ -520,8 +521,8 @@ struct DalitzEEQCMC { fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS diff --git a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx index 651828b8194..39af167b327 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx @@ -16,6 +16,7 @@ #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/ClusterHistograms.h" @@ -47,7 +48,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using EMCalPhotons = soa::Join; @@ -137,7 +138,7 @@ struct EmcalQC { PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; - PresliceOptional perCollisionEMC = o2::aod::emccluster::emphotoneventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; void init(InitContext&) { diff --git a/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx b/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx index c1a9eeed496..7c436bf018c 100644 --- a/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx +++ b/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx @@ -16,6 +16,7 @@ #include "PWGEM/PhotonMeson/Tasks/gammaConversions.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h" @@ -619,8 +620,8 @@ struct GammaConversions { } } - Preslice perCollision = aod::v0photonkf::emphotoneventId; - void processRec(aod::EMEvents::iterator const& theCollision, + Preslice perCollision = aod::v0photonkf::pmeventId; + void processRec(aod::PMEvents::iterator const& theCollision, V0DatasAdditional const& theV0s, aod::V0Legs const&) { @@ -645,7 +646,7 @@ struct GammaConversions { Preslice gperV0 = aod::gammamctrue::v0photonkfId; - void processMc(aod::EMEvents::iterator const& theCollision, + void processMc(aod::PMEvents::iterator const& theCollision, V0DatasAdditional const& theV0s, V0LegsWithMC const&, aod::V0DaughterMcParticles const&, diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index d8a006afd3f..7435451a3a6 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -15,6 +15,7 @@ #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "Common/CCDB/EventSelectionParams.h" @@ -48,7 +49,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -476,8 +477,8 @@ struct PCMQC { // fRegistry.fill(HIST("V0Leg/hZY"), leg.z(), leg.y()); } - Preslice perCollisionV0 = aod::v0photonkf::emphotoneventId; - Preslice perCollisionV0ML = aod::v0photonkf::emphotoneventId; + Preslice perCollisionV0 = aod::v0photonkf::pmeventId; + Preslice perCollisionV0ML = aod::v0photonkf::pmeventId; Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx index 5516dfdac41..f35b926e50c 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx @@ -16,6 +16,7 @@ #include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" @@ -54,7 +55,7 @@ using namespace o2::aod::pwgem::photonmeson::utils::mcutil; using namespace o2::aod::pwgem::dilepton::utils::mcutil; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyMCCollisions = soa::Join; @@ -568,8 +569,8 @@ struct PCMQCMC { fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaEta"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.eta() - mcleg.eta()); fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPhi"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.phi() - mcleg.phi()); } - Preslice perCollisionV0 = aod::v0photonkf::emphotoneventId; - Preslice perCollisionV0ML = aod::v0photonkf::emphotoneventId; + Preslice perCollisionV0 = aod::v0photonkf::pmeventId; + Preslice perCollisionV0ML = aod::v0photonkf::pmeventId; Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; diff --git a/PWGEM/PhotonMeson/Tasks/phosQC.cxx b/PWGEM/PhotonMeson/Tasks/phosQC.cxx index 8504be6ae8a..f98c5fcfba2 100644 --- a/PWGEM/PhotonMeson/Tasks/phosQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/phosQC.cxx @@ -17,6 +17,7 @@ #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "Common/CCDB/TriggerAliases.h" @@ -44,7 +45,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; struct phosQC { diff --git a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx index fe6ec07c476..7036c3a30de 100644 --- a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx @@ -18,11 +18,14 @@ #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "Common/Core/RecoDecay.h" + #include #include #include @@ -202,13 +205,13 @@ struct PhotonResoTask { using PcmMcLegs = soa::Join; - using Colls = soa::Join; + using Colls = soa::Join; using McColls = o2::soa::Join; using McParticles = EMMCParticles; - PresliceOptional perCollisionEMC = o2::aod::emccluster::emphotoneventId; - PresliceOptional perCollisionPCM = aod::v0photonkf::emphotoneventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; @@ -314,12 +317,30 @@ struct PhotonResoTask { const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality (%)"}; const AxisSpec thnAxisInvMass{thnConfigAxisInvMass, "#it{M}_{#gamma#gamma} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisEtaGen{280, -0.7, 0.7, "#it{#eta}_{Gen}"}; + const AxisSpec thnAxisEtaRec{280, -0.7, 0.7, "#it{#eta}_{Rec}"}; + + const AxisSpec thnAxisPhiGen{360, 0., o2::constants::math::TwoPI, "#it{#varphi}_{Gen} (rad)"}; + const AxisSpec thnAxisPhiRec{360, 0., o2::constants::math::TwoPI, "#it{#varphi}_{Rec} (rad)"}; + registry.add("EMCal/hPhotonReso", "EMCal photon rec pT vs true pT vs cent", HistType::kTH3D, {thnAxisPtRec, thnAxisPtGen, thnAxisCent}); registry.add("EMCal/hConvPhotonReso", "EMCal conversion photon rec pT vs true pT vs cent ", HistType::kTH3D, {thnAxisPtRec, thnAxisPtGen, thnAxisCent}); registry.add("EMCal/hPi0Reso", "EMCal pi0 rec pT vs true pT vs min vs cent ", HistType::kTHnSparseF, {thnAxisPtRec, thnAxisPtGen, thnConfigAxisInvMass, thnAxisCent}); registry.add("EMCal/hEtaReso", "EMCal eta rec pT vs true pT vs min vs cent ", HistType::kTHnSparseF, {thnAxisPtRec, thnAxisPtGen, thnConfigAxisInvMass, thnAxisCent}); + registry.add("EMCal/hPhotonResoEta", "EMCal photon rec eta vs true eta vs cent", HistType::kTH3D, {thnAxisEtaRec, thnAxisEtaGen, thnAxisCent}); + registry.add("EMCal/hConvPhotonResoEta", "EMCal conversion photon rec eta vs true eta vs cent ", HistType::kTH3D, {thnAxisEtaRec, thnAxisEtaGen, thnAxisCent}); + + registry.add("EMCal/hPi0ResoEta", "EMCal pi0 rec eta vs true eta vs min vs cent ", HistType::kTHnSparseF, {thnAxisEtaRec, thnAxisEtaGen, thnConfigAxisInvMass, thnAxisCent}); + registry.add("EMCal/hEtaResoEta", "EMCal eta rec eta vs true eta vs min vs cent ", HistType::kTHnSparseF, {thnAxisEtaRec, thnAxisEtaGen, thnConfigAxisInvMass, thnAxisCent}); + + registry.add("EMCal/hPhotonResoPhi", "EMCal photon rec phi vs true phi vs cent", HistType::kTH3D, {thnAxisPhiRec, thnAxisPhiGen, thnAxisCent}); + registry.add("EMCal/hConvPhotonResoPhi", "EMCal conversion photon rec phi vs true phi vs cent ", HistType::kTH3D, {thnAxisPhiRec, thnAxisPhiGen, thnAxisCent}); + + registry.add("EMCal/hPi0ResoPhi", "EMCal pi0 rec phi vs true phi vs min vs cent ", HistType::kTHnSparseF, {thnAxisPhiRec, thnAxisPhiGen, thnConfigAxisInvMass, thnAxisCent}); + registry.add("EMCal/hEtaResoPhi", "EMCal eta rec phi vs true phi vs min vs cent ", HistType::kTHnSparseF, {thnAxisPhiRec, thnAxisPhiGen, thnConfigAxisInvMass, thnAxisCent}); + registry.add("PCM/hPhotonReso", "PCM photon rec pT vs true pT vs ", HistType::kTH3D, {thnAxisPtRec, thnAxisPtGen, thnAxisCent}); auto hMesonCuts = registry.add("hMesonCuts", "hMesonCuts;;Counts", kTH1D, {{6, 0.5, 6.5}}, false); @@ -470,11 +491,15 @@ struct PhotonResoTask { if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kGamma) { registry.fill(HIST("EMCal/hPhotonReso"), photonEMC.pt(), mcPhoton1.pt(), cent); + registry.fill(HIST("EMCal/hPhotonResoEta"), photonEMC.eta(), mcPhoton1.eta(), cent); + registry.fill(HIST("EMCal/hPhotonResoPhi"), photonEMC.phi(), mcPhoton1.phi(), cent); } else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kElectron) { if (!o2::aod::pwgem::photonmeson::utils::mcutil::isMotherPDG(mcPhoton1, PDG_t::kGamma)) { continue; } registry.fill(HIST("EMCal/hConvPhotonReso"), photonEMC.pt(), mcPhoton1.pt(), cent); + registry.fill(HIST("EMCal/hConvPhotonResoEta"), photonEMC.eta(), mcPhoton1.eta(), cent); + registry.fill(HIST("EMCal/hConvPhotonResoPhi"), photonEMC.phi(), mcPhoton1.phi(), cent); } } @@ -566,10 +591,14 @@ struct PhotonResoTask { if (pi0id >= 0) { const auto pi0mc = mcParticles.iteratorAt(pi0id); registry.fill(HIST("EMCal/hPi0Reso"), vMeson.Pt(), pi0mc.pt(), vMeson.M(), cent); + registry.fill(HIST("EMCal/hPi0ResoEta"), vMeson.Eta(), pi0mc.eta(), vMeson.M(), cent); + registry.fill(HIST("EMCal/hPi0ResoPhi"), RecoDecay::constrainAngle(vMeson.Phi()), pi0mc.phi(), vMeson.M(), cent); } if (etaid >= 0) { const auto etamc = mcParticles.iteratorAt(etaid); registry.fill(HIST("EMCal/hEtaReso"), vMeson.Pt(), etamc.pt(), vMeson.M(), cent); + registry.fill(HIST("EMCal/hEtaResoEta"), vMeson.Eta(), etamc.eta(), vMeson.M(), cent); + registry.fill(HIST("EMCal/hEtaResoPhi"), RecoDecay::constrainAngle(vMeson.Phi()), etamc.phi(), vMeson.M(), cent); } } } diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx new file mode 100644 index 00000000000..40a6599bb71 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -0,0 +1,1833 @@ +// 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 photonhbt.cxx +/// \brief V0 photon HBT analysis. +/// \author Daiki Sekihata, daiki.sekihata@cern.ch +/// Stefanie Mrozinski, stefanie.mrozinski@cern.ch + +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// Single-photon track-type combo. +enum class V0Combo : int { + Inclusive = 0, + ItstpcItstpc = 1, ///< both legs ITS+TPC + ItstpcTpconly = 2, ///< one ITS+TPC leg, one TPC-only + TpconlyTpconly = 3, ///< both legs TPC-only +}; + +/// Photon-pair track-type combo. +enum class PairCombo : int { + Inclusive = 0, + IiXIi = 1, + IiXIt = 2, + IiXTt = 3, + ItXIt = 4, + ItXTt = 5, + TtXTt = 6, +}; + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyV0Photons = soa::Join; +using MyV0Photon = MyV0Photons::iterator; + +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + +// ─── MC truth classification types ──────────────────────────────────────────── + +/// Per-photon MC truth information built from the two V0 legs. +struct PhotonMCInfo { + bool hasMC = false; // both legs have a valid MC label + bool sameMother = false; // both legs share the same MC mother + bool isTruePhoton = false; // mother PDG == 22 + + int mcPosId = -1; // MC particle index of the positive leg + int mcNegId = -1; // MC particle index of the negative leg + int motherId = -1; // MC particle index of the common mother + int motherPdg = 0; + + bool isPhysicalPrimary = false; +}; + +/// Classification of a photon pair at the MC-truth level. +enum class PairTruthType : uint8_t { + Unknown = 0, + TrueTrueDistinct, // both photons are true, from different MC photons + TrueTrueSamePhoton, // both photons are true, same MC photon (clone/split) + SharedMcLeg, // different reco tracks but same MC-level leg + TrueFake, // one photon is true, one is fake + FakeFake, // both photons are fake + Pi0Daughters, // both photons come from the same MC pi0 +}; + +struct photonhbt { + + template + static inline V0Combo classifyV0Combo(TGamma const& g) + { + const auto pos = g.template posTrack_as(); + const auto neg = g.template negTrack_as(); + const bool posII = pos.hasITS() && pos.hasTPC(); + const bool posTPC = !pos.hasITS() && pos.hasTPC(); + const bool negII = neg.hasITS() && neg.hasTPC(); + const bool negTPC = !neg.hasITS() && neg.hasTPC(); + if (posII && negII) + return V0Combo::ItstpcItstpc; + if ((posII && negTPC) || (posTPC && negII)) + return V0Combo::ItstpcTpconly; + if (posTPC && negTPC) + return V0Combo::TpconlyTpconly; + return V0Combo::Inclusive; + } + + static inline PairCombo classifyPairCombo(V0Combo c1, V0Combo c2) + { + const int i1 = static_cast(c1); + const int i2 = static_cast(c2); + if (i1 <= 0 || i2 <= 0) + return PairCombo::Inclusive; + const int lo = std::min(i1, i2); + const int hi = std::max(i1, i2); + static constexpr std::array, 4> kTable = { + {{0, 0, 0, 0}, {0, 1, 2, 3}, {0, 2, 4, 5}, {0, 3, 5, 6}}}; + return static_cast(kTable[lo][hi]); + } + + // ─── Configurables: histogram axis bins ─────────────────────────────────── + + // HBT physics + ConfigurableAxis confQBins{"confQBins", {60, 0, +0.3f}, "q bins for output histograms"}; + ConfigurableAxis confKtBins{"confKtBins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6}, "kT bins"}; + + // Single-photon QA + ConfigurableAxis confPtBins{"confPtBins", {100, 0.f, 2.f}, "pT bins (GeV/c)"}; + ConfigurableAxis confEtaBins{"confEtaBins", {80, -0.8f, 0.8f}, "eta bins"}; + ConfigurableAxis confPhiBins{"confPhiBins", {90, 0.f, o2::constants::math::TwoPI}, "phi bins (rad) — O2 track phi is in [0, 2pi]"}; + + // Pair angular + ConfigurableAxis confDeltaEtaBins{"confDeltaEtaBins", {100, -0.9f, +0.9f}, "Delta-eta bins"}; + ConfigurableAxis confDeltaPhiBins{"confDeltaPhiBins", {100, -o2::constants::math::PI, o2::constants::math::PI}, "Delta-phi bins (rad)"}; + ConfigurableAxis confEllipseValBins{"confEllipseValBins", {200, 0.f, 10.f}, "ellipse value bins"}; + ConfigurableAxis confCosThetaBins{"confCosThetaBins", {100, 0.f, 1.f}, "cos(theta*) bins"}; + ConfigurableAxis confOpeningAngleBins{"confOpeningAngleBins", {100, 0.f, o2::constants::math::PI}, "opening angle bins (rad)"}; + + // Pair geometry + ConfigurableAxis confRBins{"confRBins", {100, 0.f, 100.f}, "conversion radius bins (cm)"}; + ConfigurableAxis confDeltaRBins{"confDeltaRBins", {120, 0.f, 30.f}, "|R1-R2| bins (cm)"}; + ConfigurableAxis confDeltaR3DBins{"confDeltaR3DBins", {100, 0.f, 100.f}, "3D distance between conversion points (cm)"}; + ConfigurableAxis confDeltaRxyBins{"confDeltaRxyBins", {100, 0.f, 100.f}, "xy distance between conversion points (cm)"}; + ConfigurableAxis confZConvBins{"confZConvBins", {200, -100.f, 100.f}, "conversion z (cm)"}; + ConfigurableAxis confDeltaZBins{"confDeltaZBins", {200, -100.f, 100.f}, "#Deltaz bins (cm)"}; ///< FIX: was missing + + // Event QA + ConfigurableAxis confOccupancyQA{"confOccupancyQA", {100, 0.f, 50000.f}, "occupancy"}; + ConfigurableAxis confCentQABins{"confCentQABins", {110, 0.f, 110.f}, "centrality (%)"}; + + // ─── Axis specs ──────────────────────────────────────────────────────────── + + const AxisSpec axisKt{confKtBins, "k_{T} (GeV/c)"}; + const AxisSpec axisQinv{confQBins, "q_{inv} (GeV/c)"}; + const AxisSpec axisQabsLcms{confQBins, "|#bf{q}|^{LCMS} (GeV/c)"}; + const AxisSpec axisQout{confQBins, "q_{out} (GeV/c)"}; + const AxisSpec axisQside{confQBins, "q_{side} (GeV/c)"}; + const AxisSpec axisQlong{confQBins, "q_{long} (GeV/c)"}; + const AxisSpec axisPt{confPtBins, "p_{T} (GeV/c)"}; + const AxisSpec axisEta{confEtaBins, "#eta"}; + const AxisSpec axisPhi{confPhiBins, "#phi (rad)"}; + const AxisSpec axisDeltaEta{confDeltaEtaBins, "#Delta#eta"}; + const AxisSpec axisDeltaPhi{confDeltaPhiBins, "#Delta#phi (rad)"}; + const AxisSpec axisEllipseVal{confEllipseValBins, "(#Delta#eta/#sigma_{#eta})^{2}+(#Delta#phi/#sigma_{#phi})^{2}"}; + const AxisSpec axisCosTheta{confCosThetaBins, "cos(#theta*)"}; + const AxisSpec axisOpeningAngle{confOpeningAngleBins, "Opening angle (rad)"}; + const AxisSpec axisR{confRBins, "R_{conv} (cm)"}; + const AxisSpec axisDeltaR{confDeltaRBins, "|R_{1}-R_{2}| (cm)"}; + const AxisSpec axisDeltaR3D{confDeltaR3DBins, "|#vec{r}_{1}-#vec{r}_{2}| (cm)"}; + const AxisSpec axisDeltaRxy{confDeltaRxyBins, "#Delta r_{xy} (cm)"}; + const AxisSpec axisZConv{confZConvBins, "z_{conv} (cm)"}; + const AxisSpec axisDeltaZ{confDeltaZBins, "#Delta z (cm)"}; ///< FIX: was missing + const AxisSpec axisOccupancy{confOccupancyQA, "occupancy"}; + const AxisSpec axisCentQA{confCentQABins, "centrality (%)"}; + + // ─── Configurables: QA flags ─────────────────────────────────────────────── + + struct : ConfigurableGroup { + std::string prefix = "qaflags_group"; + Configurable doPairQa{"doPairQa", true, "fill pair QA histograms at each cut step"}; + Configurable doSinglePhotonQa{"doSinglePhotonQa", true, "fill single-photon QA histograms (pT, eta, phi)"}; + Configurable cfgMaxQinvForQA{"cfgMaxQinvForQA", 0.1f, + "fill per-step pair QA histograms (hDeltaEta, hDeltaPhi, THnSparses, ...) " + "only when q_inv < this value (GeV/c). " + "Set to the HBT signal region, typically 0.1. " + "Set <= 0 to disable the gate. The CF is always filled regardless."}; + Configurable cfgMaxQinvForFullRange{"cfgMaxQinvForFullRange", 0.3f, + "fill full-range histograms (hDeltaRVsQinv, hSparseDeltaRDeltaZQinv, ...) " + "only when q_inv < this value (GeV/c). " + "Should match the upper edge of confQBins (default 0.3) — " + "fills beyond the axis range only go into the overflow bin. " + "Set <= 0 to disable the gate."}; + } qaflags; + + // ─── Configurables: HBT kind ─────────────────────────────────────────────── + + Configurable cfgDo3D{"cfgDo3D", false, "enable 3D (qout,qside,qlong) analysis"}; + Configurable cfgDo2D{"cfgDo2D", false, "enable 2D (qout,qinv) projection (requires cfgDo3D)"}; + Configurable cfgUseLCMS{"cfgUseLCMS", true, "measure 1D relative momentum in LCMS"}; + + // ─── Configurables: events ───────────────────────────────────────────────── + + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable maxY{"maxY", 0.9, "maximum rapidity"}; + + // ─── Configurables: mixed event ──────────────────────────────────────────── + + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth{"ndepth", 100, "depth for event mixing"}; + Configurable ndiffBCMix{"ndiffBCMix", 594, "difference in global BC required for mixed events"}; + Configurable cfgEP2EstimatorForMix{"cfgEP2EstimatorForMix", 3, "FT0M:0, FT0A:1, FT0C:2, FV0A:3, BTot:4, BPos:5, BNeg:6"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + + ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.f, -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 ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.f, 5.f, 10.f, 20.f, 30.f, 40.f, 50.f, 60.f, 70.f, 80.f, 90.f, 100.f, 999.f}, "Mixing bins - centrality"}; + ConfigurableAxis ConfEPBins{"ConfEPBins", {16, -o2::constants::math::PIHalf, +o2::constants::math::PIHalf}, "Mixing bins - EP angle"}; + ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + + // ─── Configurables: pair cuts ────────────────────────────────────────────── + + struct : ConfigurableGroup { + std::string prefix = "ggpaircut_group"; + // dr/cosOA cut + Configurable cfgMinDRCosOA{"cfgMinDRCosOA", -1.f, "min. dr/cosOA; <0 = disabled"}; + // R/Z geometry cuts + Configurable cfgDoRCut{"cfgDoRCut", false, "apply |R1-R2| > cfgMinDeltaR cut"}; + Configurable cfgMinDeltaR{"cfgMinDeltaR", 0.f, "minimum |R1-R2| (cm)"}; + Configurable cfgDoZCut{"cfgDoZCut", false, "apply |DeltaZ| > cfgMinDeltaZ cut"}; + Configurable cfgMinDeltaZ{"cfgMinDeltaZ", 0.f, "minimum |DeltaZ| (cm)"}; + // Ellipse cut in (DeltaEta, DeltaPhi) + Configurable cfgDoEllipseCut{"cfgDoEllipseCut", false, "reject pairs inside ellipse in DeltaEta-DeltaPhi"}; + Configurable cfgEllipseSigEta{"cfgEllipseSigEta", 0.02f, "sigma_eta for ellipse cut"}; + Configurable cfgEllipseSigPhi{"cfgEllipseSigPhi", 0.02f, "sigma_phi for ellipse cut"}; + Configurable cfgEllipseR2{"cfgEllipseR2", 1.0f, "R^2 threshold: reject if ellipse value < R^2"}; + } ggpaircuts; + + // ─── Event cut ───────────────────────────────────────────────────────────── + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require no TF border"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS ROF border"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx FT0 vs PV"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2.f, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000.f, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "no coll in time range std"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "no coll in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "no coll in ITS ROF std"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "no coll in ITS ROF strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "no HM coll in prev ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "ITS layer 3 OK"}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "ITS layers 0-3 OK"}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "all ITS layers OK"}; + } eventcuts; + + // ─── PCM cut ─────────────────────────────────────────────────────────────── + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfgRequireV0WithITSTPC{"cfgRequireV0WithITSTPC", false, "select V0s with ITS-TPC tracks"}; + Configurable cfgRequireV0WithITSOnly{"cfgRequireV0WithITSOnly", false, "select V0s with ITS-only tracks"}; + Configurable cfgRequireV0WithTPCOnly{"cfgRequireV0WithTPCOnly", false, "select V0s with TPC-only tracks"}; + Configurable cfgMinPtV0{"cfgMinPtV0", 0.1, "min pT for V0 photons at PV"}; + Configurable cfgMaxEtaV0{"cfgMaxEtaV0", 0.8, "max eta for V0 photons at PV"}; + Configurable cfgMinV0Radius{"cfgMinV0Radius", 16.0, "min V0 radius"}; + Configurable cfgMaxV0Radius{"cfgMaxV0Radius", 90.0, "max V0 radius"}; + Configurable cfgMaxAlphaAP{"cfgMaxAlphaAP", 0.95, "max alpha for AP cut"}; + Configurable cfgMaxQtAP{"cfgMaxQtAP", 0.01, "max qT for AP cut"}; + Configurable cfgMinCosPA{"cfgMinCosPA", 0.997, "min V0 CosPA"}; + Configurable cfgMaxPCA{"cfgMaxPCA", 3.0, "max distance between 2 legs"}; + Configurable cfgMaxChi2KF{"cfgMaxChi2KF", 1e+10, "max chi2/ndf with KF"}; + Configurable cfgRejectV0OnITSIB{"cfgRejectV0OnITSIB", true, "reject V0s on ITSib"}; + Configurable cfgDisableITSOnlyTrack{"cfgDisableITSOnlyTrack", false, "disable ITS-only tracks"}; + Configurable cfgDisableTPCOnlyTrack{"cfgDisableTPCOnlyTrack", false, "disable TPC-only tracks"}; + Configurable cfgMinNClusterTPC{"cfgMinNClusterTPC", 70, "min ncluster TPC"}; + Configurable cfgMinNCrossedRows{"cfgMinNCrossedRows", 70, "min crossed rows"}; + Configurable cfgMaxFracSharedClustersTPC{"cfgMaxFracSharedClustersTPC", 999.f, "max fraction of shared TPC clusters"}; + Configurable cfgMaxChi2TPC{"cfgMaxChi2TPC", 4.0, "max chi2/NclsTPC"}; + Configurable cfgMaxChi2ITS{"cfgMaxChi2ITS", 36.0, "max chi2/NclsITS"}; + Configurable cfgMinTPCNsigmaEl{"cfgMinTPCNsigmaEl", -3.5, "min TPC nsigma electron"}; + Configurable cfgMaxTPCNsigmaEl{"cfgMaxTPCNsigmaEl", +3.5, "max TPC nsigma electron"}; + } pcmcuts; + + ~photonhbt() + { + delete emh1; + emh1 = nullptr; + delete emh2; + emh2 = nullptr; + mapMixedEventIdToGlobalBC.clear(); + usedPhotonIdsPerCol.clear(); + } + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + + std::mt19937 engine; + std::uniform_int_distribution dist01; + int mRunNumber{0}; + + std::vector ztxBinEdges; + std::vector centBinEdges; + std::vector epBinEgdes; + std::vector occBinEdges; + + // ─── Pair-cut helpers ────────────────────────────────────────────────────── + + inline bool isInsideEllipse(float deta, float dphi) const + { + if (!ggpaircuts.cfgDoEllipseCut.value) // .value needed: operator T() is non-const in O2 + return false; + const float sE = ggpaircuts.cfgEllipseSigEta.value; + const float sP = ggpaircuts.cfgEllipseSigPhi.value; + if (sE < 1e-9f || sP < 1e-9f) + return false; + return (deta / sE) * (deta / sE) + (dphi / sP) * (dphi / sP) < ggpaircuts.cfgEllipseR2.value; + } + + inline bool passRZCut(float deltaR, float deltaZ) const + { + if (ggpaircuts.cfgDoRCut.value && deltaR < ggpaircuts.cfgMinDeltaR.value) + return false; + if (ggpaircuts.cfgDoZCut.value && std::fabs(deltaZ) < ggpaircuts.cfgMinDeltaZ.value) + return false; + return true; + } + + inline bool passQinvQAGate(float qinv) const + { + const float limit = qaflags.cfgMaxQinvForQA.value; + return (limit <= 0.f) || (qinv < limit); + } + + inline bool passQinvFullRangeGate(float qinv) const + { + const float limit = qaflags.cfgMaxQinvForFullRange.value; + return (limit <= 0.f) || (qinv < limit); + } + + static inline float computeCosTheta(const ROOT::Math::PtEtaPhiMVector& v1, + const ROOT::Math::PtEtaPhiMVector& v2) + { + ROOT::Math::PxPyPzEVector p1(v1), p2(v2); + ROOT::Math::PxPyPzEVector pair = p1 + p2; + ROOT::Math::Boost boost(-pair.BoostToCM()); + ROOT::Math::PxPyPzEVector p1cm = boost(p1); + ROOT::Math::XYZVector pairDir(pair.Px(), pair.Py(), pair.Pz()); + ROOT::Math::XYZVector p1cmDir(p1cm.Px(), p1cm.Py(), p1cm.Pz()); + if (pairDir.R() < 1e-9 || p1cmDir.R() < 1e-9) + return -1.f; + return static_cast(pairDir.Unit().Dot(p1cmDir.Unit())); + } + + static void parseBins(const ConfigurableAxis& cfg, std::vector& edges) + { + if (cfg.value[0] == VARIABLE_WIDTH) { + edges = std::vector(cfg.value.begin(), cfg.value.end()); + edges.erase(edges.begin()); + } else { + const int n = static_cast(cfg.value[0]); + const float xmin = static_cast(cfg.value[1]); + const float xmax = static_cast(cfg.value[2]); + edges.resize(n + 1); + for (int i = 0; i <= n; ++i) + edges[i] = xmin + (xmax - xmin) / n * i; + } + } + + static int clampBin(int b, int nmax) { return std::clamp(b, 0, nmax); } + + static int binOf(const std::vector& edges, float val) + { + const int b = static_cast( + std::lower_bound(edges.begin(), edges.end(), val) - edges.begin()) - + 1; + return clampBin(b, static_cast(edges.size()) - 2); + } + + /// ev_id : 0 = same-event, 1 = mixed-event + /// step_id: 0 = Before, 1 = AfterDRCosOA, 2 = AfterRZ, 3 = AfterEllipse + template + static constexpr const char* qaPrefix() + { + if constexpr (ev_id == 0) { + if constexpr (step_id == 0) + return "Pair/same/QA/Before/"; + if constexpr (step_id == 1) + return "Pair/same/QA/AfterDRCosOA/"; + if constexpr (step_id == 2) + return "Pair/same/QA/AfterRZ/"; + return "Pair/same/QA/AfterEllipse/"; + } else { + if constexpr (step_id == 0) + return "Pair/mix/QA/Before/"; + if constexpr (step_id == 1) + return "Pair/mix/QA/AfterDRCosOA/"; + if constexpr (step_id == 2) + return "Pair/mix/QA/AfterRZ/"; + return "Pair/mix/QA/AfterEllipse/"; + } + } + + template + static constexpr const char* fullRangePrefix() + { + if constexpr (ev_id == 0) + return "Pair/same/FullRange/"; + return "Pair/mix/FullRange/"; + } + + void init(InitContext& /*context*/) + { + mRunNumber = 0; + + parseBins(ConfVtxBins, ztxBinEdges); + parseBins(ConfCentBins, centBinEdges); + parseBins(ConfEPBins, epBinEgdes); + parseBins(ConfOccupancyBins, occBinEdges); + + emh1 = new MyEMH(ndepth); + emh2 = new MyEMH(ndepth); + + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + DefineEMEventCut(); + DefinePCMCut(); + addhistograms(); + + std::random_device seedGen; + engine = std::mt19937(seedGen()); + dist01 = std::uniform_int_distribution(0, 1); + + fRegistry.add("Pair/mix/hDiffBC", + "diff. global BC in mixed event;|BC_{current}-BC_{mixed}|", + kTH1D, {{10001, -0.5, 10000.5}}, true); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) + return; + mRunNumber = collision.runNumber(); + } + + // ─── PairQAObservables ───────────────────────────────────────────────────── + /// Plain data struct holding all observables computed from a photon pair. + /// Defined early so all histogram-booking and fill functions can use it. + + struct PairQAObservables { + // photon four-vectors and pair kinematics + ROOT::Math::PtEtaPhiMVector v1; + ROOT::Math::PtEtaPhiMVector v2; + ROOT::Math::PtEtaPhiMVector k12; + // conversion-point coordinates + float x1 = 0.f, y1 = 0.f, z1 = 0.f; + float x2 = 0.f, y2 = 0.f, z2 = 0.f; + // conversion-point radii and distances + float r1 = 0.f, r2 = 0.f; + float dx = 0.f, dy = 0.f, dz = 0.f; + float deltaR = 0.f; ///< |R1-R2| + float deltaZ = 0.f; ///< z1-z2 + float deltaRxy = 0.f; ///< sqrt(dx^2+dy^2) + float deltaR3D = 0.f; ///< sqrt(dx^2+dy^2+dz^2) + // opening angle of conversion-point vectors + float opa = 0.f; + float cosOA = 0.f; + float drOverCosOA = 0.f; + float deta = 0.f, dphi = 0.f; + float pairEta = 0.f, pairPhi = 0.f; + float kt = 0.f, qinv = 0.f; + float cosTheta = 0.f; + float openingAngle = 0.f; + // validity flag + bool valid = true; + }; + + void addSinglePhotonQAHistogramsForStep(const std::string& path) + { + fRegistry.add((path + "hPt").c_str(), "p_{T};p_{T} (GeV/c);counts", kTH1D, {axisPt}, true); + fRegistry.add((path + "hEta").c_str(), "#eta;#eta;counts", kTH1D, {axisEta}, true); + fRegistry.add((path + "hPhi").c_str(), "#phi;#phi (rad);counts", kTH1D, {axisPhi}, true); + fRegistry.add((path + "hEtaVsPhi").c_str(), "acceptance;#phi (rad);#eta", kTH2D, {axisPhi, axisEta}, true); + fRegistry.add((path + "hR").c_str(), "R_{conv};R_{conv} (cm);counts", kTH1D, {axisR}, true); + fRegistry.add((path + "hZConv").c_str(), "z_{conv};z_{conv} (cm);counts", kTH1D, {axisZConv}, true); + fRegistry.add((path + "hRVsZConv").c_str(), "R_{conv} vs z_{conv};z_{conv} (cm);R_{conv} (cm)", kTH2D, {axisZConv, axisR}, true); + } + + void addFullRangeHistograms(const std::string& path) + { + fRegistry.add((path + "hDeltaRVsQinv").c_str(), "|R_{1}-R_{2}| vs q_{inv} (full range);q_{inv} (GeV/c);|R_{1}-R_{2}| (cm)", kTH2D, {axisQinv, axisDeltaR}, true); + fRegistry.add((path + "hDeltaZVsQinv").c_str(), "#Delta z vs q_{inv} (full range);q_{inv} (GeV/c);#Delta z (cm)", kTH2D, {axisQinv, axisDeltaZ}, true); + fRegistry.add((path + "hDeltaR3DVsQinv").c_str(), "#Delta r_{3D} vs q_{inv} (full range);q_{inv} (GeV/c);#Delta r_{3D} (cm)", kTH2D, {axisQinv, axisDeltaR3D}, true); + fRegistry.add((path + "hQinvVsCent").c_str(), "q_{inv} vs centrality (full range);centrality (%);q_{inv} (GeV/c)", kTH2D, {axisCentQA, axisQinv}, true); + fRegistry.add((path + "hQinvVsOccupancy").c_str(), "q_{inv} vs occupancy (full range);occupancy;q_{inv} (GeV/c)", kTH2D, {axisOccupancy, axisQinv}, true); + fRegistry.add((path + "hSparseDeltaRDeltaZQinv").c_str(), "|R_{1}-R_{2}|,#Delta z,q_{inv} (full range)", kTHnSparseD, {axisDeltaR, axisDeltaZ, axisQinv}, true); + fRegistry.add((path + "hDeltaRCosOAVsQinv").c_str(), "#Delta r/cos(#theta_{op}/2) vs q_{inv};q_{inv} (GeV/c);#Delta r/cos(#theta_{op}/2) (cm)", kTH2D, {axisQinv, {100, 0, 100}}, true); + } + + /// ev_id : 0 = same-event, 1 = mixed-event + template + inline void fillFullRangeQA(PairQAObservables const& obs, float cent, float occupancy) + { + constexpr auto base = fullRangePrefix(); + fRegistry.fill(HIST(base) + HIST("hDeltaRVsQinv"), obs.qinv, obs.deltaR); + fRegistry.fill(HIST(base) + HIST("hDeltaZVsQinv"), obs.qinv, obs.deltaZ); + fRegistry.fill(HIST(base) + HIST("hDeltaR3DVsQinv"), obs.qinv, obs.deltaR3D); + fRegistry.fill(HIST(base) + HIST("hQinvVsCent"), cent, obs.qinv); + fRegistry.fill(HIST(base) + HIST("hQinvVsOccupancy"), occupancy, obs.qinv); + fRegistry.fill(HIST(base) + HIST("hSparseDeltaRDeltaZQinv"), + obs.deltaR, obs.deltaZ, obs.qinv); + } + + template + inline void fillFullRangeDeltaRCosOA(float qinv, float drOverCosOA) + { + constexpr auto base = fullRangePrefix(); + fRegistry.fill(HIST(base) + HIST("hDeltaRCosOAVsQinv"), qinv, drOverCosOA); + } + + void addQAHistogramsForStep(const std::string& path) + { + // ── 1D: photon kinematics ──────────────────────────────────────────────── + fRegistry.add((path + "hPairEta").c_str(), "pair #eta;#eta_{pair};counts", kTH1D, {axisEta}, true); + fRegistry.add((path + "hPairPhi").c_str(), "pair #phi;#phi_{pair} (rad);counts", kTH1D, {axisPhi}, true); + fRegistry.add((path + "hPairKt").c_str(), "pair k_{T};k_{T} (GeV/c);counts", kTH1D, {axisKt}, true); + fRegistry.add((path + "hQinv").c_str(), "q_{inv};q_{inv} (GeV/c);counts", kTH1D, {axisQinv}, true); + + // ── 1D: angular ───────────────────────────────────────────────────────── + fRegistry.add((path + "hDeltaEta").c_str(), "#Delta#eta;#Delta#eta;counts", kTH1D, {axisDeltaEta}, true); + fRegistry.add((path + "hDeltaPhi").c_str(), "#Delta#phi;#Delta#phi (rad);counts", kTH1D, {axisDeltaPhi}, true); + fRegistry.add((path + "hCosTheta").c_str(), "cos(#theta*) in pair rest frame;cos(#theta*);counts", kTH1D, {axisCosTheta}, true); + fRegistry.add((path + "hOpeningAngle").c_str(), "Opening angle;#alpha (rad);counts", kTH1D, {axisOpeningAngle}, true); + fRegistry.add((path + "hEllipseVal").c_str(), "(#Delta#eta/#sigma_{#eta})^{2}+(#Delta#phi/#sigma_{#phi})^{2};value;counts", kTH1D, {axisEllipseVal}, true); + + // ── 1D: geometry ──────────────────────────────────────────────────────── + fRegistry.add((path + "hR1").c_str(), "R_{conv,1};R_{1} (cm);counts", kTH1D, {axisR}, true); + fRegistry.add((path + "hR2").c_str(), "R_{conv,2};R_{2} (cm);counts", kTH1D, {axisR}, true); + fRegistry.add((path + "hDeltaR").c_str(), "|R_{1}-R_{2}|;|R_{1}-R_{2}| (cm);counts", kTH1D, {axisDeltaR}, true); + fRegistry.add((path + "hDeltaZ").c_str(), "#Delta z;#Delta z (cm);counts", kTH1D, {axisDeltaZ}, true); + fRegistry.add((path + "hDeltaRxy").c_str(), "#Delta r_{xy};#Delta r_{xy} (cm);counts", kTH1D, {axisDeltaRxy}, true); + fRegistry.add((path + "hDeltaR3D").c_str(), "|#vec{r}_{1}-#vec{r}_{2}|;#Delta r_{3D} (cm);counts", kTH1D, {axisDeltaR3D}, true); + + // ── 1D: event-level ───────────────────────────────────────────────────── + fRegistry.add((path + "hCent").c_str(), "centrality;centrality (%);counts", kTH1D, {axisCentQA}, true); + fRegistry.add((path + "hOccupancy").c_str(), "occupancy;occupancy;counts", kTH1D, {axisOccupancy}, true); + + // ── 2D: angular ───────────────────────────────────────────────────────── + fRegistry.add((path + "hDEtaDPhi").c_str(), "#Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi (rad)", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); + fRegistry.add((path + "hDeltaEtaVsPairEta").c_str(), "#Delta#eta vs #LT#eta#GT_{pair};#LT#eta#GT_{pair};#Delta#eta", kTH2D, {axisEta, axisDeltaEta}, true); + + // ── 2D: geometry ──────────────────────────────────────────────────────── + fRegistry.add((path + "hR1VsR2").c_str(), "R_{1} vs R_{2};R_{1} (cm);R_{2} (cm)", kTH2D, {axisR, axisR}, true); + fRegistry.add((path + "hDeltaRVsDeltaZ").c_str(), "|R_{1}-R_{2}| vs #Delta z;|R_{1}-R_{2}| (cm);#Delta z (cm)", kTH2D, {axisDeltaR, axisDeltaZ}, true); + + // ── 2D: geometry vs kT ────────────────────────────────────────────────── + // Note: hDeltaRVsQinv, hDeltaZVsQinv live in FullRange/ (always filled, full q range) + fRegistry.add((path + "hDeltaRVsKt").c_str(), "|R_{1}-R_{2}| vs k_{T};k_{T} (GeV/c);|R_{1}-R_{2}| (cm)", kTH2D, {axisKt, axisDeltaR}, true); + fRegistry.add((path + "hDeltaZVsKt").c_str(), "#Delta z vs k_{T};k_{T} (GeV/c);#Delta z (cm)", kTH2D, {axisKt, axisDeltaZ}, true); + + // ── 2D: angular vs geometry ───────────────────────────────────────────── + fRegistry.add((path + "hDeltaPhiVsDeltaR").c_str(), "#Delta#phi vs |R_{1}-R_{2}|;|R_{1}-R_{2}| (cm);#Delta#phi (rad)", kTH2D, {axisDeltaR, axisDeltaPhi}, true); + fRegistry.add((path + "hDeltaEtaVsDeltaR").c_str(), "#Delta#eta vs |R_{1}-R_{2}|;|R_{1}-R_{2}| (cm);#Delta#eta", kTH2D, {axisDeltaR, axisDeltaEta}, true); + fRegistry.add((path + "hDeltaPhiVsDeltaZ").c_str(), "#Delta#phi vs #Delta z;#Delta z (cm);#Delta#phi (rad)", kTH2D, {axisDeltaZ, axisDeltaPhi}, true); + fRegistry.add((path + "hDeltaEtaVsDeltaZ").c_str(), "#Delta#eta vs #Delta z;#Delta z (cm);#Delta#eta", kTH2D, {axisDeltaZ, axisDeltaEta}, true); + + // ── 2D: vs event properties ───────────────────────────────────────────── + fRegistry.add((path + "hDeltaRVsCent").c_str(), "|R_{1}-R_{2}| vs centrality;centrality (%);|R_{1}-R_{2}| (cm)", kTH2D, {axisCentQA, axisDeltaR}, true); + fRegistry.add((path + "hDeltaRVsOccupancy").c_str(), "|R_{1}-R_{2}| vs occupancy;occupancy;|R_{1}-R_{2}| (cm)", kTH2D, {axisOccupancy, axisDeltaR}, true); + + fRegistry.add((path + "hSparseDEtaDPhiCent").c_str(), + "#Delta#eta,#Delta#phi,centrality", + kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisCentQA}, true); + fRegistry.add((path + "hSparseDEtaDPhiOcc").c_str(), + "#Delta#eta,#Delta#phi,occupancy", + kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisOccupancy}, true); + fRegistry.add((path + "hSparseDEtaDPhiKt").c_str(), + "#Delta#eta,#Delta#phi,k_{T}", + kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisKt}, true); + fRegistry.add((path + "hSparseDeltaRDeltaZKt").c_str(), + "|R_{1}-R_{2}|,#Delta z,k_{T}", + kTHnSparseD, {axisDeltaR, axisDeltaZ, axisKt}, true); + } + + void addhistograms() + { + static constexpr std::string_view det[6] = {"FT0M", "FT0A", "FT0C", "BTot", "BPos", "BNeg"}; + fRegistry.add("Event/before/hEP2_CentFT0C_forMix", + Form("2nd harmonics EP for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", det[cfgEP2EstimatorForMix].data()), + kTH2D, {{110, 0, 110}, {180, -o2::constants::math::PIHalf, +o2::constants::math::PIHalf}}, false); + fRegistry.add("Event/after/hEP2_CentFT0C_forMix", + Form("2nd harmonics EP for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", det[cfgEP2EstimatorForMix].data()), + kTH2D, {{110, 0, 110}, {180, -o2::constants::math::PIHalf, +o2::constants::math::PIHalf}}, false); + + addSinglePhotonQAHistogramsForStep("SinglePhoton/Before/"); + addSinglePhotonQAHistogramsForStep("SinglePhoton/AfterDRCosOA/"); + addSinglePhotonQAHistogramsForStep("SinglePhoton/AfterRZ/"); + addSinglePhotonQAHistogramsForStep("SinglePhoton/AfterEllipse/"); + + // ── HBT correlation functions ───────────────────────────────────────────── + if (cfgDo3D) { + fRegistry.add("Pair/same/CF_3D", "diphoton correlation 3D LCMS", + kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt}, true); + if (cfgDo2D) { + fRegistry.add("Pair/same/CF_2D", "diphoton correlation 2D (qout,qinv)", + kTHnSparseD, {axisQout, axisQinv, axisKt}, true); + } + } else { + if (cfgUseLCMS) { + fRegistry.add("Pair/same/CF_1D", "diphoton correlation 1D LCMS", kTH2D, {axisQabsLcms, axisKt}, true); + } else { + fRegistry.add("Pair/same/CF_1D", "diphoton correlation 1D (qinv)", kTH2D, {axisQinv, axisKt}, true); + } + } + + fRegistry.add("Pair/same/hDeltaRCosOA", + "distance between 2 conversion points / cos(#theta_{op}/2);#Delta r / cos(#theta_{op}/2) (cm);counts", + kTH1D, {{100, 0, 100}}, true); + + // ── QA steps (same-event; mix-event cloned below) ───────────────────────── + addQAHistogramsForStep("Pair/same/QA/Before/"); + addQAHistogramsForStep("Pair/same/QA/AfterDRCosOA/"); + addQAHistogramsForStep("Pair/same/QA/AfterRZ/"); + addQAHistogramsForStep("Pair/same/QA/AfterEllipse/"); + + // ── MC truth histograms (same-event; mix-event cloned below) ───────────── + addMCHistograms(); + + // ── Full-range histograms: always filled, qinv as axis ─────────────────── + addFullRangeHistograms("Pair/same/FullRange/"); + + // Clone all Pair/same/ histograms to Pair/mix/ + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } + + // ─── DefineEMEventCut ────────────────────────────────────────────────────── + + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); + fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); + fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); + } + + // ─── DefinePCMCut ────────────────────────────────────────────────────────── + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + fV0PhotonCut.SetV0PtRange(pcmcuts.cfgMinPtV0, 1e10f); + fV0PhotonCut.SetV0EtaRange(-pcmcuts.cfgMaxEtaV0, +pcmcuts.cfgMaxEtaV0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfgMinCosPA); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfgMaxPCA); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfgMaxChi2KF); + fV0PhotonCut.SetRxyRange(pcmcuts.cfgMinV0Radius, pcmcuts.cfgMaxV0Radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfgMaxAlphaAP, pcmcuts.cfgMaxQtAP); + fV0PhotonCut.RejectITSib(pcmcuts.cfgRejectV0OnITSIB); + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfgMinNClusterTPC); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfgMinNCrossedRows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfgMaxFracSharedClustersTPC); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfgMaxChi2TPC); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfgMinTPCNsigmaEl, pcmcuts.cfgMaxTPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfgMaxChi2ITS); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfgDisableITSOnlyTrack); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfgDisableTPCOnlyTrack); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfgRequireV0WithITSTPC); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfgRequireV0WithITSOnly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfgRequireV0WithTPCOnly); + } + + /// step_id: 0 = Before, 1 = AfterDRCosOA, 2 = AfterRZ, 3 = AfterEllipse + template + static constexpr const char* singlePhotonQAPrefix() + { + if constexpr (step_id == 0) + return "SinglePhoton/Before/"; + if constexpr (step_id == 1) + return "SinglePhoton/AfterDRCosOA/"; + if constexpr (step_id == 2) + return "SinglePhoton/AfterRZ/"; + return "SinglePhoton/AfterEllipse/"; + } + + template + inline void fillSinglePhotonQAStep(TPhoton const& g) + { + if (!qaflags.doSinglePhotonQa) + return; + constexpr auto base = singlePhotonQAPrefix(); + const float r = std::sqrt(g.vx() * g.vx() + g.vy() * g.vy()); + fRegistry.fill(HIST(base) + HIST("hPt"), g.pt()); + fRegistry.fill(HIST(base) + HIST("hEta"), g.eta()); + fRegistry.fill(HIST(base) + HIST("hPhi"), g.phi()); + fRegistry.fill(HIST(base) + HIST("hEtaVsPhi"), g.phi(), g.eta()); + fRegistry.fill(HIST(base) + HIST("hR"), r); + fRegistry.fill(HIST(base) + HIST("hZConv"), g.vz()); + fRegistry.fill(HIST(base) + HIST("hRVsZConv"), g.vz(), r); + } + + template + void fillPairHistogram(TCollision const& /*collision*/, + ROOT::Math::PtEtaPhiMVector v1, + ROOT::Math::PtEtaPhiMVector v2, + float weight = 1.f) + { + float rndm = std::pow(-1, dist01(engine) % 2); + auto k12 = 0.5 * (v1 + v2); + float kt = k12.Pt(); + float qinv = -(((v1 - v2) * rndm).M()); + + ROOT::Math::XYZVector uv_out(k12.Px() / k12.Pt(), k12.Py() / k12.Pt(), 0); + ROOT::Math::XYZVector uv_long(0, 0, 1); + ROOT::Math::XYZVector uv_side = uv_out.Cross(uv_long); + + ROOT::Math::PxPyPzEVector v1c(v1), v2c(v2); + float beta_z = (v1 + v2).Beta() * std::cos((v1 + v2).Theta()); + ROOT::Math::Boost bst_z(0, 0, -beta_z); + auto q12_lcms = bst_z((v1c - v2c) * rndm); + auto q3_lcms = q12_lcms.Vect(); + float qabs_lcms = q3_lcms.R(); + float qout_lcms = q3_lcms.Dot(uv_out); + float qside_lcms = q3_lcms.Dot(uv_side); + float qlong_lcms = q3_lcms.Dot(uv_long); + + if (cfgDo3D) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("CF_3D"), + std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); + if (cfgDo2D) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("CF_2D"), + std::fabs(qout_lcms), std::fabs(qinv), kt, weight); + } + } else { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("CF_1D"), + cfgUseLCMS ? qabs_lcms : qinv, kt, weight); + } + } + + template + void fillPairHistogramMC(TCollision const& /*collision*/, + ROOT::Math::PtEtaPhiMVector v1, + ROOT::Math::PtEtaPhiMVector v2, + float weight = 1.f) + { + + float rndm = std::pow(-1, dist01(engine) % 2); + auto k12 = 0.5 * (v1 + v2); + float kt = k12.Pt(); + float qinv = -(((v1 - v2) * rndm).M()); + + ROOT::Math::XYZVector uv_out(k12.Px() / k12.Pt(), k12.Py() / k12.Pt(), 0); + ROOT::Math::XYZVector uv_long(0, 0, 1); + ROOT::Math::XYZVector uv_side = uv_out.Cross(uv_long); + + ROOT::Math::PxPyPzEVector v1c(v1), v2c(v2); + float beta_z = (v1 + v2).Beta() * std::cos((v1 + v2).Theta()); + ROOT::Math::Boost bst_z(0, 0, -beta_z); + auto q12_lcms = bst_z((v1c - v2c) * rndm); + auto q3_lcms = q12_lcms.Vect(); + float qabs_lcms = q3_lcms.R(); + float qout_lcms = q3_lcms.Dot(uv_out); + float qside_lcms = q3_lcms.Dot(uv_side); + float qlong_lcms = q3_lcms.Dot(uv_long); + + constexpr auto mcDir = []() constexpr -> const char* { + if constexpr (ev_id == 0) { + if constexpr (TruthT == PairTruthType::TrueTrueDistinct) + return "Pair/same/MC/TrueTrueDistinct/"; + if constexpr (TruthT == PairTruthType::TrueTrueSamePhoton) + return "Pair/same/MC/TrueTrueSamePhoton/"; + if constexpr (TruthT == PairTruthType::SharedMcLeg) + return "Pair/same/MC/SharedMcLeg/"; + if constexpr (TruthT == PairTruthType::TrueFake) + return "Pair/same/MC/TrueFake/"; + if constexpr (TruthT == PairTruthType::FakeFake) + return "Pair/same/MC/FakeFake/"; + return "Pair/same/MC/Pi0Daughters/"; + } else { + if constexpr (TruthT == PairTruthType::TrueTrueDistinct) + return "Pair/mix/MC/TrueTrueDistinct/"; + if constexpr (TruthT == PairTruthType::TrueTrueSamePhoton) + return "Pair/mix/MC/TrueTrueSamePhoton/"; + if constexpr (TruthT == PairTruthType::SharedMcLeg) + return "Pair/mix/MC/SharedMcLeg/"; + if constexpr (TruthT == PairTruthType::TrueFake) + return "Pair/mix/MC/TrueFake/"; + if constexpr (TruthT == PairTruthType::FakeFake) + return "Pair/mix/MC/FakeFake/"; + return "Pair/mix/MC/Pi0Daughters/"; + } + }(); + + if (cfgDo3D) { + fRegistry.fill(HIST(mcDir) + HIST("CF_3D"), + std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); + if (cfgDo2D) { + fRegistry.fill(HIST(mcDir) + HIST("CF_2D"), + std::fabs(qout_lcms), std::fabs(qinv), kt, weight); + } + } else { + fRegistry.fill(HIST(mcDir) + HIST("CF_1D"), + cfgUseLCMS ? qabs_lcms : qinv, kt, weight); + } + } + + template + PairQAObservables buildPairQAObservables(TG1 const& g1, TG2 const& g2) + { + PairQAObservables o{}; + + o.x1 = g1.vx(); + o.y1 = g1.vy(); + o.z1 = g1.vz(); + o.x2 = g2.vx(); + o.y2 = g2.vy(); + o.z2 = g2.vz(); + + o.r1 = std::sqrt(o.x1 * o.x1 + o.y1 * o.y1); + o.r2 = std::sqrt(o.x2 * o.x2 + o.y2 * o.y2); + + o.dx = o.x1 - o.x2; + o.dy = o.y1 - o.y2; + o.dz = o.z1 - o.z2; + + o.deltaR = std::fabs(o.r1 - o.r2); + o.deltaZ = o.dz; + o.deltaRxy = std::sqrt(o.dx * o.dx + o.dy * o.dy); + o.deltaR3D = std::sqrt(o.dx * o.dx + o.dy * o.dy + o.dz * o.dz); + + ROOT::Math::XYZVector cp1(o.x1, o.y1, o.z1); + ROOT::Math::XYZVector cp2(o.x2, o.y2, o.z2); + const float mag1 = std::sqrt(cp1.Mag2()); + const float mag2 = std::sqrt(cp2.Mag2()); + if (mag1 < 1e-12f || mag2 < 1e-12f) { + o.valid = false; + return o; + } + float cosPA = static_cast(cp1.Dot(cp2) / (mag1 * mag2)); + cosPA = std::clamp(cosPA, -1.f, 1.f); + o.opa = std::acos(cosPA); + o2::math_utils::bringTo02Pi(o.opa); + if (o.opa > o2::constants::math::PI) + o.opa -= o2::constants::math::PI; + o.cosOA = std::cos(o.opa / 2.f); + o.drOverCosOA = (std::fabs(o.cosOA) < 1e-12f) ? 1e12f : (o.deltaR3D / o.cosOA); + + o.v1 = ROOT::Math::PtEtaPhiMVector(g1.pt(), g1.eta(), g1.phi(), 0.f); + o.v2 = ROOT::Math::PtEtaPhiMVector(g2.pt(), g2.eta(), g2.phi(), 0.f); + o.k12 = 0.5f * (o.v1 + o.v2); + + o.deta = g1.eta() - g2.eta(); + o.dphi = RecoDecay::constrainAngle(g1.phi() - g2.phi(), -o2::constants::math::PI); // dphi in [-pi, pi] + o.pairEta = 0.5f * (g1.eta() + g2.eta()); + o.pairPhi = RecoDecay::constrainAngle(o.k12.Phi(), 0.f); // pair phi in [0, 2pi] — matches axisPhi + o.kt = o.k12.Pt(); + o.qinv = std::fabs((o.v1 - o.v2).M()); + o.cosTheta = std::fabs(computeCosTheta(o.v1, o.v2)); + o.openingAngle = o.opa; + + return o; + } + + template + inline void fillPairQAStep(PairQAObservables const& o, float cent, float occupancy) + { + if (!qaflags.doPairQa) + return; + + constexpr auto base = qaPrefix(); + + // 1D: kinematics + fRegistry.fill(HIST(base) + HIST("hPairEta"), o.pairEta); + fRegistry.fill(HIST(base) + HIST("hPairPhi"), o.pairPhi); + fRegistry.fill(HIST(base) + HIST("hPairKt"), o.kt); + fRegistry.fill(HIST(base) + HIST("hQinv"), o.qinv); + + // 1D: angular + fRegistry.fill(HIST(base) + HIST("hDeltaEta"), o.deta); + fRegistry.fill(HIST(base) + HIST("hDeltaPhi"), o.dphi); + fRegistry.fill(HIST(base) + HIST("hCosTheta"), o.cosTheta); + fRegistry.fill(HIST(base) + HIST("hOpeningAngle"), o.openingAngle); + + // 1D: geometry + fRegistry.fill(HIST(base) + HIST("hR1"), o.r1); + fRegistry.fill(HIST(base) + HIST("hR2"), o.r2); + fRegistry.fill(HIST(base) + HIST("hDeltaR"), o.deltaR); + fRegistry.fill(HIST(base) + HIST("hDeltaZ"), o.deltaZ); + fRegistry.fill(HIST(base) + HIST("hDeltaRxy"), o.deltaRxy); + fRegistry.fill(HIST(base) + HIST("hDeltaR3D"), o.deltaR3D); + + // 1D: event + fRegistry.fill(HIST(base) + HIST("hCent"), cent); + fRegistry.fill(HIST(base) + HIST("hOccupancy"), occupancy); + + // 1D: ellipse value (diagnostic, conditional on cut being configured) + const float sE = ggpaircuts.cfgEllipseSigEta.value; + const float sP = ggpaircuts.cfgEllipseSigPhi.value; + if (sE > 1e-9f && sP > 1e-9f) { + const float ellipseVal = (o.deta / sE) * (o.deta / sE) + (o.dphi / sP) * (o.dphi / sP); + fRegistry.fill(HIST(base) + HIST("hEllipseVal"), ellipseVal); + } + + // 2D: angular + fRegistry.fill(HIST(base) + HIST("hDEtaDPhi"), o.deta, o.dphi); + fRegistry.fill(HIST(base) + HIST("hDeltaEtaVsPairEta"), o.pairEta, o.deta); + + // 2D: geometry + fRegistry.fill(HIST(base) + HIST("hR1VsR2"), o.r1, o.r2); + fRegistry.fill(HIST(base) + HIST("hDeltaRVsDeltaZ"), o.deltaR, o.deltaZ); + + // 2D: geometry vs kT (qinv variants live in FullRange/) + fRegistry.fill(HIST(base) + HIST("hDeltaRVsKt"), o.kt, o.deltaR); + fRegistry.fill(HIST(base) + HIST("hDeltaZVsKt"), o.kt, o.deltaZ); + + // 2D: angular vs geometry + fRegistry.fill(HIST(base) + HIST("hDeltaPhiVsDeltaR"), o.deltaR, o.dphi); + fRegistry.fill(HIST(base) + HIST("hDeltaEtaVsDeltaR"), o.deltaR, o.deta); + fRegistry.fill(HIST(base) + HIST("hDeltaPhiVsDeltaZ"), o.deltaZ, o.dphi); + fRegistry.fill(HIST(base) + HIST("hDeltaEtaVsDeltaZ"), o.deltaZ, o.deta); + + // 2D: vs event properties (qinv variants live in FullRange/) + fRegistry.fill(HIST(base) + HIST("hDeltaRVsCent"), cent, o.deltaR); + fRegistry.fill(HIST(base) + HIST("hDeltaRVsOccupancy"), occupancy, o.deltaR); + + // THnSparse (hSparseDeltaRDeltaZQinv lives in FullRange/) + fRegistry.fill(HIST(base) + HIST("hSparseDEtaDPhiCent"), o.deta, o.dphi, cent); + fRegistry.fill(HIST(base) + HIST("hSparseDEtaDPhiOcc"), o.deta, o.dphi, occupancy); + fRegistry.fill(HIST(base) + HIST("hSparseDEtaDPhiKt"), o.deta, o.dphi, o.kt); + fRegistry.fill(HIST(base) + HIST("hSparseDeltaRDeltaZKt"), o.deltaR, o.deltaZ, o.kt); + } + + template + static PhotonMCInfo buildPhotonMCInfo(TPhoton const& g, + TMCParticles const& mcParticles) + { + PhotonMCInfo info{}; + + const auto pos = g.template posTrack_as(); + const auto neg = g.template negTrack_as(); + + // PWGEM uses emmcparticle, not the standard mcParticle accessor + if (!pos.has_emmcparticle() || !neg.has_emmcparticle()) + return info; + + info.hasMC = true; + info.mcPosId = pos.emmcparticleId(); + info.mcNegId = neg.emmcparticleId(); + + const auto mcPos = pos.template emmcparticle_as(); + const auto mcNeg = neg.template emmcparticle_as(); + + if (!mcPos.has_mothers() || !mcNeg.has_mothers()) + return info; + + const int mothIdPos = mcPos.mothersIds()[0]; + const int mothIdNeg = mcNeg.mothersIds()[0]; + if (mothIdPos != mothIdNeg) + return info; + + info.sameMother = true; + info.motherId = mothIdPos; + + const auto mother = mcParticles.iteratorAt(mothIdPos); + info.motherPdg = mother.pdgCode(); + info.isTruePhoton = (info.motherPdg == 22); + info.isPhysicalPrimary = mother.isPhysicalPrimary(); + + return info; + } + + static PairTruthType classifyPairTruth(PhotonMCInfo const& m1, + PhotonMCInfo const& m2) + { + const bool t1 = m1.hasMC && m1.sameMother && m1.isTruePhoton; + const bool t2 = m2.hasMC && m2.sameMother && m2.isTruePhoton; + + if (m1.hasMC && m2.hasMC) { + if ((m1.mcPosId >= 0 && (m1.mcPosId == m2.mcPosId || m1.mcPosId == m2.mcNegId)) || + (m1.mcNegId >= 0 && (m1.mcNegId == m2.mcPosId || m1.mcNegId == m2.mcNegId))) + return PairTruthType::SharedMcLeg; + } + + if (!t1 && !t2) + return PairTruthType::FakeFake; + if (t1 != t2) + return PairTruthType::TrueFake; + + // Both are true photons — same or different MC photon? + if (m1.motherId >= 0 && m1.motherId == m2.motherId) + return PairTruthType::TrueTrueSamePhoton; + + return PairTruthType::TrueTrueDistinct; + } + + template + static bool isPi0DaughterPair(PhotonMCInfo const& m1, + PhotonMCInfo const& m2, + TMCParticles const& mcParticles) + { + if (!m1.isTruePhoton || !m2.isTruePhoton) + return false; + if (m1.motherId < 0 || m2.motherId < 0) + return false; + // The photons themselves must have the same grandmother = pi0 + const auto ph1 = mcParticles.iteratorAt(m1.motherId); + const auto ph2 = mcParticles.iteratorAt(m2.motherId); + if (!ph1.has_mothers() || !ph2.has_mothers()) + return false; + const int gm1 = ph1.mothersIds()[0]; + const int gm2 = ph2.mothersIds()[0]; + if (gm1 != gm2) + return false; + return (std::abs(mcParticles.iteratorAt(gm1).pdgCode()) == 111); + } + + static constexpr std::string_view pairTruthLabel(PairTruthType t) + { + switch (t) { + case PairTruthType::TrueTrueDistinct: + return "TrueTrueDistinct/"; + case PairTruthType::TrueTrueSamePhoton: + return "TrueTrueSamePhoton/"; + case PairTruthType::SharedMcLeg: + return "SharedMcLeg/"; + case PairTruthType::TrueFake: + return "TrueFake/"; + case PairTruthType::FakeFake: + return "FakeFake/"; + case PairTruthType::Pi0Daughters: + return "Pi0Daughters/"; + default: + return "Unknown/"; + } + } + + void addMCHistograms() + { + const AxisSpec axisTruthType{{0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5}, "truth type (1=TrueTrueDistinct,2=TrueTrueSamePhoton,3=SharedMcLeg,4=TrueFake,5=FakeFake,6=Pi0Daughters)"}; + + static constexpr std::array kTypes = { + "TrueTrueDistinct/", + "TrueTrueSamePhoton/", + "SharedMcLeg/", + "TrueFake/", + "FakeFake/", + "Pi0Daughters/"}; + + for (const auto& label : kTypes) { + const std::string base = std::string("Pair/same/MC/") + std::string(label); + + if (cfgDo3D) { + fRegistry.add((base + "CF_3D").c_str(), "MC CF 3D LCMS", kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt}, true); + if (cfgDo2D) { + fRegistry.add((base + "CF_2D").c_str(), "MC CF 2D", kTHnSparseD, {axisQout, axisQinv, axisKt}, true); + } + } else { + if (cfgUseLCMS) { + fRegistry.add((base + "CF_1D").c_str(), "MC CF 1D LCMS", kTH2D, {axisQabsLcms, axisKt}, true); + } else { + fRegistry.add((base + "CF_1D").c_str(), "MC CF 1D (qinv)", kTH2D, {axisQinv, axisKt}, true); + } + } + + fRegistry.add((base + "hQinv").c_str(), "q_{inv};q_{inv} (GeV/c);counts", kTH1D, {axisQinv}, true); + fRegistry.add((base + "hDeltaEta").c_str(), "#Delta#eta;#Delta#eta;counts", kTH1D, {axisDeltaEta}, true); + fRegistry.add((base + "hDeltaPhi").c_str(), "#Delta#phi;#Delta#phi (rad);counts", kTH1D, {axisDeltaPhi}, true); + fRegistry.add((base + "hDEtaDPhi").c_str(), "#Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); + fRegistry.add((base + "hDeltaR").c_str(), "|R_{1}-R_{2}|;|R_{1}-R_{2}| (cm);counts", kTH1D, {axisDeltaR}, true); + fRegistry.add((base + "hDeltaZ").c_str(), "#Delta z;#Delta z (cm);counts", kTH1D, {axisDeltaZ}, true); + fRegistry.add((base + "hDeltaR3D").c_str(), "#Delta r_{3D};#Delta r_{3D} (cm);counts", kTH1D, {axisDeltaR3D}, true); + fRegistry.add((base + "hKt").c_str(), "k_{T};k_{T} (GeV/c);counts", kTH1D, {axisKt}, true); + fRegistry.add((base + "hDeltaRVsQinv").c_str(), "|R_{1}-R_{2}| vs q_{inv};q_{inv} (GeV/c);|R_{1}-R_{2}| (cm)", kTH2D, {axisQinv, axisDeltaR}, true); + fRegistry.add((base + "hDeltaZVsQinv").c_str(), "#Delta z vs q_{inv};q_{inv} (GeV/c);#Delta z (cm)", kTH2D, {axisQinv, axisDeltaZ}, true); + fRegistry.add((base + "hDeltaR3DVsQinv").c_str(), "#Delta r_{3D} vs q_{inv};q_{inv} (GeV/c);#Delta r_{3D} (cm)", kTH2D, {axisQinv, axisDeltaR3D}, true); + fRegistry.add((base + "hDEtaDPhiVsQinv").c_str(), "#Delta#eta vs #Delta#phi vs q_{inv};#Delta#eta;#Delta#phi;q_{inv}", kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisQinv}, true); + fRegistry.add((base + "hSparseDeltaRDeltaZQinv").c_str(), "|R_{1}-R_{2}|,#Delta z,q_{inv};|R_{1}-R_{2}| (cm);#Delta z (cm);q_{inv} (GeV/c)", kTHnSparseD, {axisDeltaR, axisDeltaZ, axisQinv}, true); + } + + fRegistry.add("Pair/same/MC/hTruthTypeVsQinv", "truth type vs q_{inv};q_{inv} (GeV/c);truth type", kTH2D, {axisQinv, axisTruthType}, true); + fRegistry.add("Pair/same/MC/hTruthTypeVsKt", "truth type vs k_{T};k_{T} (GeV/c);truth type", kTH2D, {axisKt, axisTruthType}, true); + } + + template + inline void fillMCPairQATyped(PairQAObservables const& obs) + { + constexpr auto base = []() constexpr -> const char* { + if constexpr (!IsMix) { + if constexpr (TruthT == PairTruthType::TrueTrueDistinct) + return "Pair/same/MC/TrueTrueDistinct/"; + if constexpr (TruthT == PairTruthType::TrueTrueSamePhoton) + return "Pair/same/MC/TrueTrueSamePhoton/"; + if constexpr (TruthT == PairTruthType::SharedMcLeg) + return "Pair/same/MC/SharedMcLeg/"; + if constexpr (TruthT == PairTruthType::TrueFake) + return "Pair/same/MC/TrueFake/"; + if constexpr (TruthT == PairTruthType::FakeFake) + return "Pair/same/MC/FakeFake/"; + return "Pair/same/MC/Pi0Daughters/"; + } else { + if constexpr (TruthT == PairTruthType::TrueTrueDistinct) + return "Pair/mix/MC/TrueTrueDistinct/"; + if constexpr (TruthT == PairTruthType::TrueTrueSamePhoton) + return "Pair/mix/MC/TrueTrueSamePhoton/"; + if constexpr (TruthT == PairTruthType::SharedMcLeg) + return "Pair/mix/MC/SharedMcLeg/"; + if constexpr (TruthT == PairTruthType::TrueFake) + return "Pair/mix/MC/TrueFake/"; + if constexpr (TruthT == PairTruthType::FakeFake) + return "Pair/mix/MC/FakeFake/"; + return "Pair/mix/MC/Pi0Daughters/"; + } + }(); + + fRegistry.fill(HIST(base) + HIST("hQinv"), obs.qinv); + fRegistry.fill(HIST(base) + HIST("hDeltaEta"), obs.deta); + fRegistry.fill(HIST(base) + HIST("hDeltaPhi"), obs.dphi); + fRegistry.fill(HIST(base) + HIST("hDEtaDPhi"), obs.deta, obs.dphi); + fRegistry.fill(HIST(base) + HIST("hDeltaR"), obs.deltaR); + fRegistry.fill(HIST(base) + HIST("hDeltaZ"), obs.deltaZ); + fRegistry.fill(HIST(base) + HIST("hDeltaR3D"), obs.deltaR3D); + fRegistry.fill(HIST(base) + HIST("hKt"), obs.kt); + + constexpr auto summaryDir = IsMix ? "Pair/mix/MC/" : "Pair/same/MC/"; + const int typeIdx = static_cast(TruthT); + fRegistry.fill(HIST(summaryDir) + HIST("hTruthTypeVsQinv"), obs.qinv, typeIdx); + fRegistry.fill(HIST(summaryDir) + HIST("hTruthTypeVsKt"), obs.kt, typeIdx); + } + + template + inline void fillMCPairQA(PairTruthType truthType, PairQAObservables const& obs) + { + switch (truthType) { + case PairTruthType::TrueTrueDistinct: + fillMCPairQATyped(obs); + break; + case PairTruthType::TrueTrueSamePhoton: + fillMCPairQATyped(obs); + break; + case PairTruthType::SharedMcLeg: + fillMCPairQATyped(obs); + break; + case PairTruthType::TrueFake: + fillMCPairQATyped(obs); + break; + case PairTruthType::FakeFake: + fillMCPairQATyped(obs); + break; + case PairTruthType::Pi0Daughters: + fillMCPairQATyped(obs); + break; + default: + break; + } + } + + template + inline void fillMCPairQAFullRangeTyped(PairQAObservables const& obs) + { + constexpr auto base = []() constexpr -> const char* { + if constexpr (!IsMix) { + if constexpr (TruthT == PairTruthType::TrueTrueDistinct) + return "Pair/same/MC/TrueTrueDistinct/"; + if constexpr (TruthT == PairTruthType::TrueTrueSamePhoton) + return "Pair/same/MC/TrueTrueSamePhoton/"; + if constexpr (TruthT == PairTruthType::SharedMcLeg) + return "Pair/same/MC/SharedMcLeg/"; + if constexpr (TruthT == PairTruthType::TrueFake) + return "Pair/same/MC/TrueFake/"; + if constexpr (TruthT == PairTruthType::FakeFake) + return "Pair/same/MC/FakeFake/"; + return "Pair/same/MC/Pi0Daughters/"; + } else { + if constexpr (TruthT == PairTruthType::TrueTrueDistinct) + return "Pair/mix/MC/TrueTrueDistinct/"; + if constexpr (TruthT == PairTruthType::TrueTrueSamePhoton) + return "Pair/mix/MC/TrueTrueSamePhoton/"; + if constexpr (TruthT == PairTruthType::SharedMcLeg) + return "Pair/mix/MC/SharedMcLeg/"; + if constexpr (TruthT == PairTruthType::TrueFake) + return "Pair/mix/MC/TrueFake/"; + if constexpr (TruthT == PairTruthType::FakeFake) + return "Pair/mix/MC/FakeFake/"; + return "Pair/mix/MC/Pi0Daughters/"; + } + }(); + + fRegistry.fill(HIST(base) + HIST("hDeltaRVsQinv"), obs.qinv, obs.deltaR); + fRegistry.fill(HIST(base) + HIST("hDeltaZVsQinv"), obs.qinv, obs.deltaZ); + fRegistry.fill(HIST(base) + HIST("hDeltaR3DVsQinv"), obs.qinv, obs.deltaR3D); + fRegistry.fill(HIST(base) + HIST("hDEtaDPhiVsQinv"), obs.deta, obs.dphi, obs.qinv); + fRegistry.fill(HIST(base) + HIST("hSparseDeltaRDeltaZQinv"), obs.deltaR, obs.deltaZ, obs.qinv); + } + + template + inline void fillMCPairQAFullRange(PairTruthType truthType, PairQAObservables const& obs) + { + switch (truthType) { + case PairTruthType::TrueTrueDistinct: + fillMCPairQAFullRangeTyped(obs); + break; + case PairTruthType::TrueTrueSamePhoton: + fillMCPairQAFullRangeTyped(obs); + break; + case PairTruthType::SharedMcLeg: + fillMCPairQAFullRangeTyped(obs); + break; + case PairTruthType::TrueFake: + fillMCPairQAFullRangeTyped(obs); + break; + case PairTruthType::FakeFake: + fillMCPairQAFullRangeTyped(obs); + break; + case PairTruthType::Pi0Daughters: + fillMCPairQAFullRangeTyped(obs); + break; + default: + break; + } + } + + template + void runPairing(TCollisions const& collisions, + TPhotons1 const& photons1, TPhotons2 const& photons2, + TSubInfos1 const&, TSubInfos2 const&, + TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, + TCut1 const& cut1, TCut2 const& cut2) + { + for (const auto& collision : collisions) { + initCCDB(collision); + int ndiphoton = 0; + + // ── Centrality selection ────────────────────────────────────────────── + const float cent[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (cent[cfgCentEstimator] < cfgCentMin || cfgCentMax < cent[cfgCentEstimator]) + continue; + + const std::array epArr = { + collision.ep2ft0m(), collision.ep2ft0a(), collision.ep2ft0c(), + collision.ep2fv0a(), collision.ep2btot(), collision.ep2bpos(), collision.ep2bneg()}; + const float ep2 = epArr[cfgEP2EstimatorForMix]; + + // ── Event QA and event cut ──────────────────────────────────────────── + fRegistry.fill(HIST("Event/before/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, 1.f); + if (!fEMEventCut.IsSelected(collision)) + continue; + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, 1.f); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + fRegistry.fill(HIST("Event/after/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + + // ── Event mixing bins ───────────────────────────────────────────────── + const float occupancy = (cfgOccupancyEstimator == 1) + ? static_cast(collision.trackOccupancyInTimeRange()) + : collision.ft0cOccupancyInTimeRange(); + const float centForQA = cent[cfgCentEstimator]; + + const int zbin = binOf(ztxBinEdges, collision.posZ()); + const int centbin = binOf(centBinEdges, centForQA); + const int epbin = binOf(epBinEgdes, ep2); + const int occbin = binOf(occBinEdges, occupancy); + + auto keyBin = std::make_tuple(zbin, centbin, epbin, occbin); + auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); + + // ── Slice photons for this collision ────────────────────────────────── + auto photons1Coll = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2Coll = photons2.sliceBy(perCollision2, collision.globalIndex()); + + // ── Single-photon QA + if (qaflags.doSinglePhotonQa) { + for (const auto& g : photons1Coll) { + if (!cut1.template IsSelected(g)) + continue; + fillSinglePhotonQAStep<0>(g); + } + } + + std::unordered_set photonIdsAfterDRCosOA; + std::unordered_set photonIdsAfterRZ; + std::unordered_set photonIdsAfterEllipse; + + // ── Same-event pair loop ────────────────────────────────────────────── + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1Coll, photons2Coll))) { + if (!cut1.template IsSelected(g1) || + !cut2.template IsSelected(g2)) + continue; + + const auto pos1 = g1.template posTrack_as(); + const auto ele1 = g1.template negTrack_as(); + const auto pos2 = g2.template posTrack_as(); + const auto ele2 = g2.template negTrack_as(); + if (pos1.trackId() == pos2.trackId() || + pos1.trackId() == ele2.trackId() || + ele1.trackId() == pos2.trackId() || + ele1.trackId() == ele2.trackId()) + continue; + + auto obs = buildPairQAObservables(g1, g2); + if (!obs.valid) + continue; + + const bool doQA = passQinvQAGate(obs.qinv); + const bool doFullRange = passQinvFullRangeGate(obs.qinv); + + // ── QA: Before any pair cut ─────────────────────────────────────── + if (doQA) + fillPairQAStep<0, 0>(obs, centForQA, occupancy); + + // ── Cut 1: dr/cosOA ─────────────────────────────────────────────── + if (doFullRange) + fillFullRangeDeltaRCosOA<0>(obs.qinv, obs.drOverCosOA); + fRegistry.fill(HIST("Pair/same/hDeltaRCosOA"), obs.drOverCosOA); + if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) + continue; + + photonIdsAfterDRCosOA.insert(g1.globalIndex()); + photonIdsAfterDRCosOA.insert(g2.globalIndex()); + + // ── QA: After dr/cosOA cut ──────────────────────────────────────── + if (doQA) + fillPairQAStep<0, 1>(obs, centForQA, occupancy); + + // ── Cut 2: R/Z geometry ─────────────────────────────────────────── + if (!passRZCut(obs.deltaR, obs.deltaZ)) + continue; + + photonIdsAfterRZ.insert(g1.globalIndex()); + photonIdsAfterRZ.insert(g2.globalIndex()); + + // ── QA: After R/Z cut ───────────────────────────────────────────── + if (doQA) + fillPairQAStep<0, 2>(obs, centForQA, occupancy); + + // ── Cut 3: Ellipse in (DeltaEta, DeltaPhi) ──────────────────────── + if (isInsideEllipse(obs.deta, obs.dphi)) + continue; + + photonIdsAfterEllipse.insert(g1.globalIndex()); + photonIdsAfterEllipse.insert(g2.globalIndex()); + + // ── QA: After ellipse cut = final accepted pairs ────────────────── + if (doQA) + fillPairQAStep<0, 3>(obs, centForQA, occupancy); + + if (doFullRange) + fillFullRangeQA<0>(obs, centForQA, occupancy); + + fillPairHistogram<0>(collision, obs.v1, obs.v2, 1.f); + ndiphoton++; + + auto addToPool = [&](auto const& g) { + if (usedPhotonIdsPerCol.insert(g.globalIndex()).second) { + EMPair gtmp(g.pt(), g.eta(), g.phi(), 0.f); + gtmp.setConversionPointXYZ(g.vx(), g.vy(), g.vz()); + emh1->AddTrackToEventPool(keyDFCollision, gtmp); + } + }; + addToPool(g1); + addToPool(g2); + } // end same-event pair loop + + if (qaflags.doSinglePhotonQa) { + for (const auto& g : photons1Coll) { + if (!cut1.template IsSelected(g)) + continue; + const int gid = g.globalIndex(); + if (photonIdsAfterDRCosOA.count(gid)) + fillSinglePhotonQAStep<1>(g); + if (photonIdsAfterRZ.count(gid)) + fillSinglePhotonQAStep<2>(g); + if (photonIdsAfterEllipse.count(gid)) + fillSinglePhotonQAStep<3>(g); + } + } + + usedPhotonIdsPerCol.clear(); + + if (!cfgDoMix || ndiphoton == 0) + continue; + + auto selectedPhotons = emh1->GetTracksPerCollision(keyDFCollision); + auto poolIDs = emh1->GetCollisionIdsFromEventPool(keyBin); + + for (const auto& mixID : poolIDs) { + // skip same event + if (mixID.second == collision.globalIndex() && mixID.first == ndf) + continue; + + const uint64_t bcMix = mapMixedEventIdToGlobalBC[mixID]; + const uint64_t diffBC = std::max(collision.globalBC(), bcMix) - + std::min(collision.globalBC(), bcMix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiffBCMix) + continue; + + auto poolPhotons = emh1->GetTracksPerCollision(mixID); + + for (const auto& g1 : selectedPhotons) { + for (const auto& g2 : poolPhotons) { + + auto obs = buildPairQAObservables(g1, g2); + if (!obs.valid) + continue; + + const bool doQA = passQinvQAGate(obs.qinv); + const bool doFullRange = passQinvFullRangeGate(obs.qinv); + + // ── QA: Before any pair cut ───────────────────────────────── + if (doQA) + fillPairQAStep<1, 0>(obs, centForQA, occupancy); + + // ── Cut 1: dr/cosOA ───────────────────────────────────────── + if (doFullRange) + fillFullRangeDeltaRCosOA<1>(obs.qinv, obs.drOverCosOA); + fRegistry.fill(HIST("Pair/mix/hDeltaRCosOA"), obs.drOverCosOA); + if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) + continue; + + // ── QA: After dr/cosOA cut ────────────────────────────────── + if (doQA) + fillPairQAStep<1, 1>(obs, centForQA, occupancy); + + // ── Cut 2: R/Z geometry ───────────────────────────────────── + if (!passRZCut(obs.deltaR, obs.deltaZ)) + continue; + + // ── QA: After R/Z cut ─────────────────────────────────────── + if (doQA) + fillPairQAStep<1, 2>(obs, centForQA, occupancy); + + // ── Cut 3: Ellipse ────────────────────────────────────────── + if (isInsideEllipse(obs.deta, obs.dphi)) + continue; + + // ── QA: After ellipse cut ─────────────────────────────────── + if (doQA) + fillPairQAStep<1, 3>(obs, centForQA, occupancy); + + // ── Full-range fills ──────────────────────────────────────── + if (doFullRange) + fillFullRangeQA<1>(obs, centForQA, occupancy); + + // ── Fill CF histogram — always ────────────────────────────── + fillPairHistogram<1>(collision, obs.v1, obs.v2, 1.f); + } + } + } // end mixed-event loop + + if (ndiphoton > 0) { + emh1->AddCollisionIdAtLast(keyBin, keyDFCollision); + emh2->AddCollisionIdAtLast(keyBin, keyDFCollision); + mapMixedEventIdToGlobalBC[keyDFCollision] = collision.globalBC(); + } + } // end collision loop + } + + using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler< + std::tuple, + std::pair, + EMPair>; + + MyEMH* emh1 = nullptr; + MyEMH* emh2 = nullptr; + + std::unordered_set usedPhotonIdsPerCol; + std::map, uint64_t> mapMixedEventIdToGlobalBC; + + SliceCache cache; + Preslice perCollisionPCM = aod::v0photonkf::pmeventId; + + Filter collisionFilterCentrality = + (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || + (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || + (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilterOccupancyTrack = + eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && + o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilterOccupancyFT0c = + eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && + o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + + using FilteredMyCollisions = soa::Filtered; + + int ndf = 0; + + void processAnalysis(FilteredMyCollisions const& collisions, + MyV0Photons const& v0photons, + aod::V0Legs const& v0legs) + { + runPairing(collisions, + v0photons, v0photons, + v0legs, v0legs, + perCollisionPCM, perCollisionPCM, + fV0PhotonCut, fV0PhotonCut); + ndf++; + } + + PROCESS_SWITCH(photonhbt, processAnalysis, "pairing for analysis", true); + + template + void runPairingMC(TCollisions const& collisions, + TPhotons const& photons, + TLegs const& /*legs*/, + TMCParticles const& mcParticles, + TPreslice const& perCollision, + TCut const& cut) + { + for (const auto& collision : collisions) { + initCCDB(collision); + int ndiphoton = 0; + + const float cent[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (cent[cfgCentEstimator] < cfgCentMin || cfgCentMax < cent[cfgCentEstimator]) + continue; + + const std::array epArr = { + collision.ep2ft0m(), collision.ep2ft0a(), collision.ep2ft0c(), + collision.ep2fv0a(), collision.ep2btot(), collision.ep2bpos(), collision.ep2bneg()}; + const float ep2 = epArr[cfgEP2EstimatorForMix]; + + fRegistry.fill(HIST("Event/before/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, 1.f); + if (!fEMEventCut.IsSelected(collision)) + continue; + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, 1.f); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + fRegistry.fill(HIST("Event/after/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + + const float occupancy = (cfgOccupancyEstimator == 1) + ? static_cast(collision.trackOccupancyInTimeRange()) + : collision.ft0cOccupancyInTimeRange(); + const float centForQA = cent[cfgCentEstimator]; + + const int zbin = binOf(ztxBinEdges, collision.posZ()); + const int centbin = binOf(centBinEdges, centForQA); + const int epbin = binOf(epBinEgdes, ep2); + const int occbin = binOf(occBinEdges, occupancy); + + auto keyBin = std::make_tuple(zbin, centbin, epbin, occbin); + auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); + + auto photonsColl = photons.sliceBy(perCollision, collision.globalIndex()); + + if (qaflags.doSinglePhotonQa) { + for (const auto& g : photonsColl) { + if (!cut.template IsSelected(g)) + continue; + fillSinglePhotonQAStep<0>(g); + } + } + + std::unordered_set photonIdsAfterDRCosOA; + std::unordered_set photonIdsAfterRZ; + std::unordered_set photonIdsAfterEllipse; + + // ── Same-event pair loop ────────────────────────────────────────────── + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photonsColl, photonsColl))) { + if (!cut.template IsSelected(g1) || + !cut.template IsSelected(g2)) + continue; + + const auto pos1 = g1.template posTrack_as(); + const auto ele1 = g1.template negTrack_as(); + const auto pos2 = g2.template posTrack_as(); + const auto ele2 = g2.template negTrack_as(); + if (pos1.trackId() == pos2.trackId() || + pos1.trackId() == ele2.trackId() || + ele1.trackId() == pos2.trackId() || + ele1.trackId() == ele2.trackId()) + continue; + + // ── MC truth classification ─────────────────────────────────────── + const auto mc1 = buildPhotonMCInfo(g1, mcParticles); + const auto mc2 = buildPhotonMCInfo(g2, mcParticles); + auto truthType = classifyPairTruth(mc1, mc2); + if (truthType == PairTruthType::TrueTrueDistinct && + isPi0DaughterPair(mc1, mc2, mcParticles)) + truthType = PairTruthType::Pi0Daughters; + + auto obs = buildPairQAObservables(g1, g2); + if (!obs.valid) + continue; + + const bool doQA = passQinvQAGate(obs.qinv); + const bool doFullRange = passQinvFullRangeGate(obs.qinv); + + // ── Pair QA: Before ─────────────────────────────────────────────── + if (doQA) + fillPairQAStep<0, 0>(obs, centForQA, occupancy); + + // ── Cut 1: dr/cosOA ─────────────────────────────────────────────── + if (doFullRange) + fillFullRangeDeltaRCosOA<0>(obs.qinv, obs.drOverCosOA); + fRegistry.fill(HIST("Pair/same/hDeltaRCosOA"), obs.drOverCosOA); + if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) + continue; + + photonIdsAfterDRCosOA.insert(g1.globalIndex()); + photonIdsAfterDRCosOA.insert(g2.globalIndex()); + if (doQA) + fillPairQAStep<0, 1>(obs, centForQA, occupancy); + + // ── Cut 2: R/Z geometry ─────────────────────────────────────────── + if (!passRZCut(obs.deltaR, obs.deltaZ)) + continue; + + photonIdsAfterRZ.insert(g1.globalIndex()); + photonIdsAfterRZ.insert(g2.globalIndex()); + if (doQA) + fillPairQAStep<0, 2>(obs, centForQA, occupancy); + + // ── Cut 3: Ellipse ──────────────────────────────────────────────── + if (isInsideEllipse(obs.deta, obs.dphi)) + continue; + + photonIdsAfterEllipse.insert(g1.globalIndex()); + photonIdsAfterEllipse.insert(g2.globalIndex()); + if (doQA) + fillPairQAStep<0, 3>(obs, centForQA, occupancy); + + // ── Full-range fills ────────────────────────────────────────────── + if (doFullRange) + fillFullRangeQA<0>(obs, centForQA, occupancy); + + // ── Fill inclusive CF — always ──────────────────────────────────── + fillPairHistogram<0>(collision, obs.v1, obs.v2, 1.f); + ndiphoton++; + + if (doQA) + fillMCPairQA(truthType, obs); + if (doFullRange) + fillMCPairQAFullRange(truthType, obs); + switch (truthType) { + case PairTruthType::TrueTrueDistinct: + fillPairHistogramMC<0, PairTruthType::TrueTrueDistinct>(collision, obs.v1, obs.v2); + break; + case PairTruthType::TrueTrueSamePhoton: + fillPairHistogramMC<0, PairTruthType::TrueTrueSamePhoton>(collision, obs.v1, obs.v2); + break; + case PairTruthType::SharedMcLeg: + fillPairHistogramMC<0, PairTruthType::SharedMcLeg>(collision, obs.v1, obs.v2); + break; + case PairTruthType::TrueFake: + fillPairHistogramMC<0, PairTruthType::TrueFake>(collision, obs.v1, obs.v2); + break; + case PairTruthType::FakeFake: + fillPairHistogramMC<0, PairTruthType::FakeFake>(collision, obs.v1, obs.v2); + break; + case PairTruthType::Pi0Daughters: + fillPairHistogramMC<0, PairTruthType::Pi0Daughters>(collision, obs.v1, obs.v2); + break; + default: + break; + } + + auto addToPool = [&](auto const& g) { + if (usedPhotonIdsPerCol.insert(g.globalIndex()).second) { + EMPair gtmp(g.pt(), g.eta(), g.phi(), 0.f); + gtmp.setConversionPointXYZ(g.vx(), g.vy(), g.vz()); + emh1->AddTrackToEventPool(keyDFCollision, gtmp); + } + }; + addToPool(g1); + addToPool(g2); + } // end same-event pair loop + + if (qaflags.doSinglePhotonQa) { + for (const auto& g : photonsColl) { + if (!cut.template IsSelected(g)) + continue; + const int gid = g.globalIndex(); + if (photonIdsAfterDRCosOA.count(gid)) + fillSinglePhotonQAStep<1>(g); + if (photonIdsAfterRZ.count(gid)) + fillSinglePhotonQAStep<2>(g); + if (photonIdsAfterEllipse.count(gid)) + fillSinglePhotonQAStep<3>(g); + } + } + + usedPhotonIdsPerCol.clear(); + + if (!cfgDoMix || ndiphoton == 0) + continue; + + auto selectedPhotons = emh1->GetTracksPerCollision(keyDFCollision); + auto poolIDs = emh1->GetCollisionIdsFromEventPool(keyBin); + + for (const auto& mixID : poolIDs) { + if (mixID.second == collision.globalIndex() && mixID.first == ndf) + continue; + const uint64_t bcMix = mapMixedEventIdToGlobalBC[mixID]; + const uint64_t diffBC = std::max(collision.globalBC(), bcMix) - + std::min(collision.globalBC(), bcMix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiffBCMix) + continue; + + auto poolPhotons = emh1->GetTracksPerCollision(mixID); + for (const auto& g1 : selectedPhotons) { + for (const auto& g2 : poolPhotons) { + auto obs = buildPairQAObservables(g1, g2); + if (!obs.valid) + continue; + const bool doQA = passQinvQAGate(obs.qinv); + const bool doFullRange = passQinvFullRangeGate(obs.qinv); + if (doQA) + fillPairQAStep<1, 0>(obs, centForQA, occupancy); + if (doFullRange) + fillFullRangeDeltaRCosOA<1>(obs.qinv, obs.drOverCosOA); + fRegistry.fill(HIST("Pair/mix/hDeltaRCosOA"), obs.drOverCosOA); + if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) + continue; + if (doQA) + fillPairQAStep<1, 1>(obs, centForQA, occupancy); + if (!passRZCut(obs.deltaR, obs.deltaZ)) + continue; + if (doQA) + fillPairQAStep<1, 2>(obs, centForQA, occupancy); + if (isInsideEllipse(obs.deta, obs.dphi)) + continue; + if (doQA) + fillPairQAStep<1, 3>(obs, centForQA, occupancy); + if (doFullRange) + fillFullRangeQA<1>(obs, centForQA, occupancy); + fillPairHistogram<1>(collision, obs.v1, obs.v2, 1.f); + } + } + } + + if (ndiphoton > 0) { + emh1->AddCollisionIdAtLast(keyBin, keyDFCollision); + emh2->AddCollisionIdAtLast(keyBin, keyDFCollision); + mapMixedEventIdToGlobalBC[keyDFCollision] = collision.globalBC(); + } + } // end collision loop + } + + void processMC(FilteredMyCollisions const& collisions, + MyV0Photons const& v0photons, + MyMCV0Legs const& v0legs, + aod::EMMCParticles const& mcParticles, + aod::EMMCEvents const& /*mcEvents*/) + { + runPairingMC(collisions, v0photons, v0legs, mcParticles, + perCollisionPCM, fV0PhotonCut); + ndf++; + } + + PROCESS_SWITCH(photonhbt, processMC, "pairing with MC truth classification", false); +}; + +// ============================================================================ +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"photonhbt"})}; +} diff --git a/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx b/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx index b7141518624..996ce6abdda 100644 --- a/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx +++ b/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx @@ -17,6 +17,7 @@ #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" @@ -59,7 +60,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photonmeson::photonpair; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -389,8 +390,8 @@ struct prefilterPhoton { } auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto positrons_per_collision = posTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto electrons_per_collision = negTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto positrons_per_collision = posTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto electrons_per_collision = negTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); if (!fEMEventCut.IsSelected(collision) || !is_cent_ok) { for (const auto& photon1 : photons1_per_collision) { @@ -537,8 +538,8 @@ struct prefilterPhoton { } auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto positrons_per_collision = posTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); - auto electrons_per_collision = negTracks->sliceByCached(o2::aod::emprimaryelectronda::emphotoneventId, collision.globalIndex(), cache); + auto positrons_per_collision = posTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); + auto electrons_per_collision = negTracks->sliceByCached(o2::aod::emprimaryelectronda::pmeventId, collision.globalIndex(), cache); for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons1_per_collision))) { if (!cut1.template IsSelected(g1) || !cut1.template IsSelected(g2)) { @@ -600,8 +601,8 @@ struct prefilterPhoton { std::unordered_map map_pfb_ele; // map ele.globalIndex -> prefilter bit SliceCache cache; - Preslice perCollision_v0 = aod::v0photonkf::emphotoneventId; - Preslice perCollision_electron = aod::emprimaryelectronda::emphotoneventId; + Preslice perCollision_v0 = aod::v0photonkf::pmeventId; + Preslice perCollision_electron = aod::emprimaryelectronda::pmeventId; Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; diff --git a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx index 936e5ea335b..f7c5484084c 100644 --- a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx @@ -14,6 +14,7 @@ /// \author M. Hemmer, marvin.hemmer@cern.ch #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" @@ -118,7 +119,7 @@ struct TaskFlowReso { SliceCache cache; EventPlaneHelper epHelper; - using CollsWithQvecs = soa::Join; + using CollsWithQvecs = soa::Join; using CollWithQvec = CollsWithQvecs::iterator; static constexpr std::size_t NQVecEntries = 6; diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index 69c0dae38a8..ca6e5a02503 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -17,6 +17,7 @@ #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" @@ -257,14 +258,14 @@ struct TaskPi0FlowEMC { // using FilteredEMCalPhotons = soa::Filtered>; using EMCalPhotons = soa::Join; using PCMPhotons = soa::Join; - using FilteredCollsWithQvecs = soa::Filtered>; - using CollsWithQvecs = soa::Join; - using Colls = soa::Join; + using FilteredCollsWithQvecs = soa::Filtered>; + using CollsWithQvecs = soa::Join; + using Colls = soa::Join; static constexpr std::size_t NQVecEntries = 6; - PresliceOptional perCollisionEMC = o2::aod::emccluster::emphotoneventId; - PresliceOptional perCollisionPCM = aod::v0photonkf::emphotoneventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; diff --git a/PWGEM/PhotonMeson/Utils/EventHistograms.h b/PWGEM/PhotonMeson/Utils/EventHistograms.h index 5f2b6d91e6f..e45409dda9e 100644 --- a/PWGEM/PhotonMeson/Utils/EventHistograms.h +++ b/PWGEM/PhotonMeson/Utils/EventHistograms.h @@ -66,7 +66,7 @@ inline void addEventHistograms(o2::framework::HistogramRegistry* fRegistry) 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}, "centrality FT0C (%)"}; - fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::kTH1F, {{100, -50, +50}}, false); + fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::kTH1D, {{100, -50, +50}}, false); fRegistry->add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", o2::framework::kTH1F, {{6001, -0.5, 6000.5}}, false); fRegistry->add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", o2::framework::kTH1F, {{6001, -0.5, 6000.5}}, false); fRegistry->add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", o2::framework::kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, false); diff --git a/PWGEM/PhotonMeson/Utils/NMHistograms.h b/PWGEM/PhotonMeson/Utils/NMHistograms.h index 7911957bb03..03c3dcc3f89 100644 --- a/PWGEM/PhotonMeson/Utils/NMHistograms.h +++ b/PWGEM/PhotonMeson/Utils/NMHistograms.h @@ -60,8 +60,8 @@ inline void addNMHistograms(o2::framework::HistogramRegistry* fRegistry, bool is fRegistry->add("Pair/Eta/hs_FromSameGamma", "Two clusters from same gamma that is a eta daughter (conversion)", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); const o2::framework::AxisSpec axis_rapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; - fRegistry->add("Generated/Pi0/hPt", "pT;p_{T} (GeV/c)", o2::framework::kTH1F, {axis_pt}, true); - fRegistry->add("Generated/Pi0/hPtY", "Generated info", o2::framework::kTH2F, {axis_pt, axis_rapidity}, true); + fRegistry->add("Generated/Pi0/hPt", "pT;p_{T} (GeV/c)", o2::framework::kTH1D, {axis_pt}, true); + fRegistry->add("Generated/Pi0/hPtY", "Generated info", o2::framework::kTH2D, {axis_pt, axis_rapidity}, true); fRegistry->addClone("Generated/Pi0/", "Generated/Eta/"); fRegistry->get(HIST("Generated/Pi0/hPt"))->SetXTitle("p_{T} (GeV/c)"); diff --git a/PWGHF/Core/CentralityEstimation.h b/PWGHF/Core/CentralityEstimation.h index 71cdc0ebffd..33ee20266f4 100644 --- a/PWGHF/Core/CentralityEstimation.h +++ b/PWGHF/Core/CentralityEstimation.h @@ -30,6 +30,7 @@ enum CentralityEstimator { FT0M, FV0A, NTracksPV, + FT0CVariant2, NCentralityEstimators }; @@ -43,6 +44,11 @@ concept HasFT0CCent = requires(T collision) { collision.centFT0C(); }; +template +concept HasFT0CVariant2Cent = requires(T collision) { + collision.centFT0CVariant2(); +}; + template concept HasFT0MCent = requires(T collision) { collision.centFT0M(); @@ -76,6 +82,15 @@ float getCentralityColl(const TCollision& collision) return collision.centFT0C(); } +/// Evaluate centrality/multiplicity percentile using FT0C variant 1 estimator +/// \param candidate is candidate +/// \return centrality/multiplicity percentile of the collision +template +float getCentralityColl(const TCollision& collision) +{ + return collision.centFT0CVariant2(); +} + /// Evaluate centrality/multiplicity percentile using FT0M estimator /// \param candidate is candidate /// \return centrality/multiplicity percentile of the collision @@ -144,6 +159,18 @@ float getCentralityColl(const TCollision& collision, const int centEstimator) } LOG(fatal) << "Collision does not have centFV0A()."; break; + case CentralityEstimator::NTracksPV: + if constexpr (HasNTracksPvCent) { + return collision.centNTPV(); + } + LOG(fatal) << "Collision does not have centNTPV()."; + break; + case CentralityEstimator::FT0CVariant2: + if constexpr (HasFT0CVariant2Cent) { + return collision.centFT0CVariant2(); + } + LOG(fatal) << "Collision does not have centFT0CVariant2()."; + break; default: LOG(fatal) << "Centrality estimator not valid. See CentralityEstimator for valid values."; break; diff --git a/PWGHF/Core/DecayChannelsLegacy.h b/PWGHF/Core/DecayChannelsLegacy.h index 675417d975b..0f0f8892a75 100644 --- a/PWGHF/Core/DecayChannelsLegacy.h +++ b/PWGHF/Core/DecayChannelsLegacy.h @@ -26,7 +26,8 @@ enum DecayType { OmegaczeroToXiPi, OmegaczeroToOmegaPi, OmegaczeroToOmegaK, - OmegaczeroToOmegaPiOneMu + OmegaczeroToOmegaPiOneMu, + XiczeroToOmegaK }; } // namespace hf_cand_xic0_omegac0 diff --git a/PWGHF/Core/HfMlResponseLcToK0sP.h b/PWGHF/Core/HfMlResponseLcToK0sP.h index 4e6899bf3aa..1d90b015008 100644 --- a/PWGHF/Core/HfMlResponseLcToK0sP.h +++ b/PWGHF/Core/HfMlResponseLcToK0sP.h @@ -82,6 +82,7 @@ enum class InputFeaturesLcToK0sP : uint8_t { v0MK0Short, v0MGamma, ctV0, + decayLengthV0, dcaV0daughters, ptV0Pos, dcaPosToPV, @@ -136,6 +137,7 @@ class HfMlResponseLcToK0sP : public HfMlResponse CHECK_AND_FILL_VEC_LC_FULL(candidate, v0MGamma, mGamma); CHECK_AND_FILL_VEC_LC_HFHELPER(candidate, ctV0, ctV0K0s); // CHECK_AND_FILL_VEC_LC_HFHELPER(candidate, ctV0, ctV0Lambda); + CHECK_AND_FILL_VEC_LC(decayLengthV0); CHECK_AND_FILL_VEC_LC(dcaV0daughters); CHECK_AND_FILL_VEC_LC(ptV0Pos); CHECK_AND_FILL_VEC_LC_FULL(candidate, dcaPosToPV, dcapostopv); @@ -180,6 +182,7 @@ class HfMlResponseLcToK0sP : public HfMlResponse FILL_MAP_LC(v0MK0Short), FILL_MAP_LC(v0MGamma), FILL_MAP_LC(ctV0), + FILL_MAP_LC(decayLengthV0), FILL_MAP_LC(dcaV0daughters), FILL_MAP_LC(ptV0Pos), FILL_MAP_LC(dcaPosToPV), diff --git a/PWGHF/D2H/Core/DataCreationCharmReso.h b/PWGHF/D2H/Core/DataCreationCharmReso.h index 3914b37c283..fb44dce3b42 100644 --- a/PWGHF/D2H/Core/DataCreationCharmReso.h +++ b/PWGHF/D2H/Core/DataCreationCharmReso.h @@ -18,6 +18,13 @@ #ifndef PWGHF_D2H_CORE_DATACREATIONCHARMRESO_H_ #define PWGHF_D2H_CORE_DATACREATIONCHARMRESO_H_ +#ifndef HomogeneousField +#define HomogeneousField // needed for KFParticle::SetField(magneticField); +#endif + +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGEM/PhotonMeson/Utils/TrackSelection.h" #include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" @@ -25,7 +32,9 @@ #include "PWGHF/Utils/utilsMcMatching.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/TPCVDriftManager.h" #include "Common/Core/trackUtilities.h" +#include "Tools/KFparticle/KFUtilities.h" #include #include @@ -39,6 +48,10 @@ #include #include +#include +#include +#include + #include #include @@ -69,6 +82,7 @@ enum BachelorType : uint8_t { Lambda, AntiLambda, Track, + Gamma, NBachelorTypes }; @@ -83,6 +97,7 @@ enum PairingType : uint8_t { V0Only, TrackOnly, V0AndTrack, + GammaOnly, NPairingType }; @@ -110,6 +125,7 @@ struct HfResoCandidateV0 { float dcaV0ToPv = 1000.f; float dcaDau = 1000.f; float alpha = -1.f; + float qt = -1.f; float eta = -999.f; float radius = 0.f; float mK0Short = 0.f; @@ -123,6 +139,7 @@ struct HfResoVarContainer { float invMassD0 = 0.f; float invMassD0Bar = 0.f; float invMassReso = 0.f; + float invMassResoBar = 0.f; float ptReso = -1.f; int8_t signD = 0; std::array pVectorProng0 = {0.f, 0.f, 0.f}; @@ -150,6 +167,31 @@ struct HfResoConfigV0Cuts : o2::framework::ConfigurableGroup { o2::framework::Configurable propagateV0toPV{"propagateV0toPV", false, "Enable or disable V0 propagation to V0"}; }; +struct HfResoConfigGammaCuts : o2::framework::ConfigurableGroup { + std::string prefix = "gammas"; // JSON group name + o2::framework::Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; + o2::framework::Configurable ptMin{"ptMin", 0.1f, "minimum pT"}; + o2::framework::Configurable ptMaxItsOnly{"ptMaxItsOnly", 0.3f, "maximum pT for ITS-only gammas"}; + o2::framework::Configurable etaMaxDau{"etaMaxDau", 1.f, "maximum eta gamma daughters"}; + o2::framework::Configurable trackNclusItsCut{"trackNclusItsCut", 0, "Minimum number of ITS clusters for gamma daughter"}; + o2::framework::Configurable trackNCrossedRowsTpc{"trackNCrossedRowsTpc", 50, "Minimum TPC crossed rows"}; + o2::framework::Configurable trackNsharedClusTpc{"trackNsharedClusTpc", 1000, "Maximum number of shared TPC clusters for gamma daughter"}; + o2::framework::Configurable trackFracMaxindableTpcCls{"trackFracMaxindableTpcCls", 0.8f, "Maximum fraction of findable TPC clusters for gamma daughter"}; + o2::framework::Configurable dcaDauIts{"dcaDauIts", 0.5f, "maximum DCA gamma daughters (ITS)"}; + o2::framework::Configurable dcaDauItsIb{"dcaDauItsIb", 1.0f, "maximum DCA gamma daughters (ITS IB)"}; + o2::framework::Configurable dcaDauTpc{"dcaDauTpc", 0.5f, "maximum DCA gamma daughters (TPC)"}; + o2::framework::Configurable dcaDauTpcInner{"dcaDauTpcInner", 1.0f, "maximum DCA gamma daughters (TPC inner)"}; + o2::framework::Configurable dcaMaxDauToPv{"dcaMaxDauToPv", 0.1f, "Maximum gamma daughter's DCA to PV"}; + o2::framework::Configurable dcaPv{"dcaPv", 1.f, "DCA gamma to PV"}; + o2::framework::Configurable cosPa{"cosPa", 0.99f, "gamma CosPA"}; + o2::framework::Configurable radiusMin{"radiusMin", 1.0f, "Minimum gamma radius accepted"}; + o2::framework::Configurable radiusMax{"radiusMax", 90.f, "Maximum gamma radius accepted"}; + o2::framework::Configurable alphaApMax{"alphaApMax", 0.95f, "Maximum alpha AP"}; + o2::framework::Configurable qtApMax{"qtApMax", 0.01f, "Maximum qt AP"}; + o2::framework::Configurable nSigmaTpcEl{"nSigmaTpcEl", 4.f, "N sigma TPC for electrons"}; + o2::framework::Configurable propagateGammatoPV{"propagateGammatoPV", false, "Enable or disable V0 propagation to V0"}; +}; + struct HfResoConfigSingleTrackCuts : o2::framework::ConfigurableGroup { std::string prefix = "singleTracks"; // JSON group name o2::framework::Configurable setTrackSelections{"setTrackSelections", 2, "flag to apply track selections: 0=none; 1=global track w/o DCA selection; 2=global track; 3=only ITS quality"}; @@ -198,10 +240,16 @@ void addHistograms(o2::framework::HistogramRegistry& registry) const o2::framework::AxisSpec axisDeltaMassToPi{500, 0.13, 1.13, "inv. mass (GeV/#it{c}^{2})"}; const o2::framework::AxisSpec axisDeltaMassToPr{500, 0.93, 1.93, "inv. mass (GeV/#it{c}^{2})"}; const o2::framework::AxisSpec axisDeltaMassToLambda{500, 1.05, 2.05, "inv. mass (GeV/#it{c}^{2})"}; + const o2::framework::AxisSpec axisDeltaMassToGamma{500, 0., 0.25, "inv. mass (GeV/#it{c}^{2})"}; const o2::framework::AxisSpec axisMassDsj{400, 0.49f, 0.89f, ""}; // Ds1 and Ds2Star legacy + const o2::framework::AxisSpec axisAlpha{100, -1.f, 1.f}; + const o2::framework::AxisSpec axisQt{100, 0.f, 0.25f}; + const o2::framework::AxisSpec axisRadius{450, 0.f, 90.f}; registry.add("hMassVsPtK0s", "K0^{s} candidates;#it{p}_{T} (GeV/#it{c});inv. mass (#pi^{#plus}#pi^{#minus}) (GeV/#it{c}^{2});entries", {o2::framework::HistType::kTH2D, {axisPt, axisMassKzero}}); registry.add("hMassVsPtLambda", "Lambda candidates;#it{p}_{T} (GeV/#it{c});inv. mass (p #pi^{#minus}) (GeV/#it{c}^{2});entries", {o2::framework::HistType::kTH2D, {axisPt, axisMassLambda}}); + registry.add("hAP", "Aremnteros-Podolanski plot for V0 candidates;#it{#alpha};#it{q}_{T} (GeV/#it{c});entries", {o2::framework::HistType::kTH2D, {axisAlpha, axisQt}}); + registry.add("hV0Radius", "Radius of V0 candidates;#it{R} (cm);entries", {o2::framework::HistType::kTH1D, {axisRadius}}); registry.add("hdEdxVsP", "Tracks;#it{p} (GeV/#it{c});d#it{E}/d#it{x};entries", {o2::framework::HistType::kTH2D, {axisP, axisDeDx}}); if constexpr (DType == DMesonType::D0) { @@ -214,6 +262,7 @@ void addHistograms(o2::framework::HistogramRegistry& registry) registry.add("hMassD0K", "D0Kplus candidates; m_{D^{0}K^{+}} - m_{D^{0}} (GeV/#it{c}^{2});entries", {o2::framework::HistType::kTH2D, {axisPt, axisDeltaMassToK}}); registry.add("hMassD0Proton", "D0Proton candidates; m_{D^{0}p} - m_{D^{0}} (GeV/#it{c}^{2});entries", {o2::framework::HistType::kTH2D, {axisPt, axisDeltaMassToPr}}); registry.add("hMassD0Lambda", "D0Lambda candidates; m_{D^{0}#Lambda} - m_{D^{0}} (GeV/#it{c}^{2});entries", {o2::framework::HistType::kTH2D, {axisPt, axisDeltaMassToLambda}}); + registry.add("hMassD0Gamma", "D0Gamma candidates; m_{D^{0}#gamma} - m_{D^{0}} (GeV/#it{c}^{2});entries", {o2::framework::HistType::kTH2D, {axisPt, axisDeltaMassToGamma}}); } else if constexpr (DType == DMesonType::Dplus) { const o2::framework::AxisSpec axisMassDplus{200, 1.7f, 2.1f, "inv. mass (GeV/#it{c}^{2})"}; registry.add("hMassVsPtDplusAll", "Dplus candidates (all, regardless the pairing with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {o2::framework::HistType::kTH2D, {axisPt, axisMassDplus}}); @@ -292,6 +341,18 @@ float alphaAP(std::array const& momV0, std::array const& mom return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); } +/// Utility to compute qT +/// \param momDau0 is the momentum of first daughter +/// \param momDau1 is the momentum of second daughter +/// \return qtAP +//_______________________________________________________________________ +inline float qtAP(std::array const& momDau0, std::array const& momDau1) +{ + float momTot = RecoDecay::p2(momDau0[0] + momDau1[0], momDau0[1] + momDau1[1], momDau0[2] + momDau1[2]); + float dp = RecoDecay::dotProd(std::array{momDau1[0], momDau1[1], momDau1[2]}, std::array{momDau0[0] + momDau1[0], momDau0[1] + momDau1[1], momDau0[2] + momDau1[2]}); + return std::sqrt(RecoDecay::p2(momDau1[0], momDau1[1], momDau1[2]) - dp * dp / momTot); // qt of v0 +} + /// Utility to find DCA of V0 to Primary vertex /// \param x is the x-coordinate /// \param y is the y-coordinate @@ -397,6 +458,7 @@ bool buildAndSelectV0(const Coll& collision, const std::array& dDaughter v0.v0Type = {BIT(BachelorType::K0s) | BIT(BachelorType::Lambda) | BIT(BachelorType::AntiLambda)}; // for lambda hypotesys define if its lambda or anti-lambda v0.alpha = alphaAP(v0.mom, v0.momPos, v0.momNeg); + v0.qt = qtAP(v0.momPos, v0.momNeg); bool const matter = v0.alpha > 0; CLRBIT(v0.v0Type, matter ? BachelorType::AntiLambda : BachelorType::Lambda); auto massPos = matter ? o2::constants::physics::MassProton : o2::constants::physics::MassPionCharged; @@ -438,6 +500,195 @@ bool buildAndSelectV0(const Coll& collision, const std::array& dDaughter return true; } +/// Basic selection of V0 candidates +/// \param collision is the current collision +/// \param dauTracks are the v0 daughter tracks +/// \param dDaughtersIds are the IDs of the D meson daughter tracks +/// \param cfgV0Cuts are the cuts to be applied to the V0 +/// \param v0 is the V0 candidate +/// \param matCorr is the material correction type to be used in the track propagation +/// \param bz is the magnetic field +/// \param vDriftMgr is the TPC velocity drift manager +/// \param rejectPairsWithCommonDaughter is a flag to activate rejection of pairs sharing a daughter track +/// \return a bitmap with mass hypotesis if passes all cuts +template +bool buildAndSelectGamma(const Coll& collision, const std::array& dDaughtersIds, const std::array& dauTracks, const Cuts& cfgGammaCuts, HfResoCandidateV0& v0, o2::base::Propagator::MatCorrType const& matCorr, o2::aod::common::TPCVDriftManager* vDriftMgr, bool rejectPairsWithCommonDaughter) +{ + const auto& trackPos = dauTracks[0]; + const auto& trackNeg = dauTracks[1]; + if (trackPos.sign() * trackNeg.sign() > 0) { // reject same sign pair + return false; + } + if (trackPos.globalIndex() == trackNeg.globalIndex()) { + return false; + } + if (o2::pwgem::photonmeson::isITSonlyTrack(trackPos) && !trackNeg.hasITS()) { + return false; + } + if (o2::pwgem::photonmeson::isITSonlyTrack(trackNeg) && !trackPos.hasITS()) { + return false; + } + + // single-tracks selection + if (!selectV0Daughter(trackPos, dDaughtersIds, cfgGammaCuts, rejectPairsWithCommonDaughter) || !selectV0Daughter(trackNeg, dDaughtersIds, cfgGammaCuts, rejectPairsWithCommonDaughter)) { + return false; + } + if ((trackPos.hasTPC() && std::abs(trackPos.tpcNSigmaEl()) > cfgGammaCuts.nSigmaTpcEl.value) || (trackNeg.hasTPC() && std::abs(trackNeg.tpcNSigmaEl()) > cfgGammaCuts.nSigmaTpcEl.value)) { + return false; + } + + std::array dcaInfo; + auto trackParPos = getTrackParCov(trackPos); + if (o2::pwgem::photonmeson::isTPConlyTrack(trackPos) && !vDriftMgr->moveTPCTrack(collision, trackPos, trackParPos)) { + LOGP(error, "failed correction for positive tpc track"); + return false; + } + auto trackParPropPos = trackParPos; + trackParPropPos.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParPropPos, 2.f, matCorr, &dcaInfo); + auto trackPosDcaXY = dcaInfo[0]; + + auto trackParNeg = getTrackParCov(trackNeg); + if (o2::pwgem::photonmeson::isTPConlyTrack(trackNeg) && !vDriftMgr->moveTPCTrack(collision, trackNeg, trackParNeg)) { + LOGP(error, "failed correction for negative tpc track"); + return false; + } + auto trackParPropNeg = trackParNeg; + trackParPropNeg.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParPropNeg, 2.f, matCorr, &dcaInfo); + auto trackNegDcaXY = dcaInfo[0]; + + // daughters DCA to V0's collision primary vertex + if (std::fabs(trackPosDcaXY) < cfgGammaCuts.dcaMaxDauToPv.value || std::fabs(trackNegDcaXY) < cfgGammaCuts.dcaMaxDauToPv.value) { + return false; + } + + float gammaVtx[3] = {0.f, 0.f, 0.f}; + Vtx_recalculationParCov(o2::base::Propagator::Instance(), trackParPropPos, trackParPropNeg, gammaVtx, matCorr); + float radiusXy = std::hypot(gammaVtx[0], gammaVtx[1]); + const float maxX{83.1f}; // max X for track IU + const float marginTpc{7.f}; // margin for r cut in cm + if (radiusXy > maxX + marginTpc) { + return false; + } + if (radiusXy < std::fabs(gammaVtx[2]) * std::tan(2 * std::atan(std::exp(-cfgGammaCuts.etaMax.value))) - marginTpc) { + return false; // RZ line cut + } + + // vertex reconstruction + KFPTrack kfpTrackPos = createKFPTrackFromTrackParCov(trackParPropPos, trackPos.sign(), trackPos.tpcNClsFound(), trackPos.tpcChi2NCl()); + KFPTrack kfpTrackNeg = createKFPTrackFromTrackParCov(trackParPropNeg, trackNeg.sign(), trackNeg.tpcNClsFound(), trackNeg.tpcChi2NCl()); + KFParticle kfPartPos(kfpTrackPos, kPositron); + KFParticle kfPartNeg(kfpTrackNeg, kElectron); + const KFParticle* gammaDaughters[2] = {&kfPartPos, &kfPartNeg}; + + KFParticle gamma; + gamma.SetConstructMethod(2); + gamma.Construct(gammaDaughters, 2); + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle KFPV(kfpVertex); + + // Transport the gamma to the recalculated decay vertex + KFParticle gammaDecayVtx = gamma; // with respect to (0,0,0) + gammaDecayVtx.TransportToPoint(gammaVtx); + v0.cosPA = cpaFromKF(gammaDecayVtx, KFPV); + if (v0.cosPA < cfgGammaCuts.cosPa.value) { + return false; + } + + v0.pos = {gammaDecayVtx.GetX(), gammaDecayVtx.GetY(), gammaDecayVtx.GetZ()}; + v0.radius = std::hypot(gammaDecayVtx.GetX(), gammaDecayVtx.GetY()); + if (v0.radius > maxX + marginTpc) { + return false; + } + if (v0.radius < std::fabs(gammaDecayVtx.GetZ()) * std::tan(2 * std::atan(std::exp(-cfgGammaCuts.etaMax.value))) - marginTpc) { + return false; // RZ line cut + } + if (v0.radius < cfgGammaCuts.radiusMin.value || cfgGammaCuts.radiusMax.value < v0.radius) { + return false; + } + + const float minRadTpcOnly{16.f}; + if ((!trackNeg.hasITS() && !trackNeg.hasITS()) && v0.radius < minRadTpcOnly) { // TPConly tracks can detect conversion points larger than minRadTpcOnly. + return false; + } + + // Apply a topological constraint of the gamma to the PV. Parameters will be given at the primary vertex. + KFParticle gammaPvConstr = gamma; + gammaPvConstr.SetProductionVertex(KFPV); + v0.mom = RecoDecay::pVec(std::array{gammaPvConstr.GetPx(), gammaPvConstr.GetPy(), gammaPvConstr.GetPz()}); + v0.pT = std::hypot(v0.mom[0], v0.mom[1]); + if (v0.pT < cfgGammaCuts.ptMin.value) { + return false; + } + if (o2::pwgem::photonmeson::isITSonlyTrack(trackNeg) && o2::pwgem::photonmeson::isITSonlyTrack(trackPos) && v0.pT > cfgGammaCuts.ptMaxItsOnly.value) { + return false; + } + v0.eta = RecoDecay::eta(v0.mom); + if (std::abs(v0.eta) > cfgGammaCuts.etaMax.value) { + return false; + } + + KFParticle kfPartDecayVtxPos = kfPartPos; // Don't set Primary Vertex + KFParticle kfPartDecayVtxNeg = kfPartNeg; // Don't set Primary Vertex + kfPartDecayVtxPos.TransportToPoint(gammaVtx); // Don't set Primary Vertex + kfPartDecayVtxNeg.TransportToPoint(gammaVtx); // Don't set Primary Vertex + v0.dcaDau = kfPartDecayVtxPos.GetDistanceFromParticle(kfPartDecayVtxNeg); + v0.momPos = RecoDecay::pVec(std::array{kfPartDecayVtxPos.GetPx(), kfPartDecayVtxPos.GetPy(), kfPartDecayVtxPos.GetPz()}); + v0.momNeg = RecoDecay::pVec(std::array{kfPartDecayVtxNeg.GetPx(), kfPartDecayVtxNeg.GetPy(), kfPartDecayVtxNeg.GetPz()}); + float ptItsOnlyMax{0.15f}; + if (o2::pwgem::photonmeson::isITSonlyTrack(trackPos) && std::hypot(v0.momPos[0], v0.momPos[1]) > ptItsOnlyMax) { + return false; + } + if (o2::pwgem::photonmeson::isITSonlyTrack(trackNeg) && std::hypot(v0.momNeg[0], v0.momNeg[1]) > ptItsOnlyMax) { + return false; + } + + const float maxRItsMft{66.f}; + if (!trackNeg.hasITS() && !trackPos.hasITS()) { // V0s with TPConly-TPConly + if (maxRItsMft < v0.radius && v0.radius < maxX + marginTpc) { + if (v0.dcaDau > cfgGammaCuts.dcaDauTpcInner.value) { + return false; + } + } else { + if (v0.dcaDau > cfgGammaCuts.dcaDauTpc.value) { + return false; + } + } + } else { // V0s with ITS hits + if (v0.radius < minRadTpcOnly) { + if (v0.dcaDau > cfgGammaCuts.dcaDauItsIb.value) { + return false; + } + } else { + if (v0.dcaDau > cfgGammaCuts.dcaDauIts.value) { + return false; + } + } + } + + // v0 DCA to primary vertex + v0.dcaV0ToPv = calculateDCAStraightToPV( + v0.pos[0], v0.pos[1], v0.pos[2], + v0.momPos[0] + v0.momNeg[0], + v0.momPos[1] + v0.momNeg[1], + v0.momPos[2] + v0.momNeg[2], + collision.posX(), collision.posY(), collision.posZ()); + if (std::abs(v0.dcaV0ToPv) > cfgGammaCuts.dcaPv.value) { + return false; + } + + // distinguish V0 hypotheses + v0.alpha = alphaAP(v0.mom, v0.momPos, v0.momNeg); + v0.qt = qtAP(v0.momPos, v0.momNeg); + ; + if (!checkAP(v0.alpha, v0.qt, cfgGammaCuts.alphaApMax.value, cfgGammaCuts.qtApMax.value)) { // store only photon conversions + return false; + } + v0.v0Type = BIT(BachelorType::Gamma); + return true; +} + /// Basic selection of tracks /// \param track is the track /// \param dDaughtersIds are the IDs of the D meson daughter tracks @@ -945,6 +1196,7 @@ void fillMcRecoInfoDTrack(PParticles const& particlesMc, /// \param tracksIU is the trackIU table /// \param particlesMc is the MC particle table /// \param hfRejMap is the event rejection map from the HF event selection util +/// \param bz is the magnetic field /// \param pdg is the O2DatabasePDG service /// \param registry is the histogram registry /// \param matCorr is the material correction type to be used in the track propagation @@ -957,7 +1209,8 @@ void fillMcRecoInfoDTrack(PParticles const& particlesMc, /// \param rowMcRecV0Reduced is the MC reco D-V0 reduced table to be filled /// \param rowMcRecTrkReduced is the MC reco D-track reduced table to be filled /// \param rowCandDmesMlReduced is the ML reduced table to be filled -template +/// \param vDriftMgr is the TPC velocity drift manager object +template void runDataCreation(Coll const& collision, CCands const& candsD, BBachV0s const& bachelorV0s, @@ -974,6 +1227,7 @@ void runDataCreation(Coll const& collision, DmesCuts const& cfgDmesCuts, TrkCuts const& cfgSingleTrackCuts, V0Cuts const& cfgV0Cuts, + GammaCuts const& cfgGammaCuts, QaConfig const& cfgQaPlots, bool rejectPairsWithCommonDaughter, TableCollRed& rowCollisionReduced, @@ -982,16 +1236,19 @@ void runDataCreation(Coll const& collision, TableTrkRed& rowTrkReduced, TableMcRecV0Red& rowMcRecV0Reduced, TableMcRecTrkRed& rowMcRecTrkReduced, - TableCandDMlRed& rowCandDmesMlReduced) + TableCandDMlRed& rowCandDmesMlReduced, + o2::aod::common::TPCVDriftManager* vDriftMgr = nullptr) { int const indexHfReducedCollision = rowCollisionReduced.lastIndex() + 1; // std::map where the key is the V0.globalIndex() and // the value is the V0 index in the table of the selected v0s std::map selectedV0s; std::map selectedTracks; + std::map selectedGammas; bool fillHfReducedCollision = false; constexpr bool DoTracks = PairType == PairingType::TrackOnly || PairType == PairingType::V0AndTrack; constexpr bool DoV0s = PairType == PairingType::V0Only || PairType == PairingType::V0AndTrack; + constexpr bool DoGammas = PairType == PairingType::GammaOnly; // loop on D candidates for (const auto& candD : candsD) { // initialize variables depending on D meson type @@ -1131,6 +1388,8 @@ void runDataCreation(Coll const& collision, getPxPyPz(trackParK0, candV0.mom); } // compute resonance invariant mass and filling of QA histograms + registry.fill(HIST("hAP"), candV0.alpha, candV0.qt); + registry.fill(HIST("hV0Radius"), candV0.radius); if (TESTBIT(candV0.v0Type, BachelorType::K0s)) { registry.fill(HIST("hMassVsPtK0s"), candV0.pT, candV0.mK0Short); if constexpr (DType == DMesonType::Dstar) { @@ -1416,6 +1675,70 @@ void runDataCreation(Coll const& collision, } } // end of loop on bachelor tracks } // end of do tracks + if constexpr (DoGammas) { + for (const auto& gamma : bachelorV0s) { + auto trackPos = tracksIU.rawIteratorAt(gamma.posTrackId()); + auto trackNeg = tracksIU.rawIteratorAt(gamma.negTrackId()); + // Apply selsection + auto gammaDauTracks = std::array{trackPos, trackNeg}; + HfResoCandidateV0 candGamma; + if (!buildAndSelectGamma(collision, prongIdsD, gammaDauTracks, cfgGammaCuts, candGamma, matCorr, vDriftMgr, rejectPairsWithCommonDaughter)) { + continue; + } + // Get single track variables + float chi2TpcDauGammaMax = -1.f; + int nItsClsDauGammaMin = 8, nTpcCrossRowsDauGammaMin = 200; + for (const auto& gammaTrack : gammaDauTracks) { + if (gammaTrack.itsNCls() < nItsClsDauGammaMin) { + nItsClsDauGammaMin = gammaTrack.itsNCls(); + } + if (gammaTrack.tpcNClsCrossedRows() < nTpcCrossRowsDauGammaMin) { + nTpcCrossRowsDauGammaMin = gammaTrack.tpcNClsCrossedRows(); + } + if (gammaTrack.tpcChi2NCl() > chi2TpcDauGammaMax) { + chi2TpcDauGammaMax = gammaTrack.tpcChi2NCl(); + } + } + // propagate gamma to primary vertex (if enabled) + if (cfgGammaCuts.propagateGammatoPV.value) { + std::array const pVecGammaOrig = {candGamma.mom[0], candGamma.mom[1], candGamma.mom[2]}; + std::array dcaInfo{}; + auto trackParGamma = o2::track::TrackPar(candGamma.pos, pVecGammaOrig, 0, true); + trackParGamma.setPID(o2::track::PID::Photon); + trackParGamma.setAbsCharge(0); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParGamma, 2.f, matCorr, &dcaInfo); + getPxPyPz(trackParGamma, candGamma.mom); + } + registry.fill(HIST("hAP"), candGamma.alpha, candGamma.qt); + registry.fill(HIST("hV0Radius"), candGamma.radius); + if constexpr (DType == DMesonType::D0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, candGamma.mom}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassKPlus, o2::constants::physics::MassGamma}); + varUtils.invMassResoBar = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, candGamma.mom}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPionCharged, o2::constants::physics::MassGamma}); + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, candGamma.mom)); + if (!cfgQaPlots.applyCutsForQaHistograms.value || + ((varUtils.invMassD0 > cfgQaPlots.cutMassDMin.value && varUtils.invMassD0 < cfgQaPlots.cutMassDMax.value) || + (varUtils.invMassD0Bar > cfgQaPlots.cutMassDMin.value && varUtils.invMassD0Bar < cfgQaPlots.cutMassDMax.value))) { + registry.fill(HIST("hMassD0Gamma"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0); + registry.fill(HIST("hMassD0Gamma"), varUtils.ptReso, varUtils.invMassResoBar - varUtils.invMassD0Bar); + } + } + // fill V0 table --> use same for V0s and gammas + // if information on V0 already stored, go to next V0 + if (!selectedGammas.count(gamma.globalIndex())) { + rowCandV0Reduced(trackPos.globalIndex(), trackNeg.globalIndex(), + indexHfReducedCollision, + candGamma.pos[0], candGamma.pos[1], candGamma.pos[2], + candGamma.momPos[0], candGamma.momPos[1], candGamma.momPos[2], + candGamma.momNeg[0], candGamma.momNeg[1], candGamma.momNeg[2], + candGamma.cosPA, + candGamma.dcaV0ToPv, + nItsClsDauGammaMin, nTpcCrossRowsDauGammaMin, chi2TpcDauGammaMax, + candGamma.v0Type); + selectedGammas[gamma.globalIndex()] = rowCandV0Reduced.lastIndex(); + } + fillHfCandD = true; + } // end of loop on V0 candidates + } // end of do gammas // fill D candidate table if (fillHfCandD) { // fill candDplus table only once per D candidate, only if at least one V0 is found if constexpr (DType == DMesonType::Dplus) { diff --git a/PWGHF/D2H/DataModel/ReducedDataModel.h b/PWGHF/D2H/DataModel/ReducedDataModel.h index f3fcbc188d1..d70597c8678 100644 --- a/PWGHF/D2H/DataModel/ReducedDataModel.h +++ b/PWGHF/D2H/DataModel/ReducedDataModel.h @@ -846,6 +846,11 @@ DECLARE_SOA_TABLE(HfRedLbLcMls, "AOD", "HFREDLBLCML", //! Table with ML scores f using HfRedCandLb = soa::Join; +namespace hf_cand_mc_flag +{ +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); //! reconstruction level +} + namespace hf_b0_mc { // MC Rec @@ -873,9 +878,9 @@ DECLARE_SOA_COLUMN(PdgCodeProng3, pdgCodeProng3, int); //! Pdg code DECLARE_SOA_TABLE(HfMcRecRedDpPis, "AOD", "HFMCRECREDDPPI", //! Table with reconstructed MC information on DPi(<-B0) pairs for reduced workflow hf_cand_b0_reduced::Prong0Id, hf_cand_b0_reduced::Prong1Id, - hf_cand_b0::FlagMcMatchRec, - hf_cand_b0::FlagWrongCollision, - hf_cand_b0::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_b0_mc::PtMother); // try with extended table ? @@ -893,17 +898,17 @@ DECLARE_SOA_TABLE(HfMcCheckDpPis, "AOD", "HFMCCHECKDPPI", //! Table with reconst DECLARE_SOA_TABLE(HfMcRecRedDStarPis, "AOD", "HFMCRECREDDSTPI", //! Table with reconstructed MC information on DStarPi pairs for reduced workflow hf_cand_b0_reduced::ProngD0Id, hf_cand_b0_reduced::ProngBachPiId, - hf_cand_b0::FlagMcMatchRec, - hf_cand_b0::FlagWrongCollision, - hf_cand_b0::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_b0_mc::PtMother); // Table with same size as HFCANDB0 DECLARE_SOA_TABLE(HfMcRecRedB0s, "AOD", "HFMCRECREDB0", //! Reconstruction-level MC information on B0 candidates for reduced workflow - hf_cand_b0::FlagMcMatchRec, - hf_cand_b0::FlagMcDecayChanRec, - hf_cand_b0::FlagWrongCollision, - hf_cand_b0::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_b0_mc::PtMother); DECLARE_SOA_TABLE(HfMcCheckB0s, "AOD", "HFMCCHECKB0", //! Table with reconstructed MC information on B0 candidates for MC checks in reduced workflow @@ -916,8 +921,8 @@ DECLARE_SOA_TABLE(HfMcCheckB0s, "AOD", "HFMCCHECKB0", //! Table with reconstruct o2::soa::Marker<2>); DECLARE_SOA_TABLE(HfMcGenRedB0s, "AOD", "HFMCGENREDB0", //! Generation-level MC information on B0 candidates for reduced workflow - hf_cand_b0::FlagMcMatchGen, - hf_cand_b0::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanRec, hf_b0_mc::PtTrack, hf_b0_mc::YTrack, hf_b0_mc::EtaTrack, @@ -969,19 +974,19 @@ DECLARE_SOA_COLUMN(PdgCodeProng2, pdgCodeProng2, int); //! Pdg code DECLARE_SOA_TABLE(HfMcRecRedD0Pis, "AOD", "HFMCRECREDD0PI", //! Table with reconstructed MC information on D0Pi(<-B+) pairs for reduced workflow hf_cand_bplus_reduced::Prong0Id, hf_cand_bplus_reduced::Prong1Id, - hf_cand_bplus::FlagMcMatchRec, - hf_cand_bplus::FlagWrongCollision, - hf_cand_bplus::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_bplus_mc::PtMother); // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfMcRecRedJPKs, "AOD", "HFMCRECREDJPK", //! Table with reconstructed MC information on J/PsiK(<-B+) pairs for reduced workflow hf_cand_bplus_reduced::JpsiId, hf_cand_bplus_reduced::BachKaId, - hf_cand_bplus::FlagMcMatchRec, - hf_cand_bplus::FlagMcDecayChanRec, - hf_cand_bplus::FlagWrongCollision, - hf_cand_bplus::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_bplus_mc::PtMother); // DECLARE_SOA_EXTENDED_TABLE_USER(ExTable, Tracks, "EXTABLE", @@ -995,10 +1000,10 @@ DECLARE_SOA_TABLE(HfMcCheckD0Pis, "AOD", "HFMCCHECKD0PI", //! Table with reconst // Table with same size as HFCANDBPLUS DECLARE_SOA_TABLE(HfMcRecRedBps, "AOD", "HFMCRECREDBP", //! Reconstruction-level MC information on B+ candidates for reduced workflow - hf_cand_bplus::FlagMcMatchRec, - hf_cand_bplus::FlagMcDecayChanRec, - hf_cand_bplus::FlagWrongCollision, - hf_cand_bplus::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_bplus_mc::PtMother); DECLARE_SOA_TABLE(HfMcCheckBps, "AOD", "HFMCCHECKBP", //! Table with reconstructed MC information on B+ candidates for MC checks in reduced workflow @@ -1010,8 +1015,8 @@ DECLARE_SOA_TABLE(HfMcCheckBps, "AOD", "HFMCCHECKBP", //! Table with reconstruct o2::soa::Marker<2>); DECLARE_SOA_TABLE(HfMcGenRedBps, "AOD", "HFMCGENREDBP", //! Generation-level MC information on B+ candidates for reduced workflow - hf_cand_bplus::FlagMcMatchGen, - hf_cand_bplus::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanRec, hf_bplus_mc::PtTrack, hf_bplus_mc::YTrack, hf_bplus_mc::EtaTrack, @@ -1070,9 +1075,9 @@ DECLARE_SOA_COLUMN(PdgCodeProng3, pdgCodeProng3, int); //! Pdg code DECLARE_SOA_TABLE(HfMcRecRedDsPis, "AOD", "HFMCRECREDDSPI", //! Table with reconstructed MC information on DsPi(<-Bs) pairs for reduced workflow hf_cand_bs_reduced::Prong0Id, hf_cand_bs_reduced::Prong1Id, - hf_cand_bs::FlagMcMatchRec, - hf_cand_bs::FlagWrongCollision, - hf_cand_bs::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_bs_mc::PtMother); // table with results of reconstruction level MC matching @@ -1080,10 +1085,10 @@ DECLARE_SOA_TABLE(HfMcRecRedJPPhis, "AOD", "HFMCRECREDJPPHI", //! Table with rec hf_cand_bs_reduced::JpsiId, hf_cand_bs_reduced::Prong0PhiId, hf_cand_bs_reduced::Prong1PhiId, - hf_cand_bs::FlagMcMatchRec, - hf_cand_bs::FlagMcDecayChanRec, - hf_cand_bs::FlagWrongCollision, - hf_cand_bs::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_bs_mc::PtMother); // try with extended table ? @@ -1099,10 +1104,10 @@ DECLARE_SOA_TABLE(HfMcCheckDsPis, "AOD", "HFMCCHECKDSPI", //! Table with reconst // Table with same size as HFCANDBS DECLARE_SOA_TABLE(HfMcRecRedBss, "AOD", "HFMCRECREDBS", //! Reconstruction-level MC information on Bs candidates for reduced workflow - hf_cand_bs::FlagMcMatchRec, - hf_cand_bs::FlagMcDecayChanRec, - hf_cand_bs::FlagWrongCollision, - hf_cand_bs::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_bs_mc::PtMother); DECLARE_SOA_TABLE(HfMcCheckBss, "AOD", "HFMCCHECKBS", //! Table with reconstructed MC information on Bs candidates for MC checks in reduced workflow @@ -1115,8 +1120,8 @@ DECLARE_SOA_TABLE(HfMcCheckBss, "AOD", "HFMCCHECKBS", //! Table with reconstruct o2::soa::Marker<2>); DECLARE_SOA_TABLE(HfMcGenRedBss, "AOD", "HFMCGENREDBS", //! Generation-level MC information on Bs candidates for reduced workflow - hf_cand_bs::FlagMcMatchGen, - hf_cand_bs::FlagMcDecayChanRec, + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanRec, hf_bs_mc::PtTrack, hf_bs_mc::YTrack, hf_bs_mc::EtaTrack, @@ -1172,9 +1177,9 @@ DECLARE_SOA_COLUMN(PdgCodeProng3, pdgCodeProng3, int); //! Pdg code DECLARE_SOA_TABLE(HfMcRecRedLcPis, "AOD", "HFMCRECREDLCPI", //! Table with reconstructed MC information on LcPi(<-Lb) pairs for reduced workflow hf_cand_lb_reduced::Prong0Id, hf_cand_lb_reduced::Prong1Id, - hf_cand_lb::FlagMcMatchRec, - hf_cand_lb::FlagWrongCollision, - hf_cand_lb::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_lb_mc::PtMother); DECLARE_SOA_TABLE(HfMcCheckLcPis, "AOD", "HFMCCHECKLCPI", //! Table with reconstructed MC information on LcPi(<-Lb) pairs for MC checks in reduced workflow @@ -1188,9 +1193,9 @@ DECLARE_SOA_TABLE(HfMcCheckLcPis, "AOD", "HFMCCHECKLCPI", //! Table with reconst // Table with same size as HFCANDLc DECLARE_SOA_TABLE(HfMcRecRedLbs, "AOD", "HFMCRECREDLB", //! Reconstruction-level MC information on Lb candidates for reduced workflow - hf_cand_lb::FlagMcMatchRec, - hf_cand_lb::FlagWrongCollision, - hf_cand_lb::DebugMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagWrongCollision, + hf_cand_mc_flag::DebugMcRec, hf_lb_mc::PtMother); DECLARE_SOA_TABLE(HfMcCheckLbs, "AOD", "HFMCCHECKLB", //! Table with reconstructed MC information on Lb candidates for MC checks in reduced workflow @@ -1203,7 +1208,7 @@ DECLARE_SOA_TABLE(HfMcCheckLbs, "AOD", "HFMCCHECKLB", //! Table with reconstruct o2::soa::Marker<2>); DECLARE_SOA_TABLE(HfMcGenRedLbs, "AOD", "HFMCGENREDLB", //! Generation-level MC information on Lb candidates for reduced workflow - hf_cand_lb::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcMatchGen, hf_lb_mc::PtTrack, hf_lb_mc::YTrack, hf_lb_mc::EtaTrack, @@ -1553,7 +1558,7 @@ DECLARE_SOA_TABLE(Hf3PrV0McRec, "AOD", "HF3PRV0MCREC", hf_reso_cand_reduced::Origin, hf_reso_cand_reduced::PtGen, hf_reso_cand_reduced::InvMassGen, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker<1>); DECLARE_SOA_TABLE(HfDstarV0McRec, "AOD", "HFDSTARV0MCREC", @@ -1566,7 +1571,7 @@ DECLARE_SOA_TABLE(HfDstarV0McRec, "AOD", "HFDSTARV0MCREC", hf_reso_cand_reduced::Origin, hf_reso_cand_reduced::PtGen, hf_reso_cand_reduced::InvMassGen, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker<1>); DECLARE_SOA_TABLE(Hf2PrV0McRec, "AOD", "HF2PRV0MCREC", @@ -1579,7 +1584,7 @@ DECLARE_SOA_TABLE(Hf2PrV0McRec, "AOD", "HF2PRV0MCREC", hf_reso_cand_reduced::Origin, hf_reso_cand_reduced::PtGen, hf_reso_cand_reduced::InvMassGen, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker<1>); DECLARE_SOA_TABLE(Hf3PrTrkMcRec, "AOD", "HF3PRTRKMCREC", @@ -1592,7 +1597,7 @@ DECLARE_SOA_TABLE(Hf3PrTrkMcRec, "AOD", "HF3PRTRKMCREC", hf_reso_cand_reduced::Origin, hf_reso_cand_reduced::PtGen, hf_reso_cand_reduced::InvMassGen, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker<1>); DECLARE_SOA_TABLE(HfDstarTrkMcRec, "AOD", "HFDSTARTRKMCREC", @@ -1605,7 +1610,7 @@ DECLARE_SOA_TABLE(HfDstarTrkMcRec, "AOD", "HFDSTARTRKMCREC", hf_reso_cand_reduced::Origin, hf_reso_cand_reduced::PtGen, hf_reso_cand_reduced::InvMassGen, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker<1>); DECLARE_SOA_TABLE(Hf2PrTrkMcRec, "AOD", "HF2PRTRKMCREC", @@ -1618,11 +1623,11 @@ DECLARE_SOA_TABLE(Hf2PrTrkMcRec, "AOD", "HF2PRTRKMCREC", hf_reso_cand_reduced::Origin, hf_reso_cand_reduced::PtGen, hf_reso_cand_reduced::InvMassGen, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker<1>); DECLARE_SOA_TABLE(HfMcGenRedResos, "AOD", "HFMCGENREDRESO", //! Generation-level MC information on Ds-Resonances candidates for reduced workflow - hf_cand_b0::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcMatchGen, hf_reso_cand_reduced::Origin, hf_b0_mc::PtTrack, hf_b0_mc::YTrack, @@ -1646,7 +1651,7 @@ DECLARE_SOA_TABLE(HfMcRecRedResos, "AOD", "HFMCRECREDRESO", //! Reconstruction-l hf_reso_cand_reduced::Origin, hf_reso_cand_reduced::PtGen, hf_reso_cand_reduced::InvMassGen, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker<1>); } // namespace aod diff --git a/PWGHF/D2H/TableProducer/CMakeLists.txt b/PWGHF/D2H/TableProducer/CMakeLists.txt index 19a4a7ae123..7ad2570bec7 100644 --- a/PWGHF/D2H/TableProducer/CMakeLists.txt +++ b/PWGHF/D2H/TableProducer/CMakeLists.txt @@ -72,17 +72,17 @@ o2physics_add_dpl_workflow(data-creator-charm-had-pi-reduced o2physics_add_dpl_workflow(data-creator-charm-reso-to-dstar-reduced SOURCES dataCreatorCharmResoToDstarReduced.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils KFParticle::KFParticle COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(data-creator-charm-reso-to-dplus-reduced SOURCES dataCreatorCharmResoToDplusReduced.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils KFParticle::KFParticle COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(data-creator-charm-reso-to-d0-reduced SOURCES dataCreatorCharmResoToD0Reduced.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils KFParticle::KFParticle COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(data-creator-jpsi-had-reduced diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx index b825a362cad..6526044e6d2 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx @@ -24,6 +24,7 @@ #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "Common/Core/TPCVDriftManager.h" #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" @@ -86,6 +87,8 @@ struct HfDataCreatorCharmResoToD0Reduced { } cfgDmesCuts; // selection V0 HfResoConfigV0Cuts cfgV0Cuts; + // selection Gamma + HfResoConfigGammaCuts cfgGammaCuts; // selection single tracks HfResoConfigSingleTrackCuts cfgSingleTrackCuts; // QA histograms @@ -109,6 +112,7 @@ struct HfDataCreatorCharmResoToD0Reduced { // material correction for track propagation o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + o2::aod::common::TPCVDriftManager vDriftMgr; // O2DatabasePDG service Service pdg{}; @@ -125,6 +129,7 @@ struct HfDataCreatorCharmResoToD0Reduced { using TracksWithPID = soa::Join; using TracksWithPIDAndMC = soa::Join; using TracksIUWithPID = soa::Join; + using TracksIUWithElPID = soa::Join; using TracksIUWithPIDAndMC = soa::Join; // Collisions MC using BCsInfo = soa::Join; @@ -216,7 +221,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -251,7 +256,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -289,7 +294,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -326,13 +331,48 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD2PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0V0WithMl, "Process D0 candidates paired with V0s with ML info", false); + void processD0GammaWithMl(soa::Join const& collisions, + CandsD0FilteredWithMl const& candsD0, + aod::V0s const& v0s, + TracksIUWithElPID const& tracksIU, + aod::BCsWithTimestamps const&) + { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + int dummyTable{0}; + for (const auto& collision : collisions) { + const auto hfRejMap = o2::hf_evsel::getEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + if (rejectCollisionsWithBadEvSel && hfRejMap != 0) { + continue; + } + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, ccdbPathGrpMag, lut, false); + bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + } + fitter.setBz(bz); + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD2PrMl, &vDriftMgr); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0GammaWithMl, "Process D0 candidates paired with gammas with ML info", false); + void processD0TrackWithMl(soa::Join const& collisions, CandsD0FilteredWithMl const& candsD0, aod::TrackAssoc const& trackIndices, @@ -361,7 +401,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -399,7 +439,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -439,7 +479,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -478,7 +518,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -520,7 +560,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -560,7 +600,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, hfCandD2PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -599,7 +639,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -640,7 +680,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx index d0f90836449..71c1f6b49cc 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx @@ -215,7 +215,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -250,7 +250,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -288,7 +288,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -325,7 +325,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -360,7 +360,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -398,7 +398,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -437,7 +437,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -476,7 +476,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -518,7 +518,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -558,7 +558,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -597,7 +597,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -638,7 +638,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx index 6a3829ec1b6..d8939b6a765 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx @@ -215,7 +215,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -251,7 +251,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -289,7 +289,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -326,7 +326,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -361,7 +361,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -399,7 +399,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -439,7 +439,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -478,7 +478,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -520,7 +520,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -560,7 +560,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -599,7 +599,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -640,7 +640,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions diff --git a/PWGHF/D2H/Tasks/taskB0Reduced.cxx b/PWGHF/D2H/Tasks/taskB0Reduced.cxx index 5e146308c45..16634591c5f 100644 --- a/PWGHF/D2H/Tasks/taskB0Reduced.cxx +++ b/PWGHF/D2H/Tasks/taskB0Reduced.cxx @@ -152,13 +152,13 @@ DECLARE_SOA_TABLE(HfRedCandB0Lites, "AOD", "HFREDCANDB0LITE", //! Table with som hf_cand_b0_lite::NSigTofPiBachelor, hf_cand_b0_lite::NSigTpcTofPiBachelor, // MC truth - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_b0_lite::FlagWrongCollision, hf_cand_b0_lite::PtGen); DECLARE_SOA_TABLE(HfRedB0McCheck, "AOD", "HFREDB0MCCHECK", //! Table with MC decay type check - hf_cand_3prong::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcMatchRec, hf_cand_b0_lite::FlagWrongCollision, hf_cand_b0_lite::MD, hf_cand_b0_lite::PtD, diff --git a/PWGHF/D2H/Tasks/taskBplusReduced.cxx b/PWGHF/D2H/Tasks/taskBplusReduced.cxx index bca08dbf154..5913760dcea 100644 --- a/PWGHF/D2H/Tasks/taskBplusReduced.cxx +++ b/PWGHF/D2H/Tasks/taskBplusReduced.cxx @@ -149,13 +149,13 @@ DECLARE_SOA_TABLE(HfRedCandBpLites, "AOD", "HFREDCANDBPLITE", //! Table with som hf_cand_bplus_lite::NSigTofPiBachelor, hf_cand_bplus_lite::NSigTpcTofPiBachelor, // MC truth - hf_cand_2prong::FlagMcMatchRec, - hf_cand_2prong::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_bplus_lite::FlagWrongCollision, hf_cand_bplus_lite::PtGen); DECLARE_SOA_TABLE(HfRedBpMcCheck, "AOD", "HFREDBPMCCHECK", //! Table with MC decay type check - hf_cand_2prong::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcMatchRec, hf_cand_bplus_lite::FlagWrongCollision, hf_cand_bplus_lite::MD, hf_cand_bplus_lite::PtD, diff --git a/PWGHF/D2H/Tasks/taskBplusToJpsiKReduced.cxx b/PWGHF/D2H/Tasks/taskBplusToJpsiKReduced.cxx index aa0ff931938..31fae6a389d 100644 --- a/PWGHF/D2H/Tasks/taskBplusToJpsiKReduced.cxx +++ b/PWGHF/D2H/Tasks/taskBplusToJpsiKReduced.cxx @@ -164,14 +164,14 @@ DECLARE_SOA_TABLE(HfRedCandBpLites, "AOD", "HFREDCANDBPLITE", //! Table with som hf_cand_bplustojpsik_lite::NSigTofKaBachelor, hf_cand_bplustojpsik_lite::NSigTpcTofKaBachelor, // MC truth - hf_cand_bplus::FlagMcMatchRec, - hf_cand_bplus::FlagMcDecayChanRec, - hf_cand_bplus::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_bplustojpsik_lite::FlagWrongCollision, hf_cand_bplustojpsik_lite::PtGen); // DECLARE_SOA_TABLE(HfRedBpMcCheck, "AOD", "HFREDBPMCCHECK", //! Table with MC decay type check -// hf_cand_2prong::FlagMcMatchRec, +// hf_cand_mc_flag::FlagMcMatchRec, // hf_cand_bplustojpsik_lite::FlagWrongCollision, // hf_cand_bplustojpsik_lite::MJpsi, // hf_cand_bplustojpsik_lite::PtJpsi, diff --git a/PWGHF/D2H/Tasks/taskBsReduced.cxx b/PWGHF/D2H/Tasks/taskBsReduced.cxx index 93b4485228a..703a527ffac 100644 --- a/PWGHF/D2H/Tasks/taskBsReduced.cxx +++ b/PWGHF/D2H/Tasks/taskBsReduced.cxx @@ -155,13 +155,13 @@ DECLARE_SOA_TABLE(HfRedCandBsLites, "AOD", "HFREDCANDBSLITE", //! Table with som hf_cand_bs_lite::NSigTofPiProng1, hf_cand_bs_lite::NSigTpcTofPiProng1, // MC truth - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_bs_lite::FlagWrongCollision, hf_cand_bs_lite::PtGen); DECLARE_SOA_TABLE(HfRedBsMcCheck, "AOD", "HFREDBSMCCHECK", //! Table with MC decay type check - hf_cand_3prong::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcMatchRec, hf_cand_bs_lite::FlagWrongCollision, hf_cand_bs_lite::MProng0, hf_cand_bs_lite::PtProng0, diff --git a/PWGHF/D2H/Tasks/taskBsToJpsiPhiReduced.cxx b/PWGHF/D2H/Tasks/taskBsToJpsiPhiReduced.cxx index 2ff8dbe84e2..ab44c6f7dbe 100644 --- a/PWGHF/D2H/Tasks/taskBsToJpsiPhiReduced.cxx +++ b/PWGHF/D2H/Tasks/taskBsToJpsiPhiReduced.cxx @@ -189,14 +189,14 @@ DECLARE_SOA_TABLE(HfRedCandBsLites, "AOD", "HFREDCANDBSLITE", //! Table with som hf_cand_bstojpsiphi_lite::NSigTofKaBachelor1, hf_cand_bstojpsiphi_lite::NSigTpcTofKaBachelor1, // MC truth - hf_cand_bs::FlagMcMatchRec, - hf_cand_bs::FlagMcDecayChanRec, - hf_cand_bs::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_bstojpsiphi_lite::FlagWrongCollision, hf_cand_bstojpsiphi_lite::PtGen); // DECLARE_SOA_TABLE(HfRedBsMcCheck, "AOD", "HFREDBPMCCHECK", //! Table with MC decay type check -// hf_cand_2prong::FlagMcMatchRec, +// hf_cand_mc_flag::FlagMcMatchRec, // hf_cand_bstojpsiphi_lite::FlagWrongCollision, // hf_cand_bstojpsiphi_lite::MJpsi, // hf_cand_bstojpsiphi_lite::PtJpsi, diff --git a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx index 4d02b0068a1..dcc88fbb5d9 100644 --- a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx +++ b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx @@ -602,6 +602,10 @@ struct HfTaskCharmPolarisation { hRecoPromptRandomAxes.insert(hRecoPromptRandomAxes.end(), {thnAxisDauToMuons}); std::vector hRecoNonPromptRandomAxes(hRandomaxes); hRecoNonPromptRandomAxes.insert(hRecoNonPromptRandomAxes.end(), {thnAxisDauToMuons, thnAxisPtB}); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + hRecoPromptRandomAxes.push_back(thnAxisCentrality); + hRecoNonPromptRandomAxes.push_back(thnAxisCentrality); + } registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptRandomAxes); registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptRandomAxes); if (activatePartRecoDstar) { @@ -633,8 +637,12 @@ struct HfTaskCharmPolarisation { registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores", HistType::kTHnSparseF, hRandomaxes); } if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { - std::vector const hgenPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; - std::vector const hgenNonPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + std::vector hgenPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + std::vector hgenNonPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + hgenPromptAxes.push_back(thnAxisCentrality); + hgenNonPromptAxes.push_back(thnAxisCentrality); + } registry.add("hGenPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); registry.add("hGenNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); if (activatePartRecoDstar) { @@ -659,6 +667,7 @@ struct HfTaskCharmPolarisation { if (nBkgRotations > 0) { hEPaxes.push_back(thnAxisIsRotatedCandidate); } + hEPaxes.push_back(thnAxisCentrality); registry.add("hEP", "THn for polarisation studies with cosThStar w.r.t. event plane axis and BDT scores", HistType::kTHnSparseF, hEPaxes); } } @@ -738,7 +747,7 @@ struct HfTaskCharmPolarisation { /// \param nMuons is the number of muons from daughter decays /// \param isPartRecoDstar is a flag indicating if it is a partly reconstructed Dstar meson (MC only) template - void fillRecoHistos(float invMassCharmHad, float ptCharmHad, int numPvContributors, float rapCharmHad, float invMassD0, float invMassKPiLc, float cosThetaStar, float phiEuler, std::array outputMl, int isRotatedCandidate, int8_t origin, float ptBhadMother, int8_t resoChannelLc, float absEtaMin, int numItsClsMin, int numTpcClsMin, int8_t charge, int8_t nMuons, bool isPartRecoDstar) + void fillRecoHistos(float invMassCharmHad, float ptCharmHad, int numPvContributors, float rapCharmHad, float invMassD0, float invMassKPiLc, float cosThetaStar, float phiEuler, std::array outputMl, int isRotatedCandidate, int8_t origin, float ptBhadMother, int8_t resoChannelLc, float absEtaMin, int numItsClsMin, int numTpcClsMin, int8_t charge, int8_t nMuons, bool isPartRecoDstar, float centrality = -999.f) { if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Helicity) { // Helicity if constexpr (!DoMc) { // data @@ -791,19 +800,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } else { - registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } else { - registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); } @@ -812,19 +821,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecNonPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); } @@ -835,19 +844,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } else { - registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons); } else { - registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); } @@ -856,19 +865,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons, ptBhadMother); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecNonPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); } @@ -927,19 +936,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } else { - registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } else { - registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); } @@ -948,19 +957,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecNonPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); } @@ -971,19 +980,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } else { - registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons); } else { - registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); } @@ -992,19 +1001,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons, ptBhadMother); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecNonPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); } @@ -1063,19 +1072,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } else { - registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } else { - registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); } @@ -1084,19 +1093,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecNonPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); } @@ -1107,19 +1116,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } else { - registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons); } else { - registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); } @@ -1128,19 +1137,19 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, nMuons, ptBhadMother); } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); if (activateTHnEulerPhiMonitor) { registry.fill(HIST("hRecNonPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); } @@ -1193,59 +1202,107 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, centrality); + } else { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else { - registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, centrality); + } else { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, centrality); + } else { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } } else { - registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, centrality); + } else { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } else { // non-prompt if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother, centrality); + } else { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else { - registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother, centrality); + } else { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother, centrality); + } else { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } } else { - registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother, centrality); + } else { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } } else { // without ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, centrality); + } else { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else { - registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, centrality); + } else { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } else { // non-prompt if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother, centrality); + } else { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else { - registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother, centrality); + } else { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } } @@ -1256,15 +1313,15 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (nBkgRotations > 0) { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, centrality); } else { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, centrality); } } else { if (nBkgRotations > 0) { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate, centrality); } else { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], centrality); } } } @@ -1272,15 +1329,15 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (nBkgRotations > 0) { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, centrality); } else { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, centrality); } } else { if (nBkgRotations > 0) { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, isRotatedCandidate, centrality); } else { - registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar); + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, centrality); } } } @@ -1291,15 +1348,15 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } else { - registry.fill(HIST("hPartRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + registry.fill(HIST("hPartRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } else { - registry.fill(HIST("hPartRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + registry.fill(HIST("hPartRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); } } } @@ -1307,15 +1364,15 @@ struct HfTaskCharmPolarisation { if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ if (activateTrackingSys) { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); } } else { if (!isPartRecoDstar) { - registry.fill(HIST("hRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } else { - registry.fill(HIST("hPartRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + registry.fill(HIST("hPartRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); } } } @@ -1335,76 +1392,78 @@ struct HfTaskCharmPolarisation { /// \param resoChannelLc indicates the Lc decay channel (direct, resonant) /// \param isPartRecoDstar is a flag indicating if it is a partly reconstructed Dstar->D0pi->Kpipipi0 meson (MC only) template - void fillGenHistos(float ptCharmHad, int numPvContributors, float rapCharmHad, float cosThetaStar, int8_t origin, float ptBhadMother, bool areDausInAcc, uint8_t resoChannelLc, int8_t charge, bool isPartRecoDstar) + void fillGenHistos(float ptCharmHad, int numPvContributors, float rapCharmHad, float cosThetaStar, int8_t origin, float ptBhadMother, bool areDausInAcc, uint8_t resoChannelLc, int8_t charge, bool isPartRecoDstar, float centrality = -999.f) { if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Helicity) { // Helicity if (origin == RecoDecay::OriginType::Prompt) { // prompt if (!isPartRecoDstar) { - registry.fill(HIST("hGenPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPromptHelicity"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); } else { - registry.fill(HIST("hGenPartRecoPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPartRecoPromptHelicity"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); } } else { // non-prompt if (!isPartRecoDstar) { - registry.fill(HIST("hGenNonPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenNonPromptHelicity"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); } else { - registry.fill(HIST("hGenPartRecoNonPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPartRecoNonPromptHelicity"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); } } } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Production) { // Production if (origin == RecoDecay::OriginType::Prompt) { // prompt if (!isPartRecoDstar) { - registry.fill(HIST("hGenPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPromptProduction"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); } else { - registry.fill(HIST("hGenPartRecoPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPartRecoPromptProduction"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); } } else { // non-prompt if (!isPartRecoDstar) { - registry.fill(HIST("hGenNonPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenNonPromptProduction"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); } else { - registry.fill(HIST("hGenPartRecoNonPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPartRecoNonPromptProduction"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); } } } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Beam) { // Beam if (origin == RecoDecay::OriginType::Prompt) { // prompt if (!isPartRecoDstar) { - registry.fill(HIST("hGenPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPromptBeam"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); } else { - registry.fill(HIST("hGenPartRecoPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPartRecoPromptBeam"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); } } else { // non-prompt if (!isPartRecoDstar) { - registry.fill(HIST("hGenNonPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenNonPromptBeam"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); } else { - registry.fill(HIST("hGenPartRecoNonPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + registry.fill(HIST("hGenPartRecoNonPromptBeam"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); } } } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Random) { // Random - if (origin == RecoDecay::OriginType::Prompt) { // prompt - if (!isPartRecoDstar) { - registry.fill(HIST("hGenPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); - } else { - registry.fill(HIST("hGenPartRecoPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); - } - } else { // non-prompt + if (origin == RecoDecay::OriginType::Prompt) { if (!isPartRecoDstar) { - registry.fill(HIST("hGenNonPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); - } else { - registry.fill(HIST("hGenPartRecoNonPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); - } - } - } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::EP) { // EP - if (origin == RecoDecay::OriginType::Prompt) { // prompt - if (!isPartRecoDstar) { - registry.fill(HIST("hGenPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hGenPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge, centrality); + } else { + registry.fill(HIST("hGenPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); + } } else { - registry.fill(HIST("hGenPartRecoPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hGenPartRecoPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge, centrality); + } else { + registry.fill(HIST("hGenPartRecoPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, areDausInAcc, resoChannelLc, charge); + } } } else { // non-prompt if (!isPartRecoDstar) { - registry.fill(HIST("hGenNonPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hGenNonPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge, centrality); + } else { + registry.fill(HIST("hGenNonPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } } else { - registry.fill(HIST("hGenPartRecoNonPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.fill(HIST("hGenPartRecoNonPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge, centrality); + } else { + registry.fill(HIST("hGenPartRecoNonPromptRandom"), ptCharmHad, numPvContributors, std::abs(rapCharmHad), cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } } } } @@ -1518,10 +1577,11 @@ struct HfTaskCharmPolarisation { /// \param tracks are the reconstructed tracks /// \return true if candidate in signal region template - bool runPolarisationAnalysis(Cand const& candidate, int bkgRotationId, int numPvContributors, Part const& particles, Trk const& /*tracks*/, QVecs const* qVecs = nullptr) + bool runPolarisationAnalysis(Cand const& candidate, int bkgRotationId, int numPvContributors, Part const& particles, Trk const& /*tracks*/, float centrality = -999.f, QVecs const* qVecs = nullptr) { if constexpr (WithEp) { assert(qVecs && "EP analysis requested but qVecs == nullptr"); + assert(centrality && "EP analysis requested but centrality == nullptr"); } constexpr std::size_t NScores{3u}; @@ -1845,7 +1905,7 @@ struct HfTaskCharmPolarisation { if (activateTHnSparseCosThStarEP) { // EP float cosThetaStarEP = qVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(qVecNorm.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarEP, phiEP, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarEP, phiEP, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar, centrality); } } @@ -1871,7 +1931,11 @@ struct HfTaskCharmPolarisation { // random ROOT::Math::XYZVector const randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarRandom, -99.f, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); + if (doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarRandom, -99.f, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar, centrality); + } else { + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarRandom, -99.f, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); + } } /// Table for Lc->pKpi background studies @@ -2184,7 +2248,11 @@ struct HfTaskCharmPolarisation { if (activateTHnSparseCosThStarRandom) { ROOT::Math::XYZVector const randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); float const cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarRandom, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar); + if constexpr (WithCent) { + fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarRandom, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar, *centrality); + } else { + fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarRandom, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar); + } } } @@ -2330,7 +2398,7 @@ struct HfTaskCharmPolarisation { for (const auto& dstarCandidate : groupedDstarCandidates) { nCands++; - if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, &qVecs)) { + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, centrality, &qVecs)) { nCandsInSignalRegion++; } } @@ -2359,7 +2427,7 @@ struct HfTaskCharmPolarisation { for (const auto& dstarCandidate : groupedDstarCandidates) { nCands++; - if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, &qVecs)) { + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, centrality, &qVecs)) { nCandsInSignalRegion++; } } @@ -2394,7 +2462,7 @@ struct HfTaskCharmPolarisation { for (const auto& dstarCandidate : groupedDstarCandidates) { nCands++; - if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, centrality)) { nCandsInSignalRegion++; } } @@ -2434,7 +2502,7 @@ struct HfTaskCharmPolarisation { for (const auto& dstarCandidate : groupedDstarCandidates) { nCands++; - if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, centrality)) { nCandsInSignalRegion++; } } diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 9f4cdd4e01f..64d228b45d7 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -369,6 +369,7 @@ struct HfTaskD0 { axes.push_back(thnAxisFDDC); axes.push_back(thnAxisZNA); axes.push_back(thnAxisZNC); + axes.push_back(thnAxisNumPvContr); } if (applyMl) { @@ -382,6 +383,8 @@ struct HfTaskD0 { registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap type;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); + registry.add("Data/hGapVsEta", "UPC gap vs Eta;Gap type;Eta", {HistType::kTH2F, {{7, -1.5, 5.5}, {50, -1., 1.}}}); + registry.add("Data/hGapVsRap", "UPC gap vs Eta;Gap type;Eta", {HistType::kTH2F, {{7, -1.5, 5.5}, {50, -1., 1.}}}); hfEvSel.addHistograms(registry); @@ -589,6 +592,7 @@ struct HfTaskD0 { // Determine gap type using SGSelector with BC range checking const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); const int gap = gapResult.value; + const auto numPvContributors = collision.numContrib(); // Use the BC with FIT activity if available from SGSelector auto bcForUPC = bc; @@ -633,6 +637,8 @@ struct HfTaskD0 { const float massD0 = HfHelper::invMassD0ToPiK(candidate); const float massD0bar = HfHelper::invMassD0barToKPi(candidate); const auto ptCandidate = candidate.pt(); + registry.fill(HIST("Data/hGapVsEta"), gap, candidate.eta()); + registry.fill(HIST("Data/hGapVsRap"), gap, HfHelper::yD0(candidate)); if (candidate.isSelD0() >= selectionFlagD0) { registry.fill(HIST("hMass"), massD0, ptCandidate); @@ -648,7 +654,7 @@ struct HfTaskD0 { // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC] auto fillTHnData = [&](float mass, int d0Type) { // Pre-calculate vector size to avoid reallocations - constexpr int NAxesBase = 12; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC + constexpr int NAxesBase = 13; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC, nPVcontr constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR @@ -682,6 +688,7 @@ struct HfTaskD0 { valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); valuesToFill.push_back(static_cast(zdcEnergyZNA)); valuesToFill.push_back(static_cast(zdcEnergyZNC)); + valuesToFill.push_back(static_cast(numPvContributors)); if constexpr (FillMl) { registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 819c5f3891f..fb4102b48a1 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -114,12 +114,12 @@ struct HfTaskDplus { Partition selectedDPlusCandidatesWithMl = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; // Matched MC - Partition recoDPlusCandidates = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - Partition recoDPlusCandidatesWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Partition recoDPlusCandidates = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Partition recoDPlusCandidatesWithMl = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; // MC Bkg - Partition recoBkgCandidates = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - Partition recoBkgCandidatesWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Partition recoBkgCandidates = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Partition recoBkgCandidatesWithMl = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {600, 1.67, 2.27}, "Cand. mass bins"}; ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {40, -1, 1}, "Cand. rapidity bins"}; diff --git a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx index 46d7da749fc..78462e10a73 100644 --- a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx +++ b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx @@ -109,7 +109,7 @@ struct HfTaskFlowCharmHadrons { Configurable harmonic{"harmonic", 2, "harmonic number"}; Configurable qVecDetector{"qVecDetector", 3, "Detector for Q vector estimation (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3, TPC Pos: 4, TPC Neg: 5, TPC Tot: 6)"}; - Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3, FV0A: 4)"}; + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3, FV0A: 4, NTracksPV: 5, FT0CVariant2: 6)"}; Configurable selectionFlag{"selectionFlag", 1, "Selection Flag for hadron (e.g. 1 for skimming, 3 for topo. and kine., 7 for PID)"}; Configurable centralityMin{"centralityMin", 0., "Minimum centrality accepted in SP/EP computation (not applied in resolution process)"}; Configurable centralityMax{"centralityMax", 100., "Maximum centrality accepted in SP/EP computation (not applied in resolution process)"}; @@ -124,6 +124,8 @@ struct HfTaskFlowCharmHadrons { Configurable storeEpCosSin{"storeEpCosSin", false, "Flag to store cos and sin of EP angle in ThnSparse"}; Configurable storeCandEta{"storeCandEta", false, "Flag to store candidates eta"}; Configurable storeCandSign{"storeCandSign", false, "Flag to store candidates sign"}; + Configurable storeCentSparse{"storeCentSparse", false, "Flag to store up to 4 centrality estimators comparison sparse (only applied in resolution process)"}; + Configurable> centEstimatorsForSparse{"centEstimatorsForSparse", {1, 2, 3, 4}, "Centrality estimators to be stored in the centrality sparse (FT0A: 1, FT0C: 2, FT0M: 3, FV0A: 4). Up to 4 estimators can be configured."}; Configurable occEstimator{"occEstimator", 0, "Occupancy estimation (0: None, 1: ITS, 2: FT0C)"}; Configurable saveEpResoHisto{"saveEpResoHisto", false, "Flag to save event plane resolution histogram"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -146,7 +148,7 @@ struct HfTaskFlowCharmHadrons { using CandXic0DataWMl = soa::Filtered>; using CandD0DataWMl = soa::Filtered>; using CandD0Data = soa::Filtered>; - using CollsWithQvecs = soa::Join; + using CollsWithQvecs = soa::Join; using TracksWithExtra = soa::Join; Filter filterSelectDsCandidates = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; @@ -254,6 +256,11 @@ struct HfTaskFlowCharmHadrons { registry.add("hCentEventWithCand", "Centrality distributions with charm candidates;Cent;entries", HistType::kTH1F, {{100, 0.f, 100.f}}); registry.add("hCentEventWithCandInSigRegion", "Centrality distributions with charm candidates in signal range;Cent;entries", HistType::kTH1F, {{100, 0.f, 100.f}}); + if (storeCentSparse) { + std::vector axesCent = {thnAxisCent, thnAxisCent, thnAxisCent, thnAxisCent}; + registry.add("hSparseCentEstimators", "THn with different centrality estimators; Centrality 0; Centrality 1; Centrality 2; Centrality 3", {HistType::kTHnSparseF, axesCent}); + } + if (occEstimator != 0) { registry.add("trackOccVsFT0COcc", "trackOccVsFT0COcc; trackOcc; FT0COcc", {HistType::kTH2F, {thnAxisOccupancyITS, thnAxisOccupancyFT0C}}); } @@ -878,7 +885,7 @@ struct HfTaskFlowCharmHadrons { float const xQVecBTot = collision.qvecBTotRe(); float const yQVecBTot = collision.qvecBTotIm(); - centrality = o2::hf_centrality::getCentralityColl(collision, o2::hf_centrality::CentralityEstimator::FT0C); + centrality = o2::hf_centrality::getCentralityColl(collision, centEstimator); if (storeResoOccu) { const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); registry.fill(HIST("trackOccVsFT0COcc"), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); @@ -890,6 +897,11 @@ struct HfTaskFlowCharmHadrons { occupancy, evtSelFlags[0], evtSelFlags[1], evtSelFlags[2], evtSelFlags[3], evtSelFlags[4]); } + if (storeCentSparse) { + registry.fill(HIST("hSparseCentEstimators"), o2::hf_centrality::getCentralityColl(collision, centEstimatorsForSparse->at(0)), o2::hf_centrality::getCentralityColl(collision, centEstimatorsForSparse->at(1)), + o2::hf_centrality::getCentralityColl(collision, centEstimatorsForSparse->at(2)), o2::hf_centrality::getCentralityColl(collision, centEstimatorsForSparse->at(3))); + } + if (!isCollSelected(collision, bcs, centrality)) { // no selection on the centrality is applied, but on event selection flags return; diff --git a/PWGHF/D2H/Tasks/taskLbReduced.cxx b/PWGHF/D2H/Tasks/taskLbReduced.cxx index b8ba64cb42a..fe43e8d2c6e 100644 --- a/PWGHF/D2H/Tasks/taskLbReduced.cxx +++ b/PWGHF/D2H/Tasks/taskLbReduced.cxx @@ -150,13 +150,13 @@ DECLARE_SOA_TABLE(HfRedCandLbLites, "AOD", "HFREDCANDLBLITE", //! Table with som hf_cand_lb_lite::NSigTofPiBachelor, hf_cand_lb_lite::NSigTpcTofPiBachelor, // MC truth - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_lb_lite::FlagWrongCollision, hf_cand_lb_lite::PtGen); DECLARE_SOA_TABLE(HfRedLbMcCheck, "AOD", "HFREDLBMCCHECK", //! Table with MC decay type check - hf_cand_3prong::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcMatchRec, hf_cand_lb_lite::FlagWrongCollision, hf_cand_lb_lite::MLc, hf_cand_lb_lite::PtLc, diff --git a/PWGHF/D2H/Tasks/taskOmegac0ToOmegaPi.cxx b/PWGHF/D2H/Tasks/taskOmegac0ToOmegaPi.cxx index 23cd80e4d00..c2d0ed06dcd 100644 --- a/PWGHF/D2H/Tasks/taskOmegac0ToOmegaPi.cxx +++ b/PWGHF/D2H/Tasks/taskOmegac0ToOmegaPi.cxx @@ -91,8 +91,8 @@ struct HfTaskOmegac0ToOmegaPi { using McCollisionsWithFT0M = soa::Join; Filter filterOmegaCToOmegaPiFlag = (aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi))) != static_cast(0); - Filter filterOmegaCMatchedRec = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi)); - Filter filterOmegaCMatchedGen = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi)); + Filter filterOmegaCMatchedRec = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi)); + Filter filterOmegaCMatchedGen = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi)); Preslice candOmegacKFPerCollision = aod::hf_cand_xic0_omegac0::collisionId; Preslice candOmegacKFMlPerCollision = aod::hf_cand_xic0_omegac0::collisionId; diff --git a/PWGHF/D2H/Tasks/taskXic0ToXiPi.cxx b/PWGHF/D2H/Tasks/taskXic0ToXiPi.cxx index e5944d9fd9f..31091e68555 100644 --- a/PWGHF/D2H/Tasks/taskXic0ToXiPi.cxx +++ b/PWGHF/D2H/Tasks/taskXic0ToXiPi.cxx @@ -83,8 +83,8 @@ struct HfTaskXic0ToXiPi { using McCollisionsCentFT0Ms = soa::Join; Filter filterSelectXic0Candidates = aod::hf_sel_toxipi::resultSelections == true; - Filter filterXicMatchedRec = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi)); - Filter filterXicMatchedGen = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi)); + Filter filterXicMatchedRec = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi)); + Filter filterXicMatchedGen = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi)); Preslice candXicPerCollision = aod::hf_cand_xic0_omegac0::collisionId; Preslice candXicKFPerCollision = aod::hf_cand_xic0_omegac0::collisionId; Preslice candXicMlPerCollision = aod::hf_cand_xic0_omegac0::collisionId; diff --git a/PWGHF/DataModel/CandidateReconstructionTables.h b/PWGHF/DataModel/CandidateReconstructionTables.h index 50c51aec9ef..bd34cc4817a 100644 --- a/PWGHF/DataModel/CandidateReconstructionTables.h +++ b/PWGHF/DataModel/CandidateReconstructionTables.h @@ -329,13 +329,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(Ct, ct, //! DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterXY, impactParameterXY, //! [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, std::array{px, py, pz}); }); DECLARE_SOA_COLUMN(KfTopolChi2OverNdf, kfTopolChi2OverNdf, float); //! chi2overndf of the KFParticle topological constraint -// B-hadron mother information -DECLARE_SOA_COLUMN(PtBhadMotherPart, ptBhadMotherPart, float); //! pt of the first B-hadron mother particle (only in case of non-prompt) -DECLARE_SOA_COLUMN(PdgBhadMotherPart, pdgBhadMotherPart, int); //! pdg of the first B-hadron mother particle (only in case of non-prompt) -DECLARE_SOA_COLUMN(IdxBhadMotherPart, idxBhadMotherPart, int); //! index of the first B-hadron mother particle (only in case of non-prompt) -// Kink topology and material interaction mc flags -DECLARE_SOA_COLUMN(NTracksDecayed, nTracksDecayed, int8_t); //! number of tracks matched with kinked decay topology -DECLARE_SOA_COLUMN(NInteractionsWithMaterial, nInteractionsWithMaterial, int8_t); //! number of tracks matched after interaction with material // method of secondary-vertex reconstruction enum VertexerType { DCAFitter = 0, @@ -365,13 +358,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, //! [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float errDlxy, float pxM, float pyM, float ip0, float errIp0, float ip1, float errIp1, float px0, float py0, float px1, float py1) -> float { return RecoDecay::maxNormalisedDeltaIP(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, errDlxy, std::array{pxM, pyM}, std::array{ip0, ip1}, std::array{errIp0, errIp1}, std::array{std::array{px0, py0}, std::array{px1, py1}}); }); DECLARE_SOA_DYNAMIC_COLUMN(CtXY, ctXY, //! [](float px0, float py0, float pz0, float px1, float py1, float pz1, float xVtxP, float yVtxP, float xVtxS, float yVtxS, const std::array& m) -> float { return RecoDecay::ctXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}}, m); }); -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! resonant decay channel flag, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); //! resonant decay channel flag, reconstruction level // KF related properties DECLARE_SOA_COLUMN(KfGeoMassD0, kfGeoMassD0, float); //! mass of the D0 candidate from the KFParticle geometric fit @@ -379,6 +365,26 @@ DECLARE_SOA_COLUMN(KfGeoMassD0bar, kfGeoMassD0bar, float); //! mass of the D0bar } // namespace hf_cand_2prong +// MC +namespace hf_cand_mc_flag +{ +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! main decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! main decay channel, generator level +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! resonant decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); //! resonant decay channel, generator level +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level +DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! swapping of the prongs order +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); //! debug flag for mis-association reconstruction level +// B-hadron mother information +DECLARE_SOA_COLUMN(PtBhadMotherPart, ptBhadMotherPart, float); //! pt of the first B-hadron mother particle (only in case of non-prompt) +DECLARE_SOA_COLUMN(PdgBhadMotherPart, pdgBhadMotherPart, int); //! pdg of the first B-hadron mother particle (only in case of non-prompt) +DECLARE_SOA_COLUMN(IdxBhadMotherPart, idxBhadMotherPart, int); //! index of the first B-hadron mother particle (only in case of non-prompt) +// Kink topology and material interaction MC flags +DECLARE_SOA_COLUMN(NTracksDecayed, nTracksDecayed, int8_t); //! number of tracks matched with kinked decay topology +DECLARE_SOA_COLUMN(NInteractionsWithMaterial, nInteractionsWithMaterial, int8_t); //! number of tracks matched after interaction with material +} // namespace hf_cand_mc_flag + // general columns #define HFCAND_COLUMNS \ hf_cand::CollisionId, \ @@ -463,20 +469,20 @@ DECLARE_SOA_TABLE(HfCand2ProngKF, "AOD", "HFCAND2PKF", // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCand2ProngMcRec, "AOD", "HFCAND2PMCREC", //! - hf_cand_2prong::FlagMcMatchRec, - hf_cand_2prong::OriginMcRec, - hf_cand_2prong::FlagMcDecayChanRec, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, - hf_cand::NTracksDecayed, - hf_cand::NInteractionsWithMaterial); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart, + hf_cand_mc_flag::NTracksDecayed, + hf_cand_mc_flag::NInteractionsWithMaterial); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCand2ProngMcGen, "AOD", "HFCAND2PMCGEN", //! - hf_cand_2prong::FlagMcMatchGen, - hf_cand_2prong::OriginMcGen, - hf_cand_2prong::FlagMcDecayChanGen, - hf_cand::IdxBhadMotherPart); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::FlagMcDecayChanGen, + hf_cand_mc_flag::IdxBhadMotherPart); // cascade decay candidate table @@ -495,13 +501,11 @@ DECLARE_SOA_DYNAMIC_COLUMN(PtV0Neg, ptV0Neg, //! pt of the negative V0 daughter [](float px, float py) { return RecoDecay::pt(px, py); }); DECLARE_SOA_DYNAMIC_COLUMN(CtV0, ctV0, //! c*t of the V0 [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz, double m) -> float { return RecoDecay::ct(std::array{px, py, pz}, RecoDecay::distance(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}), m); }); -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level -DECLARE_SOA_COLUMN(V0X, v0X, float); //! X position of V0 decay -DECLARE_SOA_COLUMN(V0Y, v0Y, float); //! Y position of V0 decay -DECLARE_SOA_COLUMN(V0Z, v0Z, float); //! Z position of V0 decay +DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthV0, decayLengthV0, //! + [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS) -> float { return RecoDecay::distance(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}); }); +DECLARE_SOA_COLUMN(V0X, v0X, float); //! X position of V0 decay +DECLARE_SOA_COLUMN(V0Y, v0Y, float); //! Y position of V0 decay +DECLARE_SOA_COLUMN(V0Z, v0Z, float); //! Z position of V0 decay } // namespace hf_cand_casc DECLARE_SOA_TABLE(HfCandCascBase, "AOD", "HFCANDCASCBASE", //! @@ -552,7 +556,8 @@ DECLARE_SOA_TABLE(HfCandCascBase, "AOD", "HFCANDCASCBASE", //! v0data::legacy::MAntiLambda, v0data::legacy::MK0Short, v0data::MGamma, - hf_cand_casc::CtV0); + hf_cand_casc::CtV0, + hf_cand_casc::DecayLengthV0); // , // v0data::MLambda, // v0data::MAntiLambda, @@ -566,30 +571,21 @@ using HfCandCascade = HfCandCascExt; // table with results of reconstruction level MC matching for Cascade DECLARE_SOA_TABLE(HfCandCascadeMcRec, "AOD", "HFCANDCASCMCREC", //! - hf_cand_casc::FlagMcMatchRec, - hf_cand_casc::OriginMcRec, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandCascadeMcGen, "AOD", "HFCANDCASCMCGEN", //! - hf_cand_casc::FlagMcMatchGen, - hf_cand_casc::OriginMcGen, - hf_cand::IdxBhadMotherPart); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::IdxBhadMotherPart); // specific BPlus candidate properties namespace hf_cand_bplus { -DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand2Prong, "_0"); // D0 index -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand2Prong, "_0"); // D0 index DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProduct, impactParameterProduct, // Impact parameter product for B+ -> J/Psi K [](float px0, float py0, float pz0, float px1, float py1, float pz1, float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float impParK) -> float { return impParK * RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, RecoDecay::pVec(std::array{px0, py0, pz0}, std::array{px1, py1, pz1})); }); DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProductJpsi, impactParameterProductJpsi, // J/Psi impact parameter for B+ -> J/Psi K @@ -652,15 +648,15 @@ using HfCandBplus = soa::Join; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandBplusMcRec, "AOD", "HFCANDBPMCREC", - hf_cand_bplus::FlagMcMatchRec, - hf_cand_bplus::FlagMcDecayChanRec, - hf_cand_bplus::OriginMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::OriginMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandBplusMcGen, "AOD", "HFCANDBPMCGEN", - hf_cand_bplus::FlagMcMatchGen, - hf_cand_bplus::FlagMcDecayChanGen, - hf_cand_bplus::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanGen, + hf_cand_mc_flag::OriginMcGen); // specific 3-prong decay properties namespace hf_cand_3prong @@ -683,14 +679,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(CtXY, ctXY, //! [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2, float xVtxP, float yVtxP, float xVtxS, float yVtxS, const std::array& m) -> float { return RecoDecay::ctXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}, std::array{px2, py2, pz2}}, m); }); -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level -DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! swapping of the prongs order -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! resonant decay channel flag, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); //! resonant decay channel flag, generator level // Ds± → K± K∓ π± or D± → K± K∓ π± @@ -867,21 +855,21 @@ DECLARE_SOA_TABLE(HfCand3ProngKF, "AOD", "HFCAND3PKF", // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCand3ProngMcRec, "AOD", "HFCAND3PMCREC", //! - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::IsCandidateSwapped, - hf_cand_3prong::FlagMcDecayChanRec, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, - hf_cand::NTracksDecayed, - hf_cand::NInteractionsWithMaterial); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::IsCandidateSwapped, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart, + hf_cand_mc_flag::NTracksDecayed, + hf_cand_mc_flag::NInteractionsWithMaterial); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCand3ProngMcGen, "AOD", "HFCAND3PMCGEN", //! - hf_cand_3prong::FlagMcMatchGen, - hf_cand_3prong::OriginMcGen, - hf_cand_3prong::FlagMcDecayChanGen, - hf_cand::IdxBhadMotherPart); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::FlagMcDecayChanGen, + hf_cand_mc_flag::IdxBhadMotherPart); // declare dedicated BPlus -> J/Psi K decay candidate table // convention: prongs 0 and 1 should be J/Psi decay products @@ -942,14 +930,6 @@ enum ConstructMethod { DcaFitter = 0, namespace hf_cand_x { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand2Prong, "_0"); // Jpsi index -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel flag, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel flag, generator level - } // namespace hf_cand_x // declare dedicated X candidate table @@ -996,26 +976,20 @@ using HfCandX = HfCandXExt; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandXMcRec, "AOD", "HFCANDXMCREC", //! - hf_cand_x::FlagMcMatchRec, - hf_cand_x::OriginMcRec, - hf_cand_x::FlagMcDecayChanRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandXMcGen, "AOD", "HFCANDXMCGEN", //! - hf_cand_x::FlagMcMatchGen, - hf_cand_x::OriginMcGen, - hf_cand_x::FlagMcDecayChanGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::FlagMcDecayChanGen); // specific Xicc candidate properties namespace hf_cand_xicc { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // Xic index -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level } // namespace hf_cand_xicc // declare dedicated Xicc candidate table @@ -1058,14 +1032,14 @@ using HfCandXicc = HfCandXiccExt; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandXiccMcRec, "AOD", "HFCANDXICCMCREC", //! - hf_cand_xicc::FlagMcMatchRec, - hf_cand_xicc::OriginMcRec, - hf_cand_xicc::DebugMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::DebugMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandXiccMcGen, "AOD", "HFCANDXICCMCGEN", //! - hf_cand_xicc::FlagMcMatchGen, - hf_cand_xicc::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen); // specific Omegac and Xic to Xi Pi candidate properties namespace hf_cand_xic0_omegac0 @@ -1309,16 +1283,10 @@ DECLARE_SOA_COLUMN(Xic0XError, xic0XError, float); DECLARE_SOA_COLUMN(Xic0YError, xic0YError, float); DECLARE_SOA_COLUMN(Xic0ZError, xic0ZError, float); -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); DECLARE_SOA_COLUMN(DebugGenCharmBar, debugGenCharmBar, int8_t); DECLARE_SOA_COLUMN(DebugGenCasc, debugGenCasc, int8_t); DECLARE_SOA_COLUMN(DebugGenLambda, debugGenLambda, int8_t); -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); DECLARE_SOA_COLUMN(PtCharmBaryonGen, ptCharmBaryonGen, float); DECLARE_SOA_COLUMN(RapidityCharmBaryonGen, rapidityCharmBaryonGen, float); @@ -1400,8 +1368,7 @@ DECLARE_SOA_TABLE(HfCandToOmegaPi, "AOD", "HFCANDTOOMEGAPI", hf_cand_xic0_omegac0::DcaXYToPvV0Dau0, hf_cand_xic0_omegac0::DcaXYToPvV0Dau1, hf_cand_xic0_omegac0::DcaXYToPvCascDau, hf_cand_xic0_omegac0::DcaZToPvV0Dau0, hf_cand_xic0_omegac0::DcaZToPvV0Dau1, hf_cand_xic0_omegac0::DcaZToPvCascDau, hf_cand_xic0_omegac0::DcaCascDau, hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, - hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon, hf_track_index::HFflag, - o2::soa::Marker<1>); + hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon, hf_track_index::HFflag); DECLARE_SOA_TABLE(HfCandToOmegaK, "AOD", "HFCANDTOOMEGAK", o2::soa::Index<>, @@ -1429,8 +1396,7 @@ DECLARE_SOA_TABLE(HfCandToOmegaK, "AOD", "HFCANDTOOMEGAK", hf_cand_xic0_omegac0::DcaXYToPvV0Dau0, hf_cand_xic0_omegac0::DcaXYToPvV0Dau1, hf_cand_xic0_omegac0::DcaXYToPvCascDau, hf_cand_xic0_omegac0::DcaZToPvV0Dau0, hf_cand_xic0_omegac0::DcaZToPvV0Dau1, hf_cand_xic0_omegac0::DcaZToPvCascDau, hf_cand_xic0_omegac0::DcaCascDau, hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, - hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon, - o2::soa::Marker<2>); + hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon); // table with results of KFParticle DECLARE_SOA_TABLE(HfOmegacKf, "AOD", "HFOMEGACKF", //! @@ -1534,51 +1500,47 @@ DECLARE_SOA_TABLE(HfCandToXiPiKfQa, "AOD", "HFCANDTOXIPIKFQA", // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfXicToXiPiMCRec, "AOD", "HFXICXIPIMCREC", //! - hf_cand_xic0_omegac0::FlagMcMatchRec, - hf_cand_xic0_omegac0::DebugMcRec, - hf_cand_xic0_omegac0::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::DebugMcRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, - o2::soa::Marker<1>); + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart); DECLARE_SOA_TABLE(HfOmegacToXiPiMCRec, "AOD", "HFOMCXIPIMCREC", //! - hf_cand_xic0_omegac0::FlagMcMatchRec, - hf_cand_xic0_omegac0::DebugMcRec, - hf_cand_xic0_omegac0::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::DebugMcRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, - o2::soa::Marker<2>); + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart); DECLARE_SOA_TABLE(HfToOmegaPiMCRec, "AOD", "HFTOOMEPIMCREC", //! - hf_cand_xic0_omegac0::FlagMcMatchRec, - hf_cand_xic0_omegac0::DebugMcRec, - hf_cand_xic0_omegac0::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::DebugMcRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, - o2::soa::Marker<3>); + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart); DECLARE_SOA_TABLE(HfToOmegaKMCRec, "AOD", "HFTOOMEKMCREC", //! - hf_cand_xic0_omegac0::FlagMcMatchRec, - hf_cand_xic0_omegac0::DebugMcRec, - hf_cand_xic0_omegac0::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::DebugMcRec, + hf_cand_mc_flag::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, - o2::soa::Marker<4>); + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfXicToXiPiMCGen, "AOD", "HFXICXIPIMCGEN", //! - hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, - hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<1>); + hf_cand_mc_flag::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_mc_flag::OriginMcGen, hf_cand_mc_flag::IdxBhadMotherPart); DECLARE_SOA_TABLE(HfOmegacToXiPiMCGen, "AOD", "HFOMECXIPIMCGEN", //! - hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, - hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<2>); + hf_cand_mc_flag::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_mc_flag::OriginMcGen, hf_cand_mc_flag::IdxBhadMotherPart); DECLARE_SOA_TABLE(HfToOmegaPiMCGen, "AOD", "HFTOOMEPIMCGEN", //! - hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, - hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<3>); + hf_cand_mc_flag::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_mc_flag::OriginMcGen, hf_cand_mc_flag::IdxBhadMotherPart); DECLARE_SOA_TABLE(HfToOmegaKMCGen, "AOD", "HFTOOMEKMCGEN", //! - hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, - hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<4>); + hf_cand_mc_flag::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_mc_flag::OriginMcGen, hf_cand_mc_flag::IdxBhadMotherPart); // specific Xic to Xi Pi Pi candidate properties namespace hf_cand_xic_to_xi_pi_pi @@ -1643,11 +1605,7 @@ DECLARE_SOA_COLUMN(NSigTofPiFromXicPlus1, nSigTofPiFromXicPlus1, float); DECLARE_SOA_COLUMN(NSigTofBachelorPi, nSigTofBachelorPi, float); DECLARE_SOA_COLUMN(NSigTofPiFromLambda, nSigTofPiFromLambda, float); DECLARE_SOA_COLUMN(NSigTofPrFromLambda, nSigTofPrFromLambda, float); -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); +// MC DECLARE_SOA_COLUMN(DecayLengthMcGen, decayLengthMcGen, float); // Residuals and pulls DECLARE_SOA_COLUMN(PtResidual, ptResidual, float); @@ -1745,19 +1703,19 @@ DECLARE_SOA_TABLE(HfCandXicKF, "AOD", "HFCANDXICKF", // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandXicMcRec, "AOD", "HFCANDXICMCREC", - hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec, - hf_cand_xic_to_xi_pi_pi::OriginMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandXicMcGen, "AOD", "HFCANDXICMCGEN", - hf_cand_xic_to_xi_pi_pi::FlagMcMatchGen, - hf_cand_xic_to_xi_pi_pi::OriginMcGen, - hf_cand::PdgBhadMotherPart, + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::PdgBhadMotherPart, hf_cand_xic_to_xi_pi_pi::DecayLengthMcGen); // table with residuals and pulls of PV DECLARE_SOA_TABLE(HfCandXicResid, "AOD", "HFCANDXICRESID", - hf_cand_xic_to_xi_pi_pi::OriginMcGen, + hf_cand_mc_flag::OriginMcGen, hf_cand_xic_to_xi_pi_pi::PResidual, hf_cand_xic_to_xi_pi_pi::PtResidual, hf_cand_xic_to_xi_pi_pi::XPvResidual, @@ -1778,14 +1736,7 @@ namespace hf_cand_chic { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand2Prong, "_0"); // Jpsi index DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, ECALs, "_1"); -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel flag, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel flag, generator level -DECLARE_SOA_COLUMN(JpsiToMuMuMass, jpsiToMuMuMass, float); // Jpsi mass +DECLARE_SOA_COLUMN(JpsiToMuMuMass, jpsiToMuMuMass, float); // Jpsi mass } // namespace hf_cand_chic // declare dedicated chi_c candidate table @@ -1831,29 +1782,20 @@ using HfCandChic = HfCandChicExt; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandChicMcRec, "AOD", "HFCANDCHICMCREC", //! - hf_cand_chic::FlagMcMatchRec, - hf_cand_chic::OriginMcRec, - hf_cand_chic::FlagMcDecayChanRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandChicMcGen, "AOD", "HFCANDCHICMCGEN", //! - hf_cand_chic::FlagMcMatchGen, - hf_cand_chic::OriginMcGen, - hf_cand_chic::FlagMcDecayChanGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::FlagMcDecayChanGen); // specific Lb candidate properties namespace hf_cand_lb { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // Lb index -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level enum DecayTypeMc : uint8_t { LbToLcPiToPKPiPi = 0, LbToLcKToPKPiK, @@ -1904,30 +1846,21 @@ using HfCandLb = soa::Join; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandLbMcRec, "AOD", "HFCANDLBMCREC", //! - hf_cand_lb::FlagMcMatchRec, - hf_cand_lb::FlagMcDecayChanRec, - hf_cand_lb::OriginMcRec, - hf_cand_lb::DebugMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::DebugMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandLbMcGen, "AOD", "HFCANDLBMCGEN", //! - hf_cand_lb::FlagMcMatchGen, - hf_cand_lb::FlagMcDecayChanGen, - hf_cand_lb::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanGen, + hf_cand_mc_flag::OriginMcGen); // specific B0 candidate properties namespace hf_cand_b0 { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // D index -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level enum DecayTypeMc : uint8_t { B0ToDplusPiToPiKPiPi = 0, B0ToDsPiToKKPiPi, @@ -2022,30 +1955,21 @@ DECLARE_SOA_EXTENDED_TABLE_USER(HfCandB0DStExt, HfCandB0DStar, "HFCANDB0DSTEXT", // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandB0McRec, "AOD", "HFCANDB0MCREC", - hf_cand_b0::FlagMcMatchRec, - hf_cand_b0::FlagMcDecayChanRec, - hf_cand_b0::OriginMcRec, - hf_cand_b0::DebugMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::DebugMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandB0McGen, "AOD", "HFCANDB0MCGEN", - hf_cand_b0::FlagMcMatchGen, - hf_cand_b0::FlagMcDecayChanGen, - hf_cand_b0::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanGen, + hf_cand_mc_flag::OriginMcGen); // specific Bs candidate properties namespace hf_cand_bs { -DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // Ds index -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // Ds index DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProduct, impactParameterProduct, // Impact parameter product for Bs -> J/Psi phi [](float pxJpsiDauPos, float pyJpsiDauPos, float pzJpsiDauPos, float pxJpsiDauNeg, float pyJpsiDauNeg, float pzJpsiDauNeg, float pxLfTrack0, float pyLfTrack0, float pzLfTrack0, float pxLfTrack1, float pyLfTrack1, float pzLfTrack1, float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS) -> float { float impParJpsi = RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, RecoDecay::pVec(std::array{pxJpsiDauPos, pyJpsiDauPos, pzJpsiDauPos}, std::array{pxJpsiDauNeg, pyJpsiDauNeg, pzJpsiDauNeg})); @@ -2105,8 +2029,7 @@ DECLARE_SOA_TABLE(HfCandBsBase, "AOD", "HFCANDBSBASE", hf_cand::Y, hf_cand::E, hf_cand::E2, - hf_cand_2prong::CtXY, - o2::soa::Marker<1>); + hf_cand_2prong::CtXY); // extended table with expression columns that can be used as arguments of dynamic columns DECLARE_SOA_EXTENDED_TABLE_USER(HfCandBsExt, HfCandBsBase, "HFCANDBSEXT", @@ -2119,13 +2042,13 @@ using HfCandBs = soa::Join; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandBsMcRec, "AOD", "HFCANDBSMCREC", - hf_cand_bs::FlagMcMatchRec, - hf_cand_bs::FlagMcDecayChanRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcDecayChanRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandBsMcGen, "AOD", "HFCANDBSMCGEN", - hf_cand_bs::FlagMcMatchGen, - hf_cand_bs::FlagMcDecayChanGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanGen); namespace hf_cand_4prong { @@ -2191,8 +2114,7 @@ DECLARE_SOA_TABLE(HfCandBsJPBase, "AOD", "HFCANDBSJPBASE", hf_cand::Y, hf_cand::E, hf_cand::E2, - hf_cand_4prong::CtXY, - o2::soa::Marker<1>); + hf_cand_4prong::CtXY); // extended table with expression columns that can be used as arguments of dynamic columns DECLARE_SOA_EXTENDED_TABLE_USER(HfCandBsJPExt, HfCandBsJPBase, "HFCANDBSJPEXT", @@ -2214,10 +2136,6 @@ DECLARE_SOA_COLUMN(SoftPiDcaXY, softPiDcaXY, float); DECLARE_SOA_COLUMN(SoftPiDcaZ, softPiDcaZ, float); //! soft-pion impact parameter in z DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); //! Λc index // MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level DECLARE_SOA_COLUMN(ParticleAntiparticle, particleAntiparticle, int8_t); //! particle or antiparticle enum Species : int { Sc2455 = 0, @@ -2283,17 +2201,17 @@ using HfCandSc = HfCandScExt; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandScMcRec, "AOD", "HFCANDSCMCREC", //! - hf_cand_sigmac::FlagMcMatchRec, - hf_cand_sigmac::OriginMcRec, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart, hf_cand_sigmac::ParticleAntiparticle); // table with results of generation level MC matching DECLARE_SOA_TABLE(HfCandScMcGen, "AOD", "HFCANDSCMCGEN", //! - hf_cand_sigmac::FlagMcMatchGen, - hf_cand_sigmac::OriginMcGen, - hf_cand::IdxBhadMotherPart, + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::IdxBhadMotherPart, hf_cand_sigmac::ParticleAntiparticle); // specific Σc0,++ candidate properties in cascade channel @@ -2305,11 +2223,6 @@ DECLARE_SOA_COLUMN(ChargeLc, chargeLc, int8_t); DECLARE_SOA_COLUMN(ChargeSoftPi, chargeSoftPi, int8_t); //! // pion charge(either - or +) DECLARE_SOA_COLUMN(StatusSpreadLcMinvKs0PFromPDG, statusSpreadLcMinvKs0PFromPDG, int); //! // Λc Minv spread from PDG Λc mass DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCandCascade, "_0"); //! Λc index -// MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level } // namespace hf_cand_sigmac_to_cascade // declare dedicated Σc0,++ decay candidate table @@ -2467,14 +2380,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(PVecSoftPi, pVecSoftPi, [](float px, float py, float DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPiSoftPi, tpcTofNSigmaPiSoftPi, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) [](float tpcNSigmaPiSoftPi, float TOFNSigmaPiSoftPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPiSoftPi, TOFNSigmaPiSoftPi); }); // MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level DECLARE_SOA_COLUMN(FlagMcMatchRecD0, flagMcMatchRecD0, int8_t); //! reconstruction level DECLARE_SOA_COLUMN(FlagMcMatchGenD0, flagMcMatchGenD0, int8_t); //! generator level - -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level - } // namespace hf_cand_dstar /// D0 (table) from DStar @@ -2605,20 +2512,20 @@ using HfCandDstarsWPid = soa::Join); +// ---------------- +// Lc to K0sP +// ---------------- + +DECLARE_SOA_TABLE_STAGED(HfLcToK0sPPars, "HFLCTOK0SPPAR", //! Table with candidate properties used for selection + hf_cand::Chi2PCA, + hf_cand_par::Cpa, + hf_cand_par::CpaXY, + hf_cand_par::DecayLength, + hf_cand_par::DecayLengthXY, + hf_cand_par::PtProng0, + hf_cand_par::PtProng1, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + hf_cand_par::V0Radius, + hf_cand_par::V0CosPA, + hf_cand_par::MLambda, + hf_cand_par::MAntiLambda, + hf_cand_par::MK0Short, + hf_cand_par::MGamma, + hf_cand_par::DCAV0Daughters, + hf_cand_par::PtV0Pos, + hf_cand_par::PtV0Neg, + hf_cand_par::DecayLengthV0, + hf_cand_par::DCAPosToPV, + hf_cand_par::DCANegToPV, + hf_cand_par::NSigTpcPr0, + hf_cand_par::NSigTofPr0, + hf_cand_par::CtV0, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfLcToK0sPParEs, "HFLCTOK0SPPARE", //! Table with additional candidate properties used for selection + hf_cand::XSecondaryVertex, + hf_cand::YSecondaryVertex, + hf_cand::ZSecondaryVertex, + hf_cand::ErrorDecayLength, + hf_cand::ErrorDecayLengthXY, + hf_cand_par::RSecondaryVertex, + hf_cand_par::PProng0, + hf_cand_par::PProng1, + hf_cand::PxProng0, + hf_cand::PyProng0, + hf_cand::PzProng0, + hf_cand::PxProng1, + hf_cand::PyProng1, + hf_cand::PzProng1, + v0data::PxPos, + v0data::PyPos, + v0data::PzPos, + v0data::PxNeg, + v0data::PyNeg, + v0data::PzNeg, + hf_cand::ErrorImpactParameter0, + hf_cand::ErrorImpactParameter1, + hf_cand_par::Ct, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfLcToK0sPMls, "HFLCTOK0SPML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfLcToK0sPMcs, "HFLCTOK0SPMC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + o2::soa::Marker); + // ---------------- // D+ // ---------------- @@ -1025,9 +1129,9 @@ DECLARE_SOA_TABLE_STAGED(HfDstarMcs, "HFDSTMC", //! Table with MC candidate info hf_cand_mc::FlagMcMatchRec, hf_cand_mc_charm::FlagMcMatchRecCharm, hf_cand_mc::OriginMcRec, - hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart, - hf_cand::NTracksDecayed, + hf_cand_mc_flag::PtBhadMotherPart, + hf_cand_mc_flag::PdgBhadMotherPart, + hf_cand_mc_flag::NTracksDecayed, o2::soa::Marker); // ---------------- diff --git a/PWGHF/HFC/DataModel/ReducedDMesonPairsTables.h b/PWGHF/HFC/DataModel/ReducedDMesonPairsTables.h index b739ae6c89a..9c4484de852 100644 --- a/PWGHF/HFC/DataModel/ReducedDMesonPairsTables.h +++ b/PWGHF/HFC/DataModel/ReducedDMesonPairsTables.h @@ -103,9 +103,9 @@ DECLARE_SOA_TABLE(HfCandDpTinys, "AOD", "HFCANDDPTINY", full::Eta, full::Phi, full::HfCandDpFullEvId, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::FlagMcDecayChanRec) + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec) DECLARE_SOA_TABLE(HfCandDpLites, "AOD", "HFCANDDPLITE", hf_cand::Chi2PCA, @@ -151,9 +151,9 @@ DECLARE_SOA_TABLE(HfCandDpLites, "AOD", "HFCANDDPLITE", full::Y, full::Centrality, full::HfCandDpFullEvId, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::FlagMcDecayChanRec) + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec) DECLARE_SOA_TABLE(HfCandDpFulls, "AOD", "HFCANDDPFULL", hf_cand::XSecondaryVertex, @@ -229,9 +229,9 @@ DECLARE_SOA_TABLE(HfCandDpFulls, "AOD", "HFCANDDPFULL", full::E, full::Centrality, full::HfCandDpFullEvId, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::FlagMcDecayChanRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec); DECLARE_SOA_TABLE(HfCandDpMcPs, "AOD", "HFCANDDPMCP", full::Pt, @@ -239,9 +239,9 @@ DECLARE_SOA_TABLE(HfCandDpMcPs, "AOD", "HFCANDDPMCP", full::Phi, full::Y, full::HfCandDpMcEvId, - hf_cand_3prong::FlagMcMatchGen, - hf_cand_3prong::FlagMcDecayChanGen, - hf_cand_3prong::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanGen, + hf_cand_mc_flag::OriginMcGen); } // namespace o2::aod #endif // PWGHF_HFC_DATAMODEL_REDUCEDDMESONPAIRSTABLES_H_ diff --git a/PWGHF/HFC/TableProducer/correlatorDplusDplusReduced.cxx b/PWGHF/HFC/TableProducer/correlatorDplusDplusReduced.cxx index 306d2d494e8..d58da7fccd6 100644 --- a/PWGHF/HFC/TableProducer/correlatorDplusDplusReduced.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDplusDplusReduced.cxx @@ -80,14 +80,14 @@ struct HfCorrelatorDplusDplusReduced { using CollisionsCent = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - Filter filterMcGenMatching = (nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) != 0)); + Filter filterMcGenMatching = (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchGen) != 0)); Preslice tracksPerCollision = o2::aod::track::collisionId; Preslice mcParticlesPerMcCollision = o2::aod::mcparticle::mcCollisionId; - Partition reconstructedCandSig = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchRec) != 0)); - Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); - Partition reconstructedCandSigMl = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchRec) != 0)); + Partition reconstructedCandSig = (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchRec) != 0)); + Partition reconstructedCandBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition reconstructedCandSigMl = (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchRec) != 0)); HistogramRegistry registry{"registry"}; Zorro zorro; @@ -114,21 +114,21 @@ struct HfCorrelatorDplusDplusReduced { collision.posZ()); } - template + template void fillCandidateTable(const T& candidate, int localEvIdx = -1, int sign = 1) { int8_t flagMc = 0; int8_t originMc = 0; int8_t channelMc = 0; - if constexpr (doMc) { + if constexpr (DoMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); channelMc = candidate.flagMcDecayChanRec(); } std::vector outputMl = {-999., -999.}; - if constexpr (doMl) { + if constexpr (DoMl) { for (unsigned int iclass = 0; iclass < classMlIndexes->size(); iclass++) { outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMlIndexes->at(iclass)]; } @@ -283,7 +283,10 @@ struct HfCorrelatorDplusDplusReduced { } } - void processData(aod::Collisions const& collisions, SelectedCandidates const& candidates, aod::Tracks const&) + void processData(aod::Collisions const& collisions, + SelectedCandidates const& candidates, + aod::Tracks const&, + aod::BCsWithTimestamps const&) { static int lastRunNumber = -1; // reserve memory @@ -315,16 +318,17 @@ struct HfCorrelatorDplusDplusReduced { continue; fillEvent(collision); for (const auto& candidate : candidatesInThisCollision) { - auto prong_candidate = candidate.prong1_as(); - auto candidate_sign = prong_candidate.sign(); - fillCandidateTable(candidate, rowCandidateFullEvents.lastIndex(), candidate_sign); + auto prongCandidate = candidate.prong1_as(); + auto candidateSign = -prongCandidate.sign(); + fillCandidateTable(candidate, rowCandidateFullEvents.lastIndex(), candidateSign); } } } PROCESS_SWITCH(HfCorrelatorDplusDplusReduced, processData, "Process data per collision", false); void processMcRec(aod::Collisions const& collisions, - SelectedCandidatesMc const& candidates) + SelectedCandidatesMc const& candidates, + aod::Tracks const&) { // reserve memory rowCandidateFullEvents.reserve(collisions.size()); @@ -342,15 +346,16 @@ struct HfCorrelatorDplusDplusReduced { continue; fillEvent(collision); for (const auto& candidate : candidatesInThisCollision) { - auto prong_candidate = candidate.prong1_as(); - auto candidate_sign = prong_candidate.sign(); - fillCandidateTable(candidate, rowCandidateFullEvents.lastIndex(), candidate_sign); + auto prongCandidate = candidate.prong1_as(); + auto candidateSign = -prongCandidate.sign(); + fillCandidateTable(candidate, rowCandidateFullEvents.lastIndex(), candidateSign); } } } PROCESS_SWITCH(HfCorrelatorDplusDplusReduced, processMcRec, "Process data per collision", false); - void processMcGen(aod::McCollisions const& mccollisions, MatchedGenCandidatesMc const& mcparticles) + void processMcGen(aod::McCollisions const& mccollisions, + MatchedGenCandidatesMc const& mcparticles) { // reserve memory rowCandidateMcCollisions.reserve(mccollisions.size()); diff --git a/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx b/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx index bc222987dc6..9ffe580fcf5 100644 --- a/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx +++ b/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx @@ -63,6 +63,7 @@ enum CandidateType { DsToPiKK, D0ToPiK, D0ToKPi, + LcToPKPi, Hadron }; @@ -113,22 +114,26 @@ struct HfDerivedDataCreatorCorrelationsReduced { using CandDsData = soa::Filtered>; using CandDplusData = soa::Filtered>; using CandD0Data = soa::Filtered>; + using CandLcData = soa::Filtered>; using TracksData = soa::Filtered>; Filter filterSelectDsCandidates = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; Filter filterSelectDplusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlag; Filter filterSelectD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; + Filter filterSelectLcCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlag; Filter filterSelectTrkData = (nabs(aod::track::eta) < etaTrkMax) && (aod::track::pt > ptTrkMin) && (aod::track::pt < ptTrkMax) && (nabs(aod::track::dcaXY) < dcaXYTrkMax) && (nabs(aod::track::dcaZ) < dcaZTrkMax); Preslice candsDsPerColl = aod::hf_cand::collisionId; Preslice candsDplusPerColl = aod::hf_cand::collisionId; Preslice candsD0PerColl = aod::hf_cand::collisionId; + Preslice candsLcPerColl = aod::hf_cand::collisionId; Preslice trackIndicesPerColl = aod::track::collisionId; Partition selectedDsToKKPi = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag; Partition selectedDsToPiKK = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; Partition selectedD0ToPiK = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag; Partition selectedD0ToKPi = aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; + Partition selectedLcToPKPi = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlag; ConfigurableAxis binsInvMass{"binsInvMass", {300, 1.6, 2.2}, ""}; ConfigurableAxis binsMultFT0M{"binsMultFT0M", {100, 0., 10000.}, "Multiplicity as FT0M signal amplitude"}; @@ -152,6 +157,8 @@ struct HfDerivedDataCreatorCorrelationsReduced { massCharm = o2::constants::physics::MassDS; } else if (doprocessD0SameEvent || doprocessD0MixedEvent) { massCharm = o2::constants::physics::MassD0; + } else if (doprocessLcSameEvent || doprocessLcMixedEvent) { + massCharm = o2::constants::physics::MassLambdaCPlus; } else if (doprocessHadronHadronSameEvent || doprocessHadronHadronMixedEvent) { LOG(info) << "Charm mass not set, processing Hadron-Hadron case"; } else { @@ -211,6 +218,9 @@ struct HfDerivedDataCreatorCorrelationsReduced { if constexpr (CandType == CandidateType::D0ToKPi) { return HfHelper::invMassD0barToKPi(candidate); } + if constexpr (CandType == CandidateType::LcToPKPi) { + return HfHelper::invMassLcToPKPi(candidate); + } return -1.; } @@ -245,9 +255,34 @@ struct HfDerivedDataCreatorCorrelationsReduced { outputMl[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; } } + if constexpr (CandType == CandidateType::LcToPKPi) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPKPi()[classMl->at(iclass)]; + } + } return outputMl; } + /// Cut on rapidity of the candidate + /// \param candidate is the charm hadron candidate + template + bool cutCandRapidity(const TCand& candidate) + { + double y = 0.0; + if constexpr (CandType == CandidateType::DsToKKPi || CandType == CandidateType::DsToPiKK) { + y = HfHelper::yDs(candidate); + } else if constexpr (CandType == CandidateType::DplusToPiKPi) { + y = HfHelper::yDplus(candidate); + } else if constexpr (CandType == CandidateType::D0ToPiK || CandType == CandidateType::D0ToKPi) { + y = HfHelper::yD0(candidate); + } else if constexpr (CandType == CandidateType::LcToPKPi) { + y = HfHelper::yLc(candidate); + } else { + return true; + } + return std::fabs(y) < yCandMax; + } + /// Check event selections for collision and fill the collision table /// \param collision is the collision template @@ -320,6 +355,9 @@ struct HfDerivedDataCreatorCorrelationsReduced { const float collCentrality) { for (const auto& trigCand : trigCands) { + if (!cutCandRapidity(trigCand)) { + continue; + } double trigCandPt = trigCand.pt(); registry.fill(HIST("hPhiVsPtTrig"), RecoDecay::constrainAngle(trigCand.phi(), -o2::constants::math::PIHalf), trigCandPt); registry.fill(HIST("hEtaVsPtTrig"), trigCand.eta(), trigCandPt); @@ -373,6 +411,9 @@ struct HfDerivedDataCreatorCorrelationsReduced { void fillCharmMixedEvent(TTrigCands const& trigCands) { for (const auto& trigCand : trigCands) { + if (!cutCandRapidity(trigCand)) { + continue; + } registry.fill(HIST("hPhiVsPtTrig"), RecoDecay::constrainAngle(trigCand.phi(), -o2::constants::math::PIHalf), trigCand.pt()); registry.fill(HIST("hEtaVsPtTrig"), trigCand.eta(), trigCand.pt()); @@ -534,6 +575,43 @@ struct HfDerivedDataCreatorCorrelationsReduced { } PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processD0MixedEvent, "Process Mixed Event for D0 candidates", false); + // Lc with ML selections + void processLcSameEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks, + CandLcData const&) + { + auto candsLcToPKPi = selectedLcToPKPi->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + if (forceCharmInCollision && candsLcToPKPi.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillSameEvent(candsLcToPKPi, tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processLcSameEvent, "Process Same Event for Lc candidates", false); + + // Lc with ML selections + void processLcMixedEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks, + CandLcData const&) + { + auto candsLcToPKPi = selectedLcToPKPi->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + if (forceCharmInCollision && candsLcToPKPi.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillCharmMixedEvent(candsLcToPKPi); + fillTrkMixedEvent(tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processLcMixedEvent, "Process Mixed Event for Lc candidates", false); + // Hadron Hadron Same Event void processHadronHadronSameEvent(CollsWithCentMult::iterator const& coll, TracksData const& tracks) diff --git a/PWGHF/HFC/Tasks/taskCorrelationDplusDplusReduced.cxx b/PWGHF/HFC/Tasks/taskCorrelationDplusDplusReduced.cxx index 926e2a111e5..c37c1f73feb 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDplusDplusReduced.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDplusDplusReduced.cxx @@ -55,7 +55,9 @@ struct HfTaskCorrelationDplusDplusReduced { void init(InitContext const&) { registry.add("hMassDplus", "D+ candidates;inv. mass (#pi#pi K) (GeV/#it{c}^{2}))", {HistType::kTH1F, {{120, 1.5848, 2.1848}}}); + registry.add("hMassDminus", "D- candidates;inv. mass (#pi#pi K) (GeV/#it{c}^{2}))", {HistType::kTH1F, {{120, 1.5848, 2.1848}}}); registry.add("hMassDplusMatched", "D+ matched candidates;inv. mass (#pi#pi K) (GeV/#it{c}^{2}))", {HistType::kTH1F, {{120, 1.5848, 2.1848}}}); + registry.add("hMassDminusMatched", "D- matched candidates;inv. mass (#pi#pi K) (GeV/#it{c}^{2}))", {HistType::kTH1F, {{120, 1.5848, 2.1848}}}); registry.add("hMassDplusminusPair", "D plus-minus pair candidates;inv. mass (#pi K) (GeV/#it{c}^{2});inv. mass (#pi K) (GeV/#it{c}^{2})", {HistType::kTH2F, {{120, 1.5848, 2.1848}, {120, 1.5848, 2.1848}}}); registry.add("hMassDplusPair", "D plus pair candidates;inv. mass (#pi K) (GeV/#it{c}^{2});inv. mass (#pi K) (GeV/#it{c}^{2})", {HistType::kTH2F, {{120, 1.5848, 2.1848}, {120, 1.5848, 2.1848}}}); registry.add("hMassDminusPair", "D minus pair candidates;inv. mass (#pi K) (GeV/#it{c}^{2});inv. mass (#pi K) (GeV/#it{c}^{2})", {HistType::kTH2F, {{120, 1.5848, 2.1848}, {120, 1.5848, 2.1848}}}); @@ -72,7 +74,11 @@ struct HfTaskCorrelationDplusDplusReduced { auto sign1 = 1; if (cand1.pt() < 0) { sign1 = -1; + registry.fill(HIST("hMassDminus"), mass1); + } else { + registry.fill(HIST("hMassDplus"), mass1); } + for (auto cand2 = cand1 + 1; cand2 != localCandidates.end(); ++cand2) { auto mass2 = cand2.m(); auto sign2 = 1; @@ -100,9 +106,15 @@ struct HfTaskCorrelationDplusDplusReduced { for (const auto& cand1 : localCandidates) { auto mass1 = cand1.m(); - registry.fill(HIST("hMassDplus"), mass1); - if (std::abs(cand1.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) - registry.fill(HIST("hMassDplusMatched"), mass1); + if (cand1.pt() < 0) { + registry.fill(HIST("hMassDminus"), mass1); + if (std::abs(cand1.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) + registry.fill(HIST("hMassDminusMatched"), mass1); + } else { + registry.fill(HIST("hMassDplus"), mass1); + if (std::abs(cand1.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) + registry.fill(HIST("hMassDplusMatched"), mass1); + } } } PROCESS_SWITCH(HfTaskCorrelationDplusDplusReduced, processLocalDataMcRec, "Process local MC data", false); diff --git a/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx index bb312fccaac..d870eb6731d 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx @@ -29,6 +29,8 @@ #include +#include +#include #include using namespace o2; @@ -78,10 +80,19 @@ const std::vector vecEfficiencyTracksDefault(nPtBinsTrackEfficiency); struct HfTaskCorrelationDstarHadrons { Configurable applyEfficiency{"applyEfficiency", true, "Flag for applying efficiency weights"}; + Configurable useCcdbEfficiency{"useCcdbEfficiency", false, "Flag for using efficiency values from CCDB (if false, efficiency values must be provided via json files)"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathEfficiencyDstar{"ccdbPathEfficiencyDstar", "Users/d/desharma/HFC/Efficiency/Dstar", "path in ccdb for Dstar efficiency values"}; + Configurable ccdbPathEfficiencyTracks{"ccdbPathEfficiencyTracks", "Users/d/desharma/HFC/Efficiency/Track", "path in ccdb for track efficiency values"}; + Configurable ccdbTimestamp{"ccdbTimestamp", -1, "timestamp for retrieving efficiency values from CCDB"}; + Configurable efficiencyDstarFileName{"efficiencyDstarFileName", "efficiencyHFCDstar.root", "name of the efficiency file for Dstar"}; + Configurable efficiencyTracksFileName{"efficiencyTracksFileName", "efficiencyHFCTrack.root", "name of the efficiency file for tracks"}; + Configurable nEfficiencyHist{"nEfficiencyHist", 1, "if MB nEfficiencyHist = 1, if Centrality classes nEfficiencyHist = number of centrality classes (i.e. 10)"}; + // pT ranges for correlation plots: the default values are those embedded in hf_cuts_dplus_to_pi_k_pi (i.e. the mass pT bins), but can be redefined via json files Configurable> binsPtCorrelations{"binsPtCorrelations", std::vector{vecBinsPtCorrelationsDefault}, "pT bin limits for correlation plots"}; - // efficiency configirables for candidate Dstar + // efficiency configurables for candidate Dstar Configurable> binsPtEfficiency{"binsPtEfficiency", std::vector{o2::analysis::hf_cuts_dstar_to_d0_pi::vecBinsPt}, "pT bin limits for efficiency"}; Configurable> efficiencyDstar{"efficiencyDstar", std::vector{vecEfficiencyDstarDefault}, "efficiency values for Dstar vs pT bin"}; @@ -102,6 +113,10 @@ struct HfTaskCorrelationDstarHadrons { HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + o2::ccdb::CcdbApi ccdbApi; + std::vector vecHistEfficiencyDstar; + std::vector vecHistEfficiencyTracks; + void init(InitContext&) { @@ -120,6 +135,51 @@ struct HfTaskCorrelationDstarHadrons { registry.add("hCorrel2DPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2D, {axisSpecDeltaPhi, axisSpecDeltaEta}}, true); registry.add("hDeltaEtaPtIntSidebands", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1D, {axisSpecDeltaEta}}, true); registry.add("hDeltaPhiPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1D, {axisSpecDeltaPhi}}, true); + + if (applyEfficiency && useCcdbEfficiency) { + ccdbApi.init(ccdbUrl); + std::map const metadata; + bool const isEfficiencyDstarfileAvailable = ccdbApi.retrieveBlob(ccdbPathEfficiencyDstar, ".", metadata, ccdbTimestamp, false, efficiencyDstarFileName); + if (!isEfficiencyDstarfileAvailable) { + LOGF(fatal, "Failed to retrieve efficiency file for Dstar from CCDB"); + } + bool const isEfficiencyTracksfileAvailable = ccdbApi.retrieveBlob(ccdbPathEfficiencyTracks, ".", metadata, ccdbTimestamp, false, efficiencyTracksFileName); + if (!isEfficiencyTracksfileAvailable) { + LOGF(fatal, "Failed to retrieve efficiency file for tracks from CCDB"); + } + + TFile* efficiencyDstarRootFile = TFile::Open(efficiencyDstarFileName.value.c_str(), "READ"); + if (!efficiencyDstarRootFile || efficiencyDstarRootFile->IsZombie()) { + LOGF(fatal, "Failed to open efficiency file for Dstar"); + } + + TFile* efficiencyTracksRootFile = TFile::Open(efficiencyTracksFileName.value.c_str(), "READ"); + if (!efficiencyTracksRootFile || efficiencyTracksRootFile->IsZombie()) { + LOGF(fatal, "Failed to open efficiency file for tracks"); + } + + vecHistEfficiencyDstar.resize(nEfficiencyHist); + vecHistEfficiencyTracks.resize(nEfficiencyHist); + + for (int iHist = 0; iHist < nEfficiencyHist; iHist++) { + vecHistEfficiencyDstar[iHist] = dynamic_cast(efficiencyDstarRootFile->Get(Form("hEfficiencyDstar_%d", iHist))); + if (!vecHistEfficiencyDstar[iHist]) { + LOGF(fatal, "Failed to retrieve Dstar efficiency histogram hEfficiencyDstar_%d from file", iHist); + } + + vecHistEfficiencyTracks[iHist] = dynamic_cast(efficiencyTracksRootFile->Get(Form("hEfficiencyTracks_%d", iHist))); + if (!vecHistEfficiencyTracks[iHist]) { + LOGF(fatal, "Failed to retrieve track efficiency histogram hEfficiencyTracks_%d from file", iHist); + } + vecHistEfficiencyDstar[iHist]->SetDirectory(nullptr); + vecHistEfficiencyTracks[iHist]->SetDirectory(nullptr); + } + + efficiencyDstarRootFile->Close(); + efficiencyTracksRootFile->Close(); + delete efficiencyDstarRootFile; + delete efficiencyTracksRootFile; + } } void processData(aod::DstarHadronPair const& dstarHPairs) @@ -150,12 +210,21 @@ struct HfTaskCorrelationDstarHadrons { // } float netEfficiencyWeight = 1.0; - if (applyEfficiency) { + if (applyEfficiency && !useCcdbEfficiency) { float const efficiencyWeightDstar = efficiencyDstar->at(effBinPtDstar); // LOG(info)<<"efficiencyWeightDstar "<at(effBinPtTrack); // LOG(info)<<"efficiencyWeightTracks "<GetBinContent(vecHistEfficiencyDstar[0]->GetXaxis()->FindBin(ptDstar)); + // LOG(info)<<"efficiencyWeightDstar "<GetBinContent(vecHistEfficiencyTracks[0]->GetXaxis()->FindBin(ptTrack)); + // LOG(info)<<"efficiencyWeightTracks "< 1) { + // to do + LOGF(fatal, "Using CCDB efficiency with more than 1 histogram is not implemented yet"); } // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots diff --git a/PWGHF/HFC/Tasks/taskFlow.cxx b/PWGHF/HFC/Tasks/taskFlow.cxx index add129f9673..3591f8f3907 100644 --- a/PWGHF/HFC/Tasks/taskFlow.cxx +++ b/PWGHF/HFC/Tasks/taskFlow.cxx @@ -535,9 +535,10 @@ struct HfTaskFlow { std::vector const effAxis = {{configAxis.axisEtaEfficiency, "#eta"}, {configAxis.axisPtEfficiency, "p_{T} (GeV/c)"}, {configAxis.axisVertexEfficiency, "z-vtx (cm)"}}; - std::vector const userAxis = {{configAxis.axisSamples, "sampling"}}; - std::vector const hfUserAxis = {{configAxis.axisMass, "m_{inv} (GeV/c^{2})"}, - {configAxis.axisSamples, "sampling"}}; + std::vector const hfUserAxis = {{configAxis.axisMass, "m_{inv} (GeV/c^{2})"}}; + // std::vector const userAxis = {{configAxis.axisSamples, "sampling"}}; + // std::vector const hfUserAxis = {{configAxis.axisMass, "m_{inv} (GeV/c^{2})"}, + // {configAxis.axisSamples, "sampling"}}; // ========================= // Initialization of histograms and CorrelationContainers for TpcTpc cases @@ -546,8 +547,8 @@ struct HfTaskFlow { if (doprocessSameTpcTpcChCh) { addHistograms(); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } if (doprocessSameTpcTpcD0Ch) { @@ -572,8 +573,8 @@ struct HfTaskFlow { addHistograms(); addMftHistograms(); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } if (doprocessSameTpcMftD0Ch || doprocessSameTpcMftD0ChReassociated) { @@ -599,8 +600,8 @@ struct HfTaskFlow { if (doprocessSameTpcFv0aChCh) { addHistograms(); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } if (doprocessSameTpcFv0aD0Ch) { @@ -626,8 +627,8 @@ struct HfTaskFlow { addHistograms(); addMftHistograms(); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } // ========================= @@ -639,8 +640,8 @@ struct HfTaskFlow { registry.add("Data/FT0Amp", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); registry.add("Data/FT0AmpCorr", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } if (doprocessSameTpcFt0aD0Ch) { @@ -671,8 +672,8 @@ struct HfTaskFlow { registry.add("Data/FT0Amp", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); registry.add("Data/FT0AmpCorr", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } // ========================= @@ -684,8 +685,8 @@ struct HfTaskFlow { registry.add("Data/FT0Amp", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); registry.add("Data/FT0AmpCorr", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } if (doprocessSameTpcFt0cD0Ch) { @@ -715,8 +716,8 @@ struct HfTaskFlow { registry.add("Data/FT0Amp", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); registry.add("Data/FT0AmpCorr", "", {HistType::kTH2F, {configAxis.axisChID, configAxis.axisAmplitudeFit}}); - sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); } } // End of init() function @@ -1156,7 +1157,7 @@ struct HfTaskFlow { auto triggerWeight = 1; auto associatedWeight = 1; auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision - int sampleIndex = gRandom->Uniform(0, configTask.nSamples); + // int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE for (const auto& track1 : tracks1) { @@ -1192,9 +1193,9 @@ struct HfTaskFlow { // fill single-track distributions if (!fillingHFcontainer) { // if not HF-h case - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, sampleIndex, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); } else { - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, sampleIndex, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); } // FILL QA PLOTS for trigger particle @@ -1319,10 +1320,10 @@ struct HfTaskFlow { if (!fillingHFcontainer) { // fill pair correlations - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, triggerWeight * associatedWeight); } else { - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, triggerWeight * associatedWeight); } @@ -1362,7 +1363,7 @@ struct HfTaskFlow { auto triggerWeight = 1; auto associatedWeight = 1; auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision - int sampleIndex = gRandom->Uniform(0, configTask.nSamples); + // int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE for (const auto& track1 : tracks1) { @@ -1394,9 +1395,9 @@ struct HfTaskFlow { // fill single-track distributions if (!fillingHFcontainer) { // if not HF-h case - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, sampleIndex, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); } else { - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, sampleIndex, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); } // FILL QA PLOTS for trigger particle @@ -1487,10 +1488,10 @@ struct HfTaskFlow { deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); if (!fillingHFcontainer) { - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, triggerWeight * associatedWeight); } else { - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, triggerWeight * associatedWeight); } @@ -1519,7 +1520,7 @@ struct HfTaskFlow { auto triggerWeight = 1; auto associatedWeight = 1; auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision - int sampleIndex = gRandom->Uniform(0, configTask.nSamples); + // int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE for (auto const& track1 : tracks1) { @@ -1558,9 +1559,9 @@ struct HfTaskFlow { // fill single-track distributions if (!fillingHFcontainer) { // if not HF-h case - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, sampleIndex, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); } else { - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, sampleIndex, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); } // FILL QA PLOTS for trigger particle @@ -1620,10 +1621,10 @@ struct HfTaskFlow { deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) if (!fillingHFcontainer) { - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, triggerWeight * associatedWeight); } else { - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, triggerWeight * associatedWeight); } @@ -1668,10 +1669,10 @@ struct HfTaskFlow { deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) if (!fillingHFcontainer) { - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, amplitude * triggerWeight * associatedWeight); } else { - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, amplitude * triggerWeight * associatedWeight); } @@ -1719,7 +1720,7 @@ struct HfTaskFlow { auto triggerWeight = 1; auto associatedWeight = 1; auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision - int sampleIndex = gRandom->Uniform(0, configTask.nSamples); + // int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE for (auto const& track1 : tracks1) { @@ -1742,7 +1743,7 @@ struct HfTaskFlow { float phi1 = reassociatedMftTrack.phi(); o2::math_utils::bringTo02Pi(phi1); - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, sampleIndex, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); // FILL QA PLOTS for trigger particle if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { @@ -1766,7 +1767,7 @@ struct HfTaskFlow { float deltaPhi = phi1 - phi2; deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, triggerWeight * associatedWeight); // FILL QA PLOTS for associated particle @@ -1799,7 +1800,7 @@ struct HfTaskFlow { float deltaPhi = phi1 - phi2; deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) - target->getPairHist()->Fill(step, sampleIndex, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, amplitude * triggerWeight * associatedWeight); // FILL QA PLOTS for associated particle @@ -1821,7 +1822,7 @@ struct HfTaskFlow { auto triggerWeight = 1; auto associatedWeight = 1; auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision - int sampleIndex = gRandom->Uniform(0, configTask.nSamples); + // int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE FROM FT0A for (std::size_t indexChannelA = 0; indexChannelA < ft0as.channelA().size(); indexChannelA++) { @@ -1832,7 +1833,7 @@ struct HfTaskFlow { auto phiA = getPhiFT0(channelIdA, isFT0A); auto etaA = getEtaFT0(channelIdA, isFT0A); - target->getTriggerHist()->Fill(step, 0.f, multiplicity, posZ, sampleIndex, amplitude * triggerWeight); + target->getTriggerHist()->Fill(step, 0.f, multiplicity, posZ, amplitude * triggerWeight); if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { fillTriggerQa(multiplicity, etaA, phiA, 0.f); @@ -1848,7 +1849,7 @@ struct HfTaskFlow { auto etaC = getEtaFT0(channelIdC, isFT0C); float deltaPhi = RecoDecay::constrainAngle(phiA - phiC, -PIHalf); - target->getPairHist()->Fill(step, sampleIndex, etaA - etaC, 0.f, 0.f, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, etaA - etaC, 0.f, 0.f, multiplicity, deltaPhi, posZ, amplitude * triggerWeight * associatedWeight); if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { diff --git a/PWGHF/HFL/Tasks/CMakeLists.txt b/PWGHF/HFL/Tasks/CMakeLists.txt index 2eac2ac28b6..925dc4e831d 100644 --- a/PWGHF/HFL/Tasks/CMakeLists.txt +++ b/PWGHF/HFL/Tasks/CMakeLists.txt @@ -34,6 +34,11 @@ o2physics_add_dpl_workflow(task-single-muon-mult PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-single-muon-mult-mc + SOURCES taskSingleMuonMultMc.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-single-muon-reader SOURCES taskSingleMuonReader.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGDQCore diff --git a/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx index 2bac954d50d..a8f03743e4c 100644 --- a/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx +++ b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx @@ -25,6 +25,7 @@ #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Tools/KFparticle/KFUtilities.h" @@ -46,6 +47,7 @@ #include #include +#include #include #include @@ -130,6 +132,8 @@ struct HfTaskElectronWeakBoson { // Centrality estimator configuration Configurable centralityEstimator{"centralityEstimator", CentralityEstimator::FT0M, "Centrality estimator. See CentralityEstimator for valid values."}; Configurable enableCentralityAnalysis{"enableCentralityAnalysis", true, "Enable centrality-dependent analysis"}; + Configurable enableMultiplicityPVAnalysis{"enableMultiplicityPVAnalysis", true, "Enable centrality-dependent analysis"}; + Configurable enableMultiplicityFT0MAnalysis{"enableMultiplicityFT0MAnalysis", true, "Enable centrality-dependent analysis"}; Configurable centralityMin{"centralityMin", -1, "minimum cut on centrality selection"}; Configurable centralityMax{"centralityMax", 101, "maximum cut on centrality selection"}; Configurable> centralityBins{"centralityBins", {0, 20, 60, 100}, "centrality bins"}; @@ -139,6 +143,11 @@ struct HfTaskElectronWeakBoson { Configurable massZMinQA{"massZMinQA", 0.1, "minimum mass cut for Zee Reco QA"}; // CCDB service object Service ccdb{}; + // UE + Configurable nRandomCones{"nRandomCones", 100, "number of random cones"}; + Configurable rcHardE{"rcHardE", 5.0, "hard cluster veto energy"}; + Configurable rcVetoR{"rcVetoR", 0.4, "veto radius"}; + Configurable useUEsub{"useUEsub", true, "apply UE subtraction in isolation"}; struct HfElectronCandidate { float pt, eta, phi, dcaxyTrk, dcazTrk, eop, energyIso, momIso; @@ -157,7 +166,7 @@ struct HfTaskElectronWeakBoson { : pt(ptr), eta(e), phi(ph), mass(m), ptchild0(ptzee0), ptchild1(ptzee1), charge(ch) {} }; std::vector reconstructedZ; - using CollisionsWithCent = soa::Join; + using CollisionsWithCent = soa::Join; using SelectedClusters = o2::aod::EMCALClusters; // PbPb // using TrackEle = o2::soa::Join; @@ -200,6 +209,8 @@ struct HfTaskElectronWeakBoson { ConfigurableAxis confaxisInvMassZgamma{"confaxisInvMassZgamma", {150, 0, 150}, "M_{ee} (GeV/c^{2})"}; ConfigurableAxis confaxisInvMassZ{"confaxisInvMassZ", {130, 20, 150}, "M_{ee} (GeV/c^{2})"}; ConfigurableAxis confaxisZfrag{"confaxisZfrag", {200, 0, 2.0}, "p_{T,h}/p_{T,Z}"}; + ConfigurableAxis confaxisMultPV{"confaxisMultPV", {200, 0, 200.0}, "multiplicity"}; + ConfigurableAxis confaxisMultFT0{"confaxisMultFT0", {1000, 0, 1000.0}, "multiplicity"}; // Histogram registry: an object to hold your registrygrams HistogramRegistry registry{"registry"}; @@ -208,6 +219,9 @@ struct HfTaskElectronWeakBoson { Zorro zorro; OutputObj zorroSummary{"zorroSummary"}; + // defined rnd + TRandom3* rnd = nullptr; + void init(InitContext const&) { // Configure CCDB @@ -229,6 +243,9 @@ struct HfTaskElectronWeakBoson { // add configurable for CCDB path zorro.setBaseCCDBPath(cfgCCDBPath.value); + // init random + rnd = new TRandom3(0); + // define axes you want to use const AxisSpec axisZvtx{40, -20, 20, "Zvtx"}; const AxisSpec axisCounter{1, 0, 1, "events"}; @@ -281,12 +298,18 @@ struct HfTaskElectronWeakBoson { const AxisSpec axisInvMassZgamma{confaxisInvMassZgamma, "M_{ee} (GeV/c^{2})"}; const AxisSpec axisInvMassZ{confaxisInvMassZ, "M_{ee} (GeV/c^{2})"}; const AxisSpec axisZfrag{confaxisZfrag, "p_{T,h}/p_{T,Z}"}; + const AxisSpec axisMultPV{confaxisMultPV, "multiplicity"}; + const AxisSpec axisMultFT0{confaxisMultFT0, "multiplicity"}; // create registrygrams registry.add("hZvtx", "Z vertex", kTH1D, {axisZvtx}); registry.add("hEventCounterInit", "hEventCounterInit", kTH1D, {axisCounter}); registry.add("hEventCounter", "hEventCounter", kTH1D, {axisCounter}); registry.add("hCentrality", "Centrality distribution", kTH1D, {axisCentrality}); + registry.add("hCentMultCorr", "Centrality distribution", kTH2D, {{axisCentrality}, {axisMultFT0}}); + registry.add("hMultPV", "multiplicity distribution for PV", kTH1D, {axisMultPV}); + registry.add("hMultFT0", "multiplicity distribution for FT0", kTH1D, {axisMultFT0}); + registry.add("hMultFT0PV", "multiplicity distribution", kTH2D, {{axisMultFT0}, {axisMultPV}}); registry.add("hITSchi2", "ITS #chi^{2}", kTH1F, {axisChi2}); registry.add("hTPCchi2", "TPC #chi^{2}", kTH1F, {axisChi2}); registry.add("hTPCnCls", "TPC NCls", kTH1F, {axisCluster}); @@ -320,12 +343,19 @@ struct HfTaskElectronWeakBoson { // hisotgram for EMCal trigger registry.add("hEMCalTrigger", "EMCal trigger", kTH1D, {axisTrigger}); + + // histogram for UE + registry.add("hRho", "rho UE density", kTH1F, {axisE}); + registry.add("hSumERC", "RC sumE", kTH1F, {axisE}); + registry.add("hEnergyUE", "UE vs. centrality", kTH2F, {{axisCentrality}, {axisE}}); } double getIsolatedCluster(const o2::aod::EMCALCluster& cluster, - const SelectedClusters& clusters) + const SelectedClusters& clusters, + float energyUE) { double energySum = 0.0; + double energySum_excl = 0.0; double isoEnergy = 10.0; double const etaAssCluster = cluster.eta(); double const phiAssCluster = cluster.phi(); @@ -346,11 +376,12 @@ struct HfTaskElectronWeakBoson { energySum += associateCluster.energy(); } } - + energySum_excl = energySum - cluster.energy(); if (energySum > 0) { - isoEnergy = energySum / cluster.energy() - 1.0; + isoEnergy = (energySum_excl - energyUE) / cluster.energy(); } + // LOG(info) <<"clustE = " << cluster.energy() << " ; energySum = " << energySum << " ; nclust in Cone = " << nclustSum - 1 << " ; UE = " << energyUE << " ; isoEnergy = " << isoEnergy; registry.fill(HIST("hIsolationEnergy"), cluster.energy(), isoEnergy); return (isoEnergy); @@ -387,6 +418,51 @@ struct HfTaskElectronWeakBoson { // LOG(info) << "isop = " << isoMomentum; return std::make_pair(trackCount - 1, isoMomentum); } + float estimateRhoRC(const SelectedClusters& clusters) + { + const float randomConeR = rIsolation; + const float randomConeArea = o2::constants::math::PI * randomConeR * randomConeR; + + std::vector sumErc; + sumErc.reserve(nRandomCones); + + for (int i = 0; i < nRandomCones; i++) { + + float etarc = rnd->Uniform(-etaEmcMax, etaEmcMax); // in EMCal acceptance + float phirc = rnd->Uniform(phiEmcMin, phiEmcMax); // in EMCal acceptance + + float energySumRC = 0; + + for (const auto& c : clusters) { + if (c.energy() > rcHardE) { + continue; + } + double dEtarc = etarc - c.eta(); + double dPhirc = phirc - c.phi(); + dPhirc = RecoDecay::constrainAngle(dPhirc, -o2::constants::math::PI); + double const deltaRrc = std::sqrt(dEtarc * dEtarc + dPhirc * dPhirc); + if (deltaRrc < randomConeR) { + energySumRC += c.energy(); + } + } + + registry.fill(HIST("hSumERC"), energySumRC); + sumErc.push_back(energySumRC); + } + + if (sumErc.empty()) { + return 0; + } + std::nth_element(sumErc.begin(), + sumErc.begin() + sumErc.size() / 2, + sumErc.end()); + + float median = sumErc[sumErc.size() / 2]; + // LOG(info) << "median = " << median; + registry.fill(HIST("hRho"), median / randomConeArea); + + return median / randomConeArea; + } void recoMassZee(const KFParticle& kfpIsoEle, int charge, @@ -527,13 +603,39 @@ struct HfTaskElectronWeakBoson { float centrality = 1.0; if (enableCentralityAnalysis) { centrality = o2::hf_centrality::getCentralityColl(collision, centralityEstimator); - // LOG(info) << centrality; + // LOG(info) << "centrality = " << o2::hf_centrality::getCentralityColl(collision, centralityEstimator) << " ; FTC = " << collision.multFT0C(); if (centrality < centralityMin || centrality > centralityMax) { return; } - registry.fill(HIST("hCentrality"), centrality); + registry.fill(HIST("hCentMultCorr"), centrality, collision.multFT0M()); + } + + if (enableMultiplicityFT0MAnalysis || enableMultiplicityPVAnalysis) { + if (enableMultiplicityFT0MAnalysis) + centrality = collision.multFT0M(); + if (enableMultiplicityPVAnalysis) + centrality = collision.multNTracksPV(); + // LOG(info) << "raw mult PV = " << collision.multNTracksPV(); + // LOG(info) << "raw mult FT0M = " << collision.multFT0M(); + registry.fill(HIST("hMultPV"), collision.multNTracksPV()); + registry.fill(HIST("hMultFT0"), collision.multFT0M()); + registry.fill(HIST("hMultFT0PV"), collision.multFT0M(), collision.multNTracksPV()); + } + + registry.fill(HIST("hCentrality"), centrality); + + // UE estimate + float rho = 0.f; + float energyUE = 0.f; + + if (useUEsub) { + rho = estimateRhoRC(emcClusters); + energyUE = rho * static_cast(o2::constants::math::PI * rIsolation * rIsolation); + registry.fill(HIST("hEnergyUE"), centrality, energyUE); + // LOG(info) << "UE = " << energyUE; } + // track loop for (const auto& track : tracks) { if (std::abs(track.eta()) > etaTrMax) { @@ -568,7 +670,7 @@ struct HfTaskElectronWeakBoson { registry.fill(HIST("hTPCNsigma"), track.p(), track.tpcNSigmaEl()); float eop = -0.01; - float isoEnergy = 1.0; + float isoEnergy = 99.0; // track isolation auto [trackCount, isoMomentum] = getIsolatedTrack(track.eta(), track.phi(), track.p(), tracks); // LOG(info) << "isoMomentum = " << isoMomentum; @@ -657,7 +759,7 @@ struct HfTaskElectronWeakBoson { eop = energyEmc / match.track_as().p(); // LOG(info) << "eop = " << eop; - isoEnergy = getIsolatedCluster(cluster, emcClusters); + isoEnergy = getIsolatedCluster(cluster, emcClusters, energyUE); if (match.track_as().pt() > ptTHnThresh && isTHnElectron) { registry.fill(HIST("hTHnElectrons"), match.track_as().pt(), match.track_as().tpcNSigmaEl(), m02Emc, eop, isoEnergy, isoMomentum, trackCount, track.eta(), track.tpcSignal()); diff --git a/PWGHF/HFL/Tasks/taskSingleMuonMultMc.cxx b/PWGHF/HFL/Tasks/taskSingleMuonMultMc.cxx index 1f67d77b14d..29ffc66229b 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuonMultMc.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuonMultMc.cxx @@ -17,25 +17,34 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/TrackFwd.h" +#include +#include +#include +#include #include - +#include +#include +#include +#include +#include +#include + +#include #include +#include + +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::aod::fwdtrack; -auto static constexpr MinCharge = 3.f; +// Minimum PDG charge (in units of 1/3 e) +auto static constexpr ChargeMin = 3.f; namespace { @@ -257,92 +266,92 @@ struct HfTaskSingleMuonMultMc { } // particle has an associated MC particle - bool isIdentified(const uint16_t& mask) + bool isIdentified(const uint16_t mask) { return (TESTBIT(mask, IsIdentified)); } // this particle is muon - bool isMuon(const uint16_t& mask) + bool isMuon(const uint16_t mask) { return (TESTBIT(mask, IsIdentified) && TESTBIT(mask, IsMuon)); } // this muon comes from transport - bool isSecondaryMu(const uint16_t& mask) + bool isSecondaryMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, IsSecondary)); } // this muon comes from light flavor quark decay - bool isLightDecayMu(const uint16_t& mask) + bool isLightDecayMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, HasLightParent) && (!TESTBIT(mask, IsSecondary))); } // this muon comes from tau decays - bool isTauDecayMu(const uint16_t& mask) + bool isTauDecayMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, HasTauParent) && (!TESTBIT(mask, HasWParent)) && (!TESTBIT(mask, HasZParent)) && (!TESTBIT(mask, HasBeautyParent)) && (!TESTBIT(mask, HasCharmParent))); } // this muon comes from W+- decay - bool isWBosonDecayMu(const uint16_t& mask) + bool isWBosonDecayMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, HasWParent) && (!TESTBIT(mask, HasZParent)) && (!TESTBIT(mask, HasTauParent)) && (!TESTBIT(mask, HasLightParent)) && (!TESTBIT(mask, IsSecondary))); } // this muon comes from Z decay - bool isZBosonDecayMu(const uint16_t& mask) + bool isZBosonDecayMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, HasZParent) && (!TESTBIT(mask, HasWParent)) && (!TESTBIT(mask, HasTauParent)) && (!TESTBIT(mask, HasLightParent)) && (!TESTBIT(mask, IsSecondary))); } // this muon comes from quarkonium decay - bool isQuarkoniumDecayMu(const uint16_t& mask) + bool isQuarkoniumDecayMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, HasQuarkoniumParent) && (!TESTBIT(mask, HasBeautyParent)) && (!TESTBIT(mask, HasCharmParent)) && (!TESTBIT(mask, HasLightParent))); } // this muon comes from beauty decay and does not have light flavor parent - bool isBeautyMu(const uint16_t& mask) + bool isBeautyMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, HasBeautyParent) && (!TESTBIT(mask, HasQuarkoniumParent)) && (!TESTBIT(mask, HasLightParent)) && (!TESTBIT(mask, IsSecondary))); } // this muon comes directly from beauty decay - bool isBeautyDecayMu(const uint16_t& mask) + bool isBeautyDecayMu(const uint16_t mask) { return (isBeautyMu(mask) && (!TESTBIT(mask, HasCharmParent) && (!TESTBIT(mask, HasQuarkoniumParent))) && (!TESTBIT(mask, HasLightParent)) && (!TESTBIT(mask, IsSecondary))); } // this muon comes from non-prompt charm decay and does not have light flavor parent - bool isNonpromptCharmMu(const uint16_t& mask) + bool isNonpromptCharmMu(const uint16_t mask) { return (isBeautyMu(mask) && TESTBIT(mask, HasCharmParent) && (!TESTBIT(mask, HasQuarkoniumParent)) && (!TESTBIT(mask, HasLightParent)) && (!TESTBIT(mask, IsSecondary))); } // this muon comes from prompt charm decay and does not have light flavor parent - bool isPromptCharmMu(const uint16_t& mask) + bool isPromptCharmMu(const uint16_t mask) { return (isMuon(mask) && TESTBIT(mask, HasCharmParent) && (!TESTBIT(mask, HasBeautyParent)) && (!TESTBIT(mask, HasQuarkoniumParent)) && (!TESTBIT(mask, HasLightParent)) && (!TESTBIT(mask, IsSecondary))); } // this muon comes from other sources which have not classified above. - bool isOtherMu(const uint16_t& mask) + bool isOtherMu(const uint16_t mask) { return (isMuon(mask) && (!isSecondaryMu(mask)) && (!isLightDecayMu(mask)) && (!isTauDecayMu(mask)) && (!isWBosonDecayMu(mask)) && (!isZBosonDecayMu(mask)) && (!isQuarkoniumDecayMu(mask)) && (!isBeautyMu(mask)) && (!isPromptCharmMu(mask))); } // this is a hadron - bool isHadron(const uint16_t& mask) + bool isHadron(const uint16_t mask) { return (TESTBIT(mask, IsIdentified) && (!TESTBIT(mask, IsMuon))); } // this particle is unidentified - bool isUnidentified(const uint16_t& mask) + bool isUnidentified(const uint16_t mask) { - return ((!TESTBIT(mask, IsIdentified))); + return (!TESTBIT(mask, IsIdentified)); } // fill the histograms of each particle types @@ -398,7 +407,10 @@ struct HfTaskSingleMuonMultMc { } } - void process(McGenCollisions::iterator const& mccollision, McMuons const& muons, aod::McParticles const&, McRecCollisions const& collisions) + void process(McGenCollisions::iterator const& mccollision, + McMuons const& muons, + aod::McParticles const&, + McRecCollisions const& collisions) { // event selections @@ -409,14 +421,14 @@ struct HfTaskSingleMuonMultMc { registry.fill(HIST("hNEventGenMu"), 1); for (const auto& muon : muons) { - if (!(muon.has_mcParticle())) { + if (!muon.has_mcParticle()) { continue; } auto mcPart(muon.mcParticle()); auto pdgGen(mcPart.pdgCode()); auto etaGen(mcPart.eta()); - if (!(std::abs(pdgGen) == kMuonMinus)) { + if (std::abs(pdgGen) != kMuonMinus) { continue; } if ((etaGen >= etaMax) || (etaGen < etaMin)) { @@ -439,7 +451,7 @@ struct HfTaskSingleMuonMultMc { continue; } - if (!(muon.has_mcParticle())) { + if (!muon.has_mcParticle()) { continue; } const auto pt(muon.pt()), eta(muon.eta()), rAbsorb(muon.rAtAbsorberEnd()), pDca(muon.pDca()), chi2(muon.chi2MatchMCHMFT()); @@ -474,7 +486,10 @@ struct HfTaskSingleMuonMultMc { } } - void processResTrack(McGenCollisions::iterator const& mccollision, McRecCollisions const& collisions, aod::McParticles const& particles, MyTracks const& tracks) + void processResTrack(McGenCollisions::iterator const& mccollision, + McRecCollisions const& collisions, + aod::McParticles const& particles, + MyTracks const& tracks) { // event selections if (std::abs(mccollision.posZ()) > zVtxMax) { @@ -496,7 +511,7 @@ struct HfTaskSingleMuonMultMc { charge = p->Charge(); } - if (std::abs(charge) < MinCharge) { + if (std::abs(charge) < ChargeMin) { continue; } if (particle.pt() < ptTrackMin || std::abs(particle.eta()) >= etaTrackMax) { @@ -514,17 +529,19 @@ struct HfTaskSingleMuonMultMc { auto nTrk = 0; auto tracksample = tracks.sliceBy(perCol, collision.globalIndex()); for (const auto& track : tracksample) { - if (!track.isGlobalTrack()) + if (!track.isGlobalTrack()) { continue; + } registry.fill(HIST("hParticleRec"), track.pt(), track.eta()); ++nTrk; } - if (nTrk < 1) + if (nTrk < 1) { continue; + } registry.fill(HIST("hTrackResponse"), nP, nTrk); } } - PROCESS_SWITCH(HfTaskSingleMuonMultMc, processResTrack, "Process Track Reconstruction/Generation", true); + PROCESS_SWITCH(HfTaskSingleMuonMultMc, processResTrack, "Process Track Reconstruction/Generation", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/CMakeLists.txt b/PWGHF/TableProducer/CMakeLists.txt index 119dcecd6cf..174cbfa9621 100644 --- a/PWGHF/TableProducer/CMakeLists.txt +++ b/PWGHF/TableProducer/CMakeLists.txt @@ -345,6 +345,11 @@ o2physics_add_dpl_workflow(derived-data-creator-lc-to-p-k-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(derived-data-creator-lc-to-k0s-p + SOURCES derivedDataCreatorLcToK0sP.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(derived-data-creator-xic-to-xi-pi-pi SOURCES derivedDataCreatorXicToXiPiPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/PWGHF/TableProducer/derivedDataCreatorB0ToDPi.cxx b/PWGHF/TableProducer/derivedDataCreatorB0ToDPi.cxx index 5378586cff8..bb52685c14e 100644 --- a/PWGHF/TableProducer/derivedDataCreatorB0ToDPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorB0ToDPi.cxx @@ -107,7 +107,7 @@ struct HfDerivedDataCreatorB0ToDPi { using THfCandDaughtersMl = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_b0::isSelB0ToDPi & static_cast(BIT(aod::SelectionStep::RecoMl - 1))) != 0; - Filter filterMcGenMatching = nabs(aod::hf_cand_b0::flagMcMatchGen) == static_cast(DecayChannelMain::B0ToDminusPi); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(DecayChannelMain::B0ToDminusPi); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -121,10 +121,10 @@ struct HfDerivedDataCreatorB0ToDPi { Partition candidatesMlAll = aod::hf_sel_candidate_b0::isSelB0ToDPi >= 0; Partition candidatesMcMlAll = aod::hf_sel_candidate_b0::isSelB0ToDPi >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); - Partition candidatesMcBkg = nabs(aod::hf_cand_b0::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); - Partition candidatesMcMlSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_b0::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.cxx b/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.cxx index 05c34f4c85b..5baaec8dafa 100644 --- a/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.cxx @@ -72,6 +72,7 @@ struct HfDerivedDataCreatorBplusToD0Pi { // Candidates Produces rowCandidatePar; Produces rowCandidateParD0; + Produces rowCandidateParD0E; Produces rowCandidateParE; Produces rowCandidateSel; Produces rowCandidateMl; @@ -83,6 +84,7 @@ struct HfDerivedDataCreatorBplusToD0Pi { HfConfigurableDerivedData confDerData; Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; Configurable fillCandidateParD0{"fillCandidateParD0", true, "Fill D0 candidate parameters"}; + Configurable fillCandidateParD0E{"fillCandidateParD0E", true, "Fill additional D0 candidate parameters"}; Configurable fillCandidateParE{"fillCandidateParE", true, "Fill candidate extended parameters"}; Configurable fillCandidateSel{"fillCandidateSel", true, "Fill candidate selection flags"}; Configurable fillCandidateMl{"fillCandidateMl", true, "Fill candidate selection ML scores"}; @@ -108,7 +110,7 @@ struct HfDerivedDataCreatorBplusToD0Pi { using THfCandDaughtersMl = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_bplus::isSelBplusToD0Pi & static_cast(BIT(aod::SelectionStep::RecoMl - 1))) != 0; - Filter filterMcGenMatching = nabs(aod::hf_cand_bplus::flagMcMatchGen) == static_cast(DecayChannelMain::BplusToD0Pi); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(DecayChannelMain::BplusToD0Pi); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -122,10 +124,10 @@ struct HfDerivedDataCreatorBplusToD0Pi { Partition candidatesMlAll = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= 0; Partition candidatesMcMlAll = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); - Partition candidatesMcBkg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); - Partition candidatesMcMlSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); void init(InitContext const&) { @@ -197,6 +199,32 @@ struct HfDerivedDataCreatorBplusToD0Pi { sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][1], sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][2]); } + if (fillCandidateParD0E) { + float invMassD0 = 0.; + if (candFlag == 0) { + invMassD0 = HfHelper::invMassD0ToPiK(prongCharm); + } else if (candFlag == 1) { + invMassD0 = HfHelper::invMassD0barToKPi(prongCharm); + } + rowCandidateParD0E( + prongCharm.chi2PCA(), + prongCharm.nProngsContributorsPV(), + invMassD0, + prongCharm.maxNormalisedDeltaIP(), + prongCharm.decayLengthXY(), + prongCharm.decayLengthNormalised(), + prongCharm.decayLengthXYNormalised(), + prongCharm.impactParameterNormalised0(), + prongCharm.impactParameterNormalised1(), + prongCharm.pxProng0(), + prongCharm.pyProng0(), + prongCharm.pzProng0(), + prongCharm.pxProng1(), + prongCharm.pyProng1(), + prongCharm.pzProng1(), + prongCharm.ptProng0(), + prongCharm.ptProng1()); + } if (fillCandidateParE) { rowCandidateParE( candidate.xSecondaryVertex(), @@ -209,6 +237,10 @@ struct HfDerivedDataCreatorBplusToD0Pi { candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1(), + RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), candidate.errorImpactParameter1(), HfHelper::cosThetaStarBplus(candidate), ct); @@ -277,6 +309,7 @@ struct HfDerivedDataCreatorBplusToD0Pi { reserveTable(rowCandidatePar, fillCandidatePar, sizeTableCand); reserveTable(rowCandidateParD0, fillCandidateParD0, sizeTableCand); reserveTable(rowCandidateParE, fillCandidateParE, sizeTableCand); + reserveTable(rowCandidateParD0E, fillCandidateParD0E, sizeTableCand); reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); reserveTable(rowCandidateMlD0, fillCandidateMlD0, sizeTableCand); diff --git a/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx index f8e71198d1c..9041d4d7c2e 100644 --- a/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx @@ -105,7 +105,7 @@ struct HfDerivedDataCreatorD0ToKPi { using TypeMcCollisions = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; - Filter filterMcGenMatching = nabs(aod::hf_cand_2prong::flagMcMatchGen) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesKfPerCollision = aod::hf_cand::collisionId; @@ -127,14 +127,14 @@ struct HfDerivedDataCreatorD0ToKPi { Partition candidatesMcMlAll = aod::hf_sel_candidate_d0::isSelD0 >= 0; Partition candidatesMcKfMlAll = aod::hf_sel_candidate_d0::isSelD0 >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition candidatesMcBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition candidatesMcKfSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition candidatesMcKfBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition candidatesMcMlSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition candidatesMcKfMlSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition candidatesMcKfMlBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx index 957ad139756..a7a90b507c5 100644 --- a/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx @@ -102,7 +102,7 @@ struct HfDerivedDataCreatorDplusToPiKPi { using TypeMcCollisions = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi & static_cast(BIT(aod::SelectionStep::RecoMl - 1))) != 0; // select candidates which passed all cuts at least up to RecoMl - 1 - Filter filterMcGenMatching = nabs(aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -116,10 +116,10 @@ struct HfDerivedDataCreatorDplusToPiKPi { Partition candidatesMlAll = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 0; Partition candidatesMcMlAll = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); - Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); - Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/derivedDataCreatorDsToKKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorDsToKKPi.cxx index 0a5f217e19e..587b967af0b 100644 --- a/PWGHF/TableProducer/derivedDataCreatorDsToKKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorDsToKKPi.cxx @@ -100,7 +100,7 @@ struct HfDerivedDataCreatorDsToKKPi { using TypeMcCollisions = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_ds::isSelDsToKKPi & static_cast(BIT(aod::SelectionStep::RecoMl - 1))) != 0; // select candidates which passed all cuts at least up to RecoMl - 1 - Filter filterMcGenMatching = nabs(aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -114,10 +114,10 @@ struct HfDerivedDataCreatorDsToKKPi { Partition candidatesMlAll = aod::hf_sel_candidate_ds::isSelDsToKKPi >= 0; Partition candidatesMcMlAll = aod::hf_sel_candidate_ds::isSelDsToKKPi >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); - Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); - Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx b/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx index 1a15c3b1fb3..a04dc0cf033 100644 --- a/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx @@ -98,7 +98,7 @@ struct HfDerivedDataCreatorDstarToD0Pi { using TypeMcCollisions = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == true; - Filter filterMcGenMatching = nabs(aod::hf_cand_dstar::flagMcMatchGen) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -112,10 +112,10 @@ struct HfDerivedDataCreatorDstarToD0Pi { Partition candidatesMlAll = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == true; Partition candidatesMcMlAll = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == true; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_dstar::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); - Partition candidatesMcBkg = nabs(aod::hf_cand_dstar::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); - Partition candidatesMcMlSig = nabs(aod::hf_cand_dstar::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_dstar::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/derivedDataCreatorLcToK0sP.cxx b/PWGHF/TableProducer/derivedDataCreatorLcToK0sP.cxx new file mode 100644 index 00000000000..0386d6afba6 --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorLcToK0sP.cxx @@ -0,0 +1,408 @@ +// 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 derivedDataCreatorLcToK0sP.cxx +/// \brief Producer of derived tables of Lc candidates, collisions and MC particles +/// \note Based on treeCreatorLcToK0sP.cxx and derivedDataCreatorD0ToKPi.cxx +/// +/// \author Luigi Dello Stritto , Marietta-Blau Institute +/// \author Vít Kučera , Inha University + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::hf_derived; + +/// Writes the full information in an output TTree +struct HfDerivedDataCreatorLcToK0sP { + HfProducesDerivedData< + o2::aod::HfLcToK0sPBases, + o2::aod::HfLcToK0sPCollBases, + o2::aod::HfLcToK0sPCollIds, + o2::aod::HfLcToK0sPMcCollBases, + o2::aod::HfLcToK0sPMcCollIds, + o2::aod::HfLcToK0sPMcRCollIds, + o2::aod::HfLcToK0sPPBases, + o2::aod::HfLcToK0sPPIds> + rowsCommon; + // Candidates + Produces rowCandidatePar; + Produces rowCandidateParE; + Produces rowCandidateSel; + Produces rowCandidateMl; + Produces rowCandidateId; + Produces rowCandidateMc; + + // Switches for filling tables + HfConfigurableDerivedData confDerData; + Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; + Configurable fillCandidateParE{"fillCandidateParE", true, "Fill candidate extended parameters"}; + Configurable fillCandidateSel{"fillCandidateSel", true, "Fill candidate selection flags"}; + Configurable fillCandidateMl{"fillCandidateMl", true, "Fill candidate selection ML scores"}; + Configurable fillCandidateId{"fillCandidateId", true, "Fill original indices from the candidate table"}; + Configurable fillCandidateMc{"fillCandidateMc", true, "Fill candidate MC info"}; + // Parameters for production of training samples + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + + SliceCache cache; + static constexpr double Mass{o2::constants::physics::MassLambdaCPlus}; + + using CollisionsWCentMult = soa::Join; + using CollisionsWMcCentMult = soa::Join; + using TracksWPid = soa::Join; + using SelectedCandidates = soa::Filtered>; + using SelectedCandidatesMc = soa::Filtered>; + using SelectedCandidatesMl = soa::Filtered>; + using SelectedCandidatesMcMl = soa::Filtered>; + using MatchedGenCandidatesMc = soa::Filtered>; + using TypeMcCollisions = soa::Join; + + Filter filterSelectCandidates = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= 1; + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == 1; + + Preslice candidatesPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMlPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMcMlPerCollision = aod::hf_cand::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + + // trivial partitions for all candidates to allow "->sliceByCached" inside processCandidates + Partition candidatesAll = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= 0; + Partition candidatesMcAll = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= 0; + Partition candidatesMlAll = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= 0; + Partition candidatesMcMlAll = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= 0; + // partitions for signal and background + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == 1; + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != 1; + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == 1; + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != 1; + + void init(InitContext const&) + { + std::array doprocess{doprocessData, doprocessMcSig, doprocessMcBkg, doprocessMcAll, doprocessDataMl, doprocessMcMlSig, doprocessMcMlBkg, doprocessMcMlAll, doprocessMcGenOnly}; + if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { + LOGP(fatal, "Only one process function can be enabled at a time."); + } + rowsCommon.init(confDerData); + } + + template + void fillTablesCandidate(const T& candidate, const U& bach, int candFlag, double invMass, + double ct, double ctV0, double y, int8_t flagMc, int8_t origin, const std::vector& mlScores) + { + rowsCommon.fillTablesCandidate(candidate, invMass, y); + if (fillCandidatePar) { + rowCandidatePar( + candidate.chi2PCA(), + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.v0radius(), + candidate.v0cosPA(), + candidate.mLambda(), + candidate.mAntiLambda(), + candidate.mK0Short(), + candidate.mGamma(), + candidate.dcaV0daughters(), + candidate.ptV0Pos(), + candidate.ptV0Neg(), + candidate.decayLengthV0(), + candidate.dcanegtopv(), + candidate.dcapostopv(), + bach.tpcNSigmaPr(), + bach.tofNSigmaPr(), + ctV0); + } + if (fillCandidateParE) { + rowCandidateParE( + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.rSecondaryVertex(), + RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), + RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.pxpos(), + candidate.pypos(), + candidate.pzpos(), + candidate.pxneg(), + candidate.pyneg(), + candidate.pzneg(), + candidate.errorImpactParameter0(), + candidate.errorImpactParameter1(), + ct); + } + if (fillCandidateSel) { + rowCandidateSel( + BIT(candFlag)); + } + if (fillCandidateMl) { + rowCandidateMl( + mlScores); + } + if (fillCandidateId) { + rowCandidateId( + candidate.collisionId(), + candidate.prong0Id(), + candidate.posTrackId(), + candidate.negTrackId()); + } + if (fillCandidateMc) { + rowCandidateMc( + flagMc, + origin); + } + } + + template + void processCandidates(CollType const& collisions, + Partition& candidates, + TracksWPid const&, + aod::BCs const&) + { + // Fill collision properties + if constexpr (IsMc) { + if (confDerData.fillMcRCollId) { + rowsCommon.matchedCollisions.clear(); + } + } + auto sizeTableColl = collisions.size(); + rowsCommon.reserveTablesColl(sizeTableColl); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candidatesThisColl = candidates->sliceByCached(aod::hf_cand::collisionId, thisCollId, cache); // FIXME + auto sizeTableCand = candidatesThisColl.size(); + LOGF(debug, "Rec. collision %d has %d candidates", thisCollId, sizeTableCand); + // Skip collisions without HF candidates (and without HF particles in matched MC collisions if saving indices of reconstructed collisions matched to MC collisions) + bool mcCollisionHasMcParticles{false}; + if constexpr (IsMc) { + mcCollisionHasMcParticles = confDerData.fillMcRCollId && collision.has_mcCollision() && rowsCommon.hasMcParticles[collision.mcCollisionId()]; + LOGF(debug, "Rec. collision %d has MC collision %d with MC particles? %s", thisCollId, collision.mcCollisionId(), mcCollisionHasMcParticles ? "yes" : "no"); + } + if (sizeTableCand == 0 && (!confDerData.fillMcRCollId || !mcCollisionHasMcParticles)) { + LOGF(debug, "Skipping rec. collision %d", thisCollId); + continue; + } + LOGF(debug, "Filling rec. collision %d at derived index %d", thisCollId, rowsCommon.rowCollBase.lastIndex() + 1); + rowsCommon.fillTablesCollision(collision); + + // Fill candidate properties + rowsCommon.reserveTablesCandidates(sizeTableCand); + reserveTable(rowCandidatePar, fillCandidatePar, sizeTableCand); + reserveTable(rowCandidateParE, fillCandidateParE, sizeTableCand); + reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); + reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); + reserveTable(rowCandidateId, fillCandidateId, sizeTableCand); + if constexpr (IsMc) { + reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); + } + int8_t flagMcRec = 0, origin = 0; + for (const auto& candidate : candidatesThisColl) { + if constexpr (IsMc) { + flagMcRec = candidate.flagMcMatchRec(); + origin = candidate.originMcRec(); + if constexpr (OnlyBkg) { + if (std::abs(flagMcRec) == 1) { + continue; + } + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != 1) { + continue; + } + } + } else { + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + auto bach = candidate.template prong0_as(); // bachelor + double const ct = HfHelper::ctLc(candidate); + double const ctV0 = HfHelper::ctV0K0s(candidate); + double const y = HfHelper::yLc(candidate); + float const massLcToK0sP = HfHelper::invMassLcToK0sP(candidate); + std::vector mlScoresLcToK0sP; + if constexpr (IsMl) { + std::copy(candidate.mlProbLcToK0sP().begin(), candidate.mlProbLcToK0sP().end(), std::back_inserter(mlScoresLcToK0sP)); + } + if (candidate.isSelLcToK0sP()) { + fillTablesCandidate(candidate, bach, 0, massLcToK0sP, ct, ctV0, y, flagMcRec, origin, mlScoresLcToK0sP); + } + } + } + } + + void processData(CollisionsWCentMult const& collisions, + SelectedCandidates const&, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesAll, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processData, "Process data", true); + + void processMcSig(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcSig, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processMcSig, "Process MC only for signals", false); + + void processMcBkg(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcBkg, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processMcBkg, "Process MC only for background", false); + + void processMcAll(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcAll, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processMcAll, "Process MC", false); + + // ML versions + + void processDataMl(CollisionsWCentMult const& collisions, + SelectedCandidatesMl const&, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesMlAll, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processDataMl, "Process data with ML", false); + + void processMcMlSig(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlSig, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processMcMlSig, "Process MC with ML only for signals", false); + + void processMcMlBkg(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlBkg, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processMcMlBkg, "Process MC with ML only for background", false); + + void processMcMlAll(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlAll, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToK0sP, processMcGenOnly, "Process MC gen. only", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx index b96ac350953..efecd6f6713 100644 --- a/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx @@ -100,7 +100,7 @@ struct HfDerivedDataCreatorLcToPKPi { using TypeMcCollisions = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= 1 || aod::hf_sel_candidate_lc::isSelLcToPiKP >= 1; - Filter filterMcGenMatching = nabs(aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -114,10 +114,10 @@ struct HfDerivedDataCreatorLcToPKPi { Partition candidatesMlAll = aod::hf_sel_candidate_lc::isSelLcToPKPi >= 0; Partition candidatesMcMlAll = aod::hf_sel_candidate_lc::isSelLcToPKPi >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); - Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); - Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Partition candidatesMcSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/derivedDataCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/derivedDataCreatorXicToXiPiPi.cxx index fa52ec0a79f..9e0529b97d6 100644 --- a/PWGHF/TableProducer/derivedDataCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorXicToXiPiPi.cxx @@ -102,7 +102,7 @@ struct HfDerivedDataCreatorXicToXiPiPi { using THfCandDaughtersMl = aod::Cascades; Filter filterSelectCandidates = (aod::hf_sel_candidate_xic::isSelXicToXiPiPi & static_cast(BIT(o2::aod::hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoMl - 1))) != 0; - Filter filterMcGenMatching = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchGen != 0; + Filter filterMcGenMatching = aod::hf_cand_mc_flag::flagMcMatchGen != 0; Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -116,10 +116,10 @@ struct HfDerivedDataCreatorXicToXiPiPi { Partition candidatesMlAll = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= 0; Partition candidatesMcMlAll = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= 0; // partitions for signal and background - Partition candidatesMcSig = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec != 0; - Partition candidatesMcBkg = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec == 0; - Partition candidatesMcMlSig = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec != 0; - Partition candidatesMcMlBkg = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec == 0; + Partition candidatesMcSig = aod::hf_cand_mc_flag::flagMcMatchRec != 0; + Partition candidatesMcBkg = aod::hf_cand_mc_flag::flagMcMatchRec == 0; + Partition candidatesMcMlSig = aod::hf_cand_mc_flag::flagMcMatchRec != 0; + Partition candidatesMcMlBkg = aod::hf_cand_mc_flag::flagMcMatchRec == 0; void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx b/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx index af4663a1b41..dda2819b164 100644 --- a/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx +++ b/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx @@ -96,8 +96,8 @@ DECLARE_SOA_TABLE(HfCandB0Lites, "AOD", "HFCANDB0LITE", full::Eta, full::Phi, full::Y, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec); DECLARE_SOA_TABLE(HfCandB0Fulls, "AOD", "HFCANDB0FULL", collision::BCId, @@ -146,8 +146,8 @@ DECLARE_SOA_TABLE(HfCandB0Fulls, "AOD", "HFCANDB0FULL", full::Phi, full::Y, full::E, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec); DECLARE_SOA_TABLE(HfCandB0FullEvs, "AOD", "HFCANDB0FULLEV", collision::BCId, @@ -164,8 +164,8 @@ DECLARE_SOA_TABLE(HfCandB0FullPs, "AOD", "HFCANDB0FULLP", full::Eta, full::Phi, full::Y, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcGen); } // namespace o2::aod /// Writes the full information in an output TTree @@ -188,8 +188,8 @@ struct HfTreeCreatorB0ToDPi { Filter filterSelectCandidates = aod::hf_sel_candidate_b0::isSelB0ToDPi >= selectionFlagB0; - Partition recSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); - Partition recBg = nabs(aod::hf_cand_b0::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); + Partition recSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); + Partition recBg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx b/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx index 9aa6b5f7cab..66826ddfe5c 100644 --- a/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx +++ b/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx @@ -153,7 +153,7 @@ DECLARE_SOA_TABLE(HfCandBpFulls, "AOD", "HFCANDBPFULL", full::Phi, full::Y, full::E, - hf_cand_2prong::FlagMcMatchRec, + hf_cand_mc_flag::FlagMcMatchRec, full::D0M, full::D0PtProng0, full::D0PtProng1, @@ -195,8 +195,8 @@ DECLARE_SOA_TABLE(HfCandBpFullPs, "AOD", "HFCANDBPFULLP", full::Eta, full::Phi, full::Y, - hf_cand_2prong::FlagMcMatchRec, - hf_cand_2prong::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcGen); DECLARE_SOA_TABLE(HfCandBpLites, "AOD", "HFCANDBPLITE", hf_cand::Chi2PCA, @@ -219,8 +219,8 @@ DECLARE_SOA_TABLE(HfCandBpLites, "AOD", "HFCANDBPLITE", full::Eta, full::Phi, full::Y, - hf_cand_2prong::FlagMcMatchRec, - hf_cand_2prong::OriginMcRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec); } // namespace o2::aod @@ -244,8 +244,8 @@ struct HfTreeCreatorBplusToD0Pi { Filter filterSelectCandidates = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= selectionFlagBplus; - Partition recSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); - Partition recBg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); + Partition recSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); + Partition recBg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx b/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx index 6e30341f584..6dd99548b7c 100644 --- a/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx +++ b/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx @@ -95,7 +95,7 @@ DECLARE_SOA_TABLE(HfCandBsLites, "AOD", "HFCANDBSLITE", full::Eta, full::Phi, full::Y, - hf_cand_bs::FlagMcMatchRec); + hf_cand_mc_flag::FlagMcMatchRec); DECLARE_SOA_TABLE(HfCandBsFulls, "AOD", "HFCANDBSFULL", collision::BCId, @@ -143,7 +143,7 @@ DECLARE_SOA_TABLE(HfCandBsFulls, "AOD", "HFCANDBSFULL", full::Phi, full::Y, full::E, - hf_cand_bs::FlagMcMatchRec); + hf_cand_mc_flag::FlagMcMatchRec); DECLARE_SOA_TABLE(HfCandBsFullEvs, "AOD", "HFCANDBSFULLEV", collision::BCId, @@ -160,7 +160,7 @@ DECLARE_SOA_TABLE(HfCandBsFullPs, "AOD", "HFCANDBSFULLP", full::Eta, full::Phi, full::Y, - hf_cand_bs::FlagMcMatchGen); + hf_cand_mc_flag::FlagMcMatchGen); } // namespace o2::aod /// Writes the full information in an output TTree @@ -183,8 +183,8 @@ struct HfTreeCreatorBsToDsPi { Filter filterSelectCandidates = aod::hf_sel_candidate_bs::isSelBsToDsPi >= selectionFlagBs; - Partition recSig = nabs(aod::hf_cand_bs::flagMcMatchRec) == static_cast(DecayChannelMain::BsToDsPi); - Partition recBg = nabs(aod::hf_cand_bs::flagMcMatchRec) != static_cast(DecayChannelMain::BsToDsPi); + Partition recSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(DecayChannelMain::BsToDsPi); + Partition recBg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(DecayChannelMain::BsToDsPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx index 7ad269131f9..49656d8c364 100644 --- a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx @@ -249,17 +249,17 @@ struct HfTreeCreatorD0ToKPi { using MatchedGenCandidatesMc = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; - Filter filterMcGenMatching = nabs(aod::hf_cand_2prong::flagMcMatchGen) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && (nabs(aod::hf_cand_2prong::flagMcMatchGen) != 0)); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && (nabs(aod::hf_cand_mc_flag::flagMcMatchGen) != 0)); - Partition reconstructedCandSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); - Partition reconstructedCandBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition reconstructedCandSigKF = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); - Partition reconstructedCandBkgKF = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition reconstructedCandSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != 0); + Partition reconstructedCandBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition reconstructedCandSigKF = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != 0); + Partition reconstructedCandBkgKF = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition reconstructedCandSigMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); - Partition reconstructedCandBkgMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition reconstructedCandSigKFMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); - Partition reconstructedCandBkgKFMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition reconstructedCandSigMl = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != 0); + Partition reconstructedCandBkgMl = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition reconstructedCandSigKFMl = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != 0); + Partition reconstructedCandBkgKFMl = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx b/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx index 97978baac1e..d301cee0752 100644 --- a/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx @@ -147,9 +147,9 @@ DECLARE_SOA_TABLE(HfCandDpLites, "AOD", "HFCANDDPLITE", full::Y, full::Centrality, collision::NumContrib, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::FlagMcDecayChanRec) + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec) DECLARE_SOA_TABLE(HfCandDpFulls, "AOD", "HFCANDDPFULL", collision::NumContrib, @@ -228,9 +228,9 @@ DECLARE_SOA_TABLE(HfCandDpFulls, "AOD", "HFCANDDPFULL", full::Y, full::E, full::Centrality, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::FlagMcDecayChanRec); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec); DECLARE_SOA_TABLE(HfCandDpFullEvs, "AOD", "HFCANDDPFULLEV", collision::NumContrib, @@ -245,9 +245,9 @@ DECLARE_SOA_TABLE(HfCandDpFullPs, "AOD", "HFCANDDPFULLP", full::Eta, full::Phi, full::Y, - hf_cand_3prong::FlagMcMatchGen, - hf_cand_3prong::FlagMcDecayChanGen, - hf_cand_3prong::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::FlagMcDecayChanGen, + hf_cand_mc_flag::OriginMcGen); } // namespace o2::aod /// Writes the full information in an output TTree @@ -277,11 +277,11 @@ struct HfTreeCreatorDplusToPiKPi { using CollisionsCent = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - Filter filterMcGenMatching = (nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) != 0)); + Filter filterMcGenMatching = (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchGen) != 0)); - Partition reconstructedCandSig = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchRec) != 0)); - Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); - Partition reconstructedCandSigMl = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchRec) != 0)); + Partition reconstructedCandSig = (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchRec) != 0)); + Partition reconstructedCandBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition reconstructedCandSigMl = (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_mc_flag::flagMcMatchRec) != 0)); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx b/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx index 90dfa44d771..57d484a63b1 100644 --- a/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx @@ -146,10 +146,10 @@ DECLARE_SOA_TABLE(HfCandDsLites, "AOD", "HFCANDDSLITE", hf_cand::Chi2PCA, full::Centrality, collision::NumContrib, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::FlagMcDecayChanRec, - hf_cand_3prong::IsCandidateSwapped, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::IsCandidateSwapped, full::Sign); DECLARE_SOA_TABLE(HfCandDsFulls, "AOD", "HFCANDDSFULL", @@ -219,10 +219,10 @@ DECLARE_SOA_TABLE(HfCandDsFulls, "AOD", "HFCANDDSFULL", full::AbsCos3PiK, hf_cand::Chi2PCA, full::Centrality, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec, - hf_cand_3prong::FlagMcDecayChanRec, - hf_cand_3prong::IsCandidateSwapped, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, + hf_cand_mc_flag::FlagMcDecayChanRec, + hf_cand_mc_flag::IsCandidateSwapped, full::Sign); DECLARE_SOA_TABLE(HfCandDsFullEvs, "AOD", "HFCANDDSFULLEV", @@ -241,8 +241,8 @@ DECLARE_SOA_TABLE(HfCandDsFullPs, "AOD", "HFCANDDSFULLP", full::Eta, full::Phi, full::Y, - hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcGen); + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcGen); } // namespace o2::aod enum Mother : int8_t { @@ -289,18 +289,18 @@ struct HfTreeCreatorDsToKKPi { Filter filterSelectCandidates = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; Filter filterMcGenMatching = - nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && - (aod::hf_cand_3prong::flagMcDecayChanGen == channelsResonant[Mother::Ds][decayChannel] || - (fillDplusMc && aod::hf_cand_3prong::flagMcDecayChanGen == channelsResonant[Mother::Dplus][decayChannel])); // Do not store Dplus MC if fillDplusMc is false + nabs(o2::aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && + (aod::hf_cand_mc_flag::flagMcDecayChanGen == channelsResonant[Mother::Ds][decayChannel] || + (fillDplusMc && aod::hf_cand_mc_flag::flagMcDecayChanGen == channelsResonant[Mother::Dplus][decayChannel])); // Do not store Dplus MC if fillDplusMc is false Partition selectedDsToKKPiCand = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs; Partition selectedDsToPiKKCand = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; - Partition reconstructedCandSig = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec == channelsResonant[Mother::Ds][decayChannel]) || (fillDplusMc && nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec == channelsResonant[Mother::Dplus][decayChannel]); // Do not store Dplus MC if fillDplusMc is false - Partition reconstructedCandBkg = (nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK)) || - (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec != channelsResonant[Mother::Ds][decayChannel]) || - (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec != channelsResonant[Mother::Dplus][decayChannel]) || - (!fillDplusMc && nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec == channelsResonant[Mother::Dplus][decayChannel]); + Partition reconstructedCandSig = (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && aod::hf_cand_mc_flag::flagMcDecayChanRec == channelsResonant[Mother::Ds][decayChannel]) || (fillDplusMc && nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_mc_flag::flagMcDecayChanRec == channelsResonant[Mother::Dplus][decayChannel]); // Do not store Dplus MC if fillDplusMc is false + Partition reconstructedCandBkg = (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK)) || + (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && aod::hf_cand_mc_flag::flagMcDecayChanRec != channelsResonant[Mother::Ds][decayChannel]) || + (nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_mc_flag::flagMcDecayChanRec != channelsResonant[Mother::Dplus][decayChannel]) || + (!fillDplusMc && nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_mc_flag::flagMcDecayChanRec == channelsResonant[Mother::Dplus][decayChannel]); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx b/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx index 059c3ed8f11..9cdbc18b889 100644 --- a/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx @@ -153,8 +153,8 @@ DECLARE_SOA_TABLE(HfCandDstLites, "AOD", "HFCANDDSTLITE", full::Phi, full::Y, full::CandidateSelFlag, - hf_cand_dstar::FlagMcMatchRec, - hf_cand_dstar::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, full::PtBhadMother) DECLARE_SOA_TABLE(HfCandDstFulls, "AOD", "HFCANDDSTFULL", @@ -226,8 +226,8 @@ DECLARE_SOA_TABLE(HfCandDstFulls, "AOD", "HFCANDDSTFULL", full::Y, full::E, full::CandidateSelFlag, - hf_cand_dstar::FlagMcMatchRec, - hf_cand_dstar::OriginMcRec, + hf_cand_mc_flag::FlagMcMatchRec, + hf_cand_mc_flag::OriginMcRec, full::PtBhadMother); DECLARE_SOA_TABLE(HfCandDstFullEvs, "AOD", "HFCANDDSTFULLEV", @@ -245,8 +245,8 @@ DECLARE_SOA_TABLE(HfCandDstFullPs, "AOD", "HFCANDDSTFULLP", full::Eta, full::Phi, full::Y, - hf_cand_dstar::FlagMcMatchGen, - hf_cand_dstar::OriginMcGen, + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, full::PtBhadMother); } // namespace o2::aod @@ -272,10 +272,10 @@ struct HfTreeCreatorDstarToD0Pi { using CandDstarMcGen = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstarToD0Pi; - Filter filterMcGenMatching = nabs(aod::hf_cand_dstar::flagMcMatchGen) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Filter filterMcGenMatching = nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); - Partition reconstructedCandSig = nabs(aod::hf_cand_dstar::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); - Partition reconstructedCandBkg = nabs(aod::hf_cand_dstar::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition reconstructedCandSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition reconstructedCandBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorOmegacSt.cxx b/PWGHF/TableProducer/treeCreatorOmegacSt.cxx index 448e67f7eec..5fb90429589 100644 --- a/PWGHF/TableProducer/treeCreatorOmegacSt.cxx +++ b/PWGHF/TableProducer/treeCreatorOmegacSt.cxx @@ -10,11 +10,12 @@ // or submit itself to any jurisdiction. /// \file treeCreatorOmegacSt.cxx -/// \brief Task to reconstruct Ωc from strangeness-tracked Ω and pion/kaon +/// \brief Task to reconstruct Ωc/Ξc from strangeness-tracked Ω/Ξ and pion/kaon /// /// \author Jochen Klein /// \author Tiantian Cheng +#include "PWGHF/Core/DecayChannelsLegacy.h" #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsTrkCandHf.h" #include "PWGLF/DataModel/LFStrangenessTables.h" @@ -306,6 +307,8 @@ struct HfTreeCreatorOmegacSt { {"hMassOmegaPiVsPt", "inv. mass #Omega + #pi;inv. mass (GeV/#it{c}^{2});p_{T} (GeV/#it{c})", {HistType::kTH2D, {{400, 1.5, 3.}, {10, 0., 10.}}}}, {"hMassOmegaK", "inv. mass #Omega + K;inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, {"hMassOmegaKVsPt", "inv. mass #Omega + K;inv. mass (GeV/#it{c}^{2});p_{T} (GeV/#it{c})", {HistType::kTH2D, {{400, 1.5, 3.}, {10, 0., 10.}}}}, + {"hMassXiPi", "inv. mass #Xi + #pi;inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.2, 3.2}}}}, + {"hMassXiPiVsPt", "inv. mass #Xi + #pi;inv. mass (GeV/#it{c}^{2});p_{T} (GeV/#it{c})", {HistType::kTH2D, {{400, 1.2, 3.2}, {10, 0., 10.}}}}, {"hMassOmegacId", "inv. mass #Omega + #pi (MC ID);inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, {"hMassOmegacGen", "inv. mass #Omega + #pi (from MC);inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, {"hPtVsMassOmega", "#Omega mass;p_{T} (GeV/#it{c});m (GeV/#it{c}^3)", {HistType::kTH2D, {{200, 0., 10.}, {1000, 1., 3.}}}}, @@ -366,70 +369,111 @@ struct HfTreeCreatorOmegacSt { for (const auto& mcParticle : mcParticles) { const bool isOmegaC = std::abs(mcParticle.pdgCode()) == constants::physics::Pdg::kOmegaC0; const bool isXiC = std::abs(mcParticle.pdgCode()) == constants::physics::Pdg::kXiC0; - if (isOmegaC || isXiC) { - const auto daughters = mcParticle.daughters_as(); - if (daughters.size() == NDaughters) { - int idxPionDaughter = -1; - int idxCascDaughter = -1; - int idxKaonDaughter = -1; - const auto daughters = mcParticle.daughters_as(); - for (const auto& daughter : daughters) { - if (idxCascDaughter < 0 && (std::abs(daughter.pdgCode()) == (isOmegaC ? kOmegaMinus : kXiMinus))) { - idxCascDaughter = daughter.globalIndex(); - } - if (idxPionDaughter < 0 && (std::abs(daughter.pdgCode()) == kPiPlus)) { - idxPionDaughter = daughter.globalIndex(); - } - if (idxKaonDaughter < 0 && (std::abs(daughter.pdgCode()) == kKPlus)) { - idxKaonDaughter = daughter.globalIndex(); - } - } - if (idxPionDaughter >= 0 && idxCascDaughter >= 0) { - decayChannel = o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi; // OmegaC -> Omega + Pi - } else if (idxKaonDaughter >= 0 && idxCascDaughter >= 0) { - decayChannel = o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK; // OmegaC -> Omega + K - } else { - decayChannel = -1; // LOG(warning) << "Decay channel not recognized!"; + if (!isOmegaC && !isXiC) { + continue; + } + const auto daughters = mcParticle.daughters_as(); + if (daughters.size() != NDaughters) { + continue; + } + int idxPionDaughter = -1; + int idxCascDaughter = -1; + int idxKaonDaughter = -1; + for (const auto& daughter : daughters) { + const int absDauPdg = std::abs(daughter.pdgCode()); + if (idxCascDaughter < 0) { + if (absDauPdg == kOmegaMinus || absDauPdg == kXiMinus) { + idxCascDaughter = daughter.globalIndex(); } - if (decayChannel != -1) { - int const idxDaughter = (decayChannel == o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) ? idxPionDaughter : idxKaonDaughter; - auto particle = mcParticles.rawIteratorAt(idxDaughter); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (idxPionDaughter < 0 && absDauPdg == kPiPlus) { + idxPionDaughter = daughter.globalIndex(); + } + if (idxKaonDaughter < 0 && absDauPdg == kKPlus) { + idxKaonDaughter = daughter.globalIndex(); + } + } - const auto& cascDaughter = mcParticles.iteratorAt(idxCascDaughter); - const auto& mcColl = mcParticle.mcCollision(); - std::array const primaryVertexPosGen = {mcColl.posX(), mcColl.posY(), mcColl.posZ()}; - std::array const secondaryVertexGen = {cascDaughter.vx(), cascDaughter.vy(), cascDaughter.vz()}; - float decayLengthCascGen = -1.; - float decayLengthXYCascGen = -1.; - if (cascDaughter.has_daughters()) { - const auto& cascDecayDaughter = cascDaughter.daughters_as().iteratorAt(0); - std::array const tertiaryVertexGen = {cascDecayDaughter.vx(), cascDecayDaughter.vy(), cascDecayDaughter.vz()}; - decayLengthCascGen = RecoDecay::distance(tertiaryVertexGen, primaryVertexPosGen); - decayLengthXYCascGen = RecoDecay::distanceXY(tertiaryVertexGen, primaryVertexPosGen); - } - const auto decayLengthGen = RecoDecay::distance(secondaryVertexGen, primaryVertexPosGen); - const auto decayLengthXYGen = RecoDecay::distanceXY(secondaryVertexGen, primaryVertexPosGen); - registry.fill(HIST("hDecayLengthScaledMc"), decayLengthGen * o2::constants::physics::MassOmegaC0 / mcParticle.mothers_first_as().p() * 1e4); - outputTableGen( - mcParticle.px(), - mcParticle.py(), - mcParticle.pz(), - mcParticle.pdgCode(), - cascDaughter.px(), - cascDaughter.py(), - cascDaughter.pz(), - cascDaughter.pdgCode(), - decayLengthGen, - decayLengthXYGen, - decayLengthCascGen, - decayLengthXYCascGen, - origin, - decayChannel); - mapMcPartToGenTable[mcParticle.globalIndex()] = outputTableGen.lastIndex(); + if (idxCascDaughter < 0) { + continue; + } + + int decayChannel = -1; + const int pdgCasc = std::abs(mcParticles.iteratorAt(idxCascDaughter).pdgCode()); + + if (isOmegaC) { + // Omegac0 -> Omega- pi+ or Xi- pi+ + if (idxPionDaughter >= 0) { + if (pdgCasc == kOmegaMinus) { + decayChannel = o2::aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi; + } else if (pdgCasc == kXiMinus) { + decayChannel = o2::aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi; } } + } else if (isXiC) { + // Xic0 -> Omega- K+ or Xi- pi+ + if (pdgCasc == kOmegaMinus && idxKaonDaughter >= 0) { + decayChannel = o2::aod::hf_cand_xic0_omegac0::DecayType::XiczeroToOmegaK; + } else if (pdgCasc == kXiMinus && idxPionDaughter >= 0) { + decayChannel = o2::aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi; + } + } + + if (decayChannel == -1) { + continue; + } + + int idxDaughter = -1; + switch (decayChannel) { + case o2::aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi: + case o2::aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi: + case o2::aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi: + idxDaughter = idxPionDaughter; + break; + case o2::aod::hf_cand_xic0_omegac0::DecayType::XiczeroToOmegaK: + idxDaughter = idxKaonDaughter; + break; + default: + idxDaughter = -1; + break; + } + + if (idxDaughter >= 0) { + auto particle = mcParticles.rawIteratorAt(idxDaughter); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } + + const auto& cascDaughter = mcParticles.iteratorAt(idxCascDaughter); + const auto& mcColl = mcParticle.mcCollision(); + std::array const primaryVertexPosGen = {mcColl.posX(), mcColl.posY(), mcColl.posZ()}; + std::array const secondaryVertexGen = {cascDaughter.vx(), cascDaughter.vy(), cascDaughter.vz()}; + float decayLengthCascGen = -1.; + float decayLengthXYCascGen = -1.; + if (cascDaughter.has_daughters()) { + const auto& cascDecayDaughter = cascDaughter.daughters_as().iteratorAt(0); + std::array const tertiaryVertexGen = {cascDecayDaughter.vx(), cascDecayDaughter.vy(), cascDecayDaughter.vz()}; + decayLengthCascGen = RecoDecay::distance(tertiaryVertexGen, primaryVertexPosGen); + decayLengthXYCascGen = RecoDecay::distanceXY(tertiaryVertexGen, primaryVertexPosGen); + } + const auto decayLengthGen = RecoDecay::distance(secondaryVertexGen, primaryVertexPosGen); + const auto decayLengthXYGen = RecoDecay::distanceXY(secondaryVertexGen, primaryVertexPosGen); + registry.fill(HIST("hDecayLengthScaledMc"), decayLengthGen * o2::constants::physics::MassOmegaC0 / mcParticle.mothers_first_as().p() * 1e4); + outputTableGen( + mcParticle.px(), + mcParticle.py(), + mcParticle.pz(), + mcParticle.pdgCode(), + cascDaughter.px(), + cascDaughter.py(), + cascDaughter.pz(), + cascDaughter.pdgCode(), + decayLengthGen, + decayLengthXYGen, + decayLengthCascGen, + decayLengthXYCascGen, + origin, + decayChannel); + mapMcPartToGenTable[mcParticle.globalIndex()] = outputTableGen.lastIndex(); } } PROCESS_SWITCH(HfTreeCreatorOmegacSt, processMc, "Process MC", true); @@ -476,7 +520,6 @@ struct HfTreeCreatorOmegacSt { } } } - const auto primaryVertex = getPrimaryVertex(collision); const std::array primaryVertexPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; @@ -570,7 +613,6 @@ struct HfTreeCreatorOmegacSt { const auto massXi = RecoDecay::m(momentaCascDaughters, massesXiDaughters); std::array const massesOmegaDaughters = {o2::constants::physics::MassLambda0, o2::constants::physics::MassKPlus}; const auto massOmega = RecoDecay::m(momentaCascDaughters, massesOmegaDaughters); - registry.fill(HIST("hDca"), std::sqrt(impactParameterCasc.getR2())); registry.fill(HIST("hDcaXY"), impactParameterCasc.getY()); registry.fill(HIST("hDcaXYVsPt"), trackParCovCasc.getPt(), impactParameterCasc.getY()); @@ -588,7 +630,8 @@ struct HfTreeCreatorOmegacSt { std::array const massesOmegacToOmegaPi{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassPiPlus}; std::array const massesOmegacToOmegaK{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassKPlus}; - std::array const massesXicDaughters{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus}; + // std::array const massesXicDaughters{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus}; + std::array massesXicOrOmegacToXiPi{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus}; std::array, NDaughters> momenta{}; auto trackParCovPr = getTrackParCov(v0TrackPr); @@ -662,11 +705,15 @@ struct HfTreeCreatorOmegacSt { df2.getTrackParamAtPCA(1).getPxPyPzGlo(momenta[1]); const auto massOmegaPi = RecoDecay::m(momenta, massesOmegacToOmegaPi); const auto massOmegaK = RecoDecay::m(momenta, massesOmegacToOmegaK); - const auto massXiC = RecoDecay::m(momenta, massesXicDaughters); + // const auto massXiC = RecoDecay::m(momenta, massesXicDaughters); + const auto massXiPi = RecoDecay::m(momenta, massesXicOrOmegacToXiPi); + registry.fill(HIST("hMassOmegaPi"), massOmegaPi); registry.fill(HIST("hMassOmegaPiVsPt"), massOmegaPi, RecoDecay::pt(momenta[0], momenta[1])); registry.fill(HIST("hMassOmegaK"), massOmegaK); registry.fill(HIST("hMassOmegaKVsPt"), massOmegaK, RecoDecay::pt(momenta[0], momenta[1])); + registry.fill(HIST("hMassXiPi"), massXiPi); + registry.fill(HIST("hMassXiPiVsPt"), massXiPi, RecoDecay::pt(momenta[0], momenta[1])); //--- do the MC Rec match if (mcParticles) { @@ -684,7 +731,7 @@ struct HfTreeCreatorOmegacSt { v0.posTrack_as(), // p <- lambda v0.negTrack_as()}; // pi <- lambda - if (decayChannel == o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { + if (decayChannel == o2::aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi) { // Match Omegac0 → Omega- + Pi+ indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughters, o2::constants::physics::kOmegaC0, std::array{+kPiPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3, &nPiToMuOmegac0, &nKaToPiOmegac0); @@ -700,17 +747,65 @@ struct HfTreeCreatorOmegacSt { } } } - } else if (decayChannel == o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK) { - // Match Omegac0 → Omega- + K+ + // } else if (decayChannel == o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK) { + // // Match Omegac0 → Omega- + K+ + // indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughters, o2::constants::physics::kOmegaC0, + // std::array{+kKPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3, &nPiToMuOmegac0, &nKaToPiOmegac0); + // indexRecCharmBaryon = indexRec; + // if (indexRec > -1) { + // // Omega- → K pi p (Cascade match) + // indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2, &nPiToMuCasc, &nKaToPiCasc); + // if (indexRec > -1) { + // // Lambda → p pi (Lambda match) + // indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1, &nPiToMuV0); + // if (indexRec > -1) { + // isMatched = true; + // } + // } + // } + } else if (decayChannel == o2::aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi) { + // Match Omegac0 -> Xi Pion indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughters, o2::constants::physics::kOmegaC0, - std::array{+kKPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3, &nPiToMuOmegac0, &nKaToPiOmegac0); + std::array{+kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 3); + indexRecCharmBaryon = indexRec; + if (indexRec > -1) { + // Xi- → pi pi p (Cascade match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &signCasc, 2); + if (indexRec > -1) { + // Lambda → p pi (Lambda match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); + if (indexRec > -1) { + isMatched = true; + } + } + } + } else if (decayChannel == o2::aod::hf_cand_xic0_omegac0::DecayType::XiczeroToOmegaK) { + // Match Xic0 → Omega- + K+ + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughters, o2::constants::physics::kXiC0, + std::array{+kKPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3); indexRecCharmBaryon = indexRec; if (indexRec > -1) { // Omega- → K pi p (Cascade match) - indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2, &nPiToMuCasc, &nKaToPiCasc); + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2); if (indexRec > -1) { // Lambda → p pi (Lambda match) - indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1, &nPiToMuV0); + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); + if (indexRec > -1) { + isMatched = true; + } + } + } + } else if (decayChannel == o2::aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + // Match Xic0 -> Xi Pion + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughters, o2::constants::physics::kXiC0, + std::array{+kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 3); + indexRecCharmBaryon = indexRec; + if (indexRec > -1) { + // Xi- → pi pi p (Cascade match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &signCasc, 2); + if (indexRec > -1) { + // Lambda → p pi (Lambda match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); if (indexRec > -1) { isMatched = true; } @@ -723,9 +818,12 @@ struct HfTreeCreatorOmegacSt { } } - if ((std::abs(massOmegaK - o2::constants::physics::MassOmegaC0) < massWindowOmegaC) || + if ((std::abs(massOmegaK - o2::constants::physics::MassXiC0) < massWindowXiC) || (std::abs(massOmegaPi - o2::constants::physics::MassOmegaC0) < massWindowOmegaC) || - (std::abs(massXiC - o2::constants::physics::MassXiC0) < massWindowXiC)) { + (std::abs(massXiPi - o2::constants::physics::MassXiC0) < massWindowXiC) || + (std::abs(massXiPi - o2::constants::physics::MassOmegaC0) < massWindowOmegaC) + + ) { registry.fill(HIST("hDecayLength"), decayLength * 1e4); registry.fill(HIST("hDecayLengthScaled"), decayLength * o2::constants::physics::MassOmegaC0 / RecoDecay::p(momenta[0], momenta[1]) * 1e4); outputTable(massOmega, diff --git a/PWGHF/TableProducer/treeCreatorSigmacCorrBkg.cxx b/PWGHF/TableProducer/treeCreatorSigmacCorrBkg.cxx index 212d6e597a6..98fbc5f13c3 100644 --- a/PWGHF/TableProducer/treeCreatorSigmacCorrBkg.cxx +++ b/PWGHF/TableProducer/treeCreatorSigmacCorrBkg.cxx @@ -55,8 +55,11 @@ enum Decays { Sigmac2455Pi = 0, LambdacPiPi }; enum DecaysLambdac { PKPi = 0, PiKP }; +enum Reflections { NotReflected = 0, + Reflected }; DECLARE_SOA_COLUMN(Y, y, float); DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(PtLc, ptLc, float); DECLARE_SOA_COLUMN(Mass, mass, float); DECLARE_SOA_COLUMN(DeltaMass, deltaMass, float); DECLARE_SOA_COLUMN(Charge, charge, int8_t); @@ -65,10 +68,13 @@ DECLARE_SOA_COLUMN(Decay, decay, int8_t); DECLARE_SOA_COLUMN(DecayLambdac, decayLambdac, int8_t); DECLARE_SOA_COLUMN(MlScoreFirstClass, mlScoreFirstClass, float); /// background score Λc DECLARE_SOA_COLUMN(MlScoreThirdClass, mlScoreThirdClass, float); /// non-prompt score Λc +DECLARE_SOA_COLUMN(IsReflected, isReflected, int8_t); +DECLARE_SOA_COLUMN(Origin, origin, int8_t); } // namespace hf_sigmac_bkg DECLARE_SOA_TABLE(HfCorrBkgSc, "AOD", "HFCORRBKGSC", hf_sigmac_bkg::Y, hf_sigmac_bkg::Pt, + hf_sigmac_bkg::PtLc, hf_sigmac_bkg::Mass, hf_sigmac_bkg::DeltaMass, hf_sigmac_bkg::Charge, @@ -76,23 +82,37 @@ DECLARE_SOA_TABLE(HfCorrBkgSc, "AOD", "HFCORRBKGSC", hf_sigmac_bkg::Decay, hf_sigmac_bkg::DecayLambdac, hf_sigmac_bkg::MlScoreFirstClass, - hf_sigmac_bkg::MlScoreThirdClass); + hf_sigmac_bkg::MlScoreThirdClass, + hf_sigmac_bkg::IsReflected); +DECLARE_SOA_TABLE(HfGenBkgSc, "AOD", "HFGENBKGSC", + hf_sigmac_bkg::Y, + hf_sigmac_bkg::Pt, + hf_sigmac_bkg::MotherPdg, + hf_sigmac_bkg::Origin); } // namespace o2::aod struct HfTreeCreatorSigmacCorrBkg { Produces rowCorrBkgSc; + Produces rowGenBkgSc; /// Selection of candidates Λc+ Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; Configurable yCandRecoMax{"yCandRecoMax", -1, "Maximum Sc candidate rapidity"}; + Configurable keepReflectedSignals{"keepReflectedSignals", false, "Keep also the reflected signals (i.e. generated pKpi reco as piKp, and viceversa)"}; using RecoLcMc = soa::Join; using RecoScMc = soa::Join; using ParticlesLcSigmac = soa::Join; /// @brief init function - void init(InitContext&) {} + void init(InitContext&) + { + std::array doprocesses{doprocessReco, doprocessGen}; + if (std::accumulate(doprocesses.begin(), doprocesses.end(), 0) == 0) { + LOGP(fatal, "No process function enabled. Aborting..."); + } + } /// void fillTable(RecoScMc::iterator candidateSc, RecoLcMc::iterator candLcDauSc, int motherPdg, int motherDecay = -1) @@ -103,41 +123,66 @@ struct HfTreeCreatorSigmacCorrBkg { float massLc = -1.f; float deltaMass = -1.f; const int8_t isCandPKPiPiKP = hf_sigmac_utils::isDecayToPKPiToPiKP(candLcDauSc, candidateSc); - std::array outputMl{-1., -1.}; + std::array outputMlLcPKPi{-1., -1.}; + std::array outputMlLcPiKP{-1., -1.}; + const float ptSc = candidateSc.pt(); + const float ptLcDauSc = candLcDauSc.pt(); /// rapidity selection on Σc0,++ if (yCandRecoMax >= 0. && std::abs(rapidity) > yCandRecoMax) { return; } /// BDT scores + // reconstructed Λc± → pK-π+ + if (!candLcDauSc.mlProbLcToPKPi().empty()) { + outputMlLcPKPi.at(0) = candLcDauSc.mlProbLcToPKPi()[0]; /// bkg score + outputMlLcPKPi.at(1) = candLcDauSc.mlProbLcToPKPi()[2]; /// non-prompt score + } + // reconstructed Λc± → π+K-p if (!candLcDauSc.mlProbLcToPiKP().empty()) { - outputMl.at(0) = candLcDauSc.mlProbLcToPiKP()[0]; /// bkg score - outputMl.at(1) = candLcDauSc.mlProbLcToPiKP()[2]; /// non-prompt score + outputMlLcPiKP.at(0) = candLcDauSc.mlProbLcToPiKP()[0]; /// bkg score + outputMlLcPiKP.at(1) = candLcDauSc.mlProbLcToPiKP()[2]; /// non-prompt score } - if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PKPi)) && std::abs(candLcDauSc.template prong0_as().template mcParticle_as().pdgCode()) == kProton) { + int pdgCodeProng0Abs = std::abs(candLcDauSc.template prong0_as().template mcParticle_as().pdgCode()); + + /// candidates with Λc± reconstructed in the pK-π+ decay + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PKPi))) { + massSc = HfHelper::invMassScRecoLcToPKPi(candidateSc, candLcDauSc); massLc = HfHelper::invMassLcToPKPi(candLcDauSc); deltaMass = massSc - massLc; - /// fill the tree - rowCorrBkgSc(rapidity, candidateSc.pt(), massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PKPi, outputMl.at(0), outputMl.at(1)); + if (pdgCodeProng0Abs == kProton) { + /// candidates with reconstructed Λc± → pK-π+ decay that are generated Λc± → pK-π+ (not reflected) + rowCorrBkgSc(rapidity, ptSc, ptLcDauSc, massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PKPi, outputMlLcPKPi.at(0), outputMlLcPKPi.at(1), aod::hf_sigmac_bkg::Reflections::NotReflected); + } else if (keepReflectedSignals && pdgCodeProng0Abs == kPiPlus) { + /// candidates with reconstructed Λc± → pK-π+ decay that are actually generated Λc± → π+K-p (reflected) + rowCorrBkgSc(rapidity, ptSc, ptLcDauSc, massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PKPi, outputMlLcPKPi.at(0), outputMlLcPKPi.at(1), aod::hf_sigmac_bkg::Reflections::Reflected); + } } - if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PiKP)) && std::abs(candLcDauSc.template prong0_as().template mcParticle_as().pdgCode()) == kPiPlus) { + /// candidates with Λc± reconstructed in the π+K-p decay + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PiKP))) { + massSc = HfHelper::invMassScRecoLcToPiKP(candidateSc, candLcDauSc); massLc = HfHelper::invMassLcToPiKP(candLcDauSc); deltaMass = massSc - massLc; - /// fill the tree - rowCorrBkgSc(rapidity, candidateSc.pt(), massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PiKP, outputMl.at(0), outputMl.at(1)); + if (pdgCodeProng0Abs == kPiPlus) { + /// candidates with reconstructed Λc± → π+K-p decay that are generated Λc± → π+K-p (not reflected) + rowCorrBkgSc(rapidity, ptSc, ptLcDauSc, massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PiKP, outputMlLcPiKP.at(0), outputMlLcPiKP.at(1), aod::hf_sigmac_bkg::Reflections::NotReflected); + } else if (keepReflectedSignals && pdgCodeProng0Abs == kProton) { + /// candidates with reconstructed Λc± → π+K-p decay that are actually generated Λc± → pK-π+ (reflected) + rowCorrBkgSc(rapidity, ptSc, ptLcDauSc, massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PiKP, outputMlLcPiKP.at(0), outputMlLcPiKP.at(1), aod::hf_sigmac_bkg::Reflections::Reflected); + } } } /// @brief process function to loop over the Σc reconstructed candidates and match them to corr. background sources in MC - void process(RecoScMc const& candidatesSc, - ParticlesLcSigmac const& particles, - RecoLcMc const&, - aod::TracksWMc const&) + void processReco(RecoScMc const& candidatesSc, + ParticlesLcSigmac const& particles, + RecoLcMc const&, + aod::TracksWMc const&) { /// loop over reconstructed Σc candidates for (auto const& candidateSc : candidatesSc) { @@ -303,6 +348,29 @@ struct HfTreeCreatorSigmacCorrBkg { } /// end loop over reconstructed Σc candidates } + PROCESS_SWITCH(HfTreeCreatorSigmacCorrBkg, processReco, "Process Reco MC", false); + + /// @brief process function to look for generated Σc and Λc±(2595, 2625) (needed to properly normalize the bkg templates) + void processGen(aod::McParticles const& particles) + { + /// loop over particles + for (auto const& particle : particles) { + int pdgCodeAbs = std::abs(particle.pdgCode()); + + /// keep only Σc and Λc±(2595, 2625) + if (pdgCodeAbs != o2::constants::physics::Pdg::kSigmaC0 && pdgCodeAbs != o2::constants::physics::Pdg::kSigmaCPlusPlus && pdgCodeAbs != o2::constants::physics::Pdg::kSigmaCStar0 && pdgCodeAbs != o2::constants::physics::Pdg::kSigmaCStarPlusPlus && pdgCodeAbs != aod::hf_sigmac_bkg::pdgCodeLambdac2595 && pdgCodeAbs != aod::hf_sigmac_bkg::pdgCodeLambdac2625) { + continue; + } + + /// if we arrive here, it means that the particle is either a Σc or Λc±(2595, 2625) + /// let's check the origin (prompt, non-prompt) + int8_t origin = static_cast(RecoDecay::getCharmHadronOrigin(particles, particle, false)); + + /// let's fill the table + rowGenBkgSc(particle.y(), particle.pt(), pdgCodeAbs, origin); + } /// end loop over particles + } + PROCESS_SWITCH(HfTreeCreatorSigmacCorrBkg, processGen, "Process generated MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx b/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx index 81543b0e7bf..8cdba2fe442 100644 --- a/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx @@ -239,13 +239,13 @@ struct HfTreeCreatorXicToPKPi { using CandXicMcGen = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic || aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic; - Filter filterMcGenMatching = nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); + Filter filterMcGenMatching = nabs(o2::aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); Partition selectedXicToPKPiCand = aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic; Partition selectedXicToPiKPCand = aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic; - Partition reconstructedCandSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); - Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); + Partition reconstructedCandSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); + Partition reconstructedCandBkg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); void init(InitContext const&) { diff --git a/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx index 3d0500c3690..47748b4c30d 100644 --- a/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx @@ -44,7 +44,7 @@ namespace o2::aod { namespace full { -DECLARE_SOA_COLUMN(ParticleFlag, particleFlag, int8_t); //! hf_cand_xic_to_xi_pi_pi::Sign for data, hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec for MC +DECLARE_SOA_COLUMN(ParticleFlag, particleFlag, int8_t); //! hf_cand_xic_to_xi_pi_pi::Sign for data, hf_cand_mc_flag::FlagMcMatchRec for MC DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int); //! Selection flag of candidate (output of candidateSelector) // vertices DECLARE_SOA_COLUMN(Chi2SV, chi2SV, float); //! Chi2 of candidate vertex @@ -82,7 +82,7 @@ DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); DECLARE_SOA_TABLE(HfCandXicToXiPiPiLites, "AOD", "HFXICXI2PILITE", full::ParticleFlag, - hf_cand_xic_to_xi_pi_pi::OriginMcRec, + hf_cand_mc_flag::OriginMcRec, full::CandidateSelFlag, full::Y, full::Eta, @@ -119,7 +119,7 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiLites, "AOD", "HFXICXI2PILITE", DECLARE_SOA_TABLE(HfCandXicToXiPiPiLiteKfs, "AOD", "HFXICXI2PILITKF", full::ParticleFlag, - hf_cand_xic_to_xi_pi_pi::OriginMcRec, + hf_cand_mc_flag::OriginMcRec, full::CandidateSelFlag, full::Y, full::Eta, @@ -188,7 +188,7 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiLiteKfs, "AOD", "HFXICXI2PILITKF", DECLARE_SOA_TABLE(HfCandXicToXiPiPiFulls, "AOD", "HFXICXI2PIFULL", full::ParticleFlag, - hf_cand_xic_to_xi_pi_pi::OriginMcRec, + hf_cand_mc_flag::OriginMcRec, full::CandidateSelFlag, full::Y, full::Eta, @@ -250,7 +250,7 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiFulls, "AOD", "HFXICXI2PIFULL", DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullKfs, "AOD", "HFXICXI2PIFULKF", full::ParticleFlag, - hf_cand_xic_to_xi_pi_pi::OriginMcRec, + hf_cand_mc_flag::OriginMcRec, full::CandidateSelFlag, full::Y, full::Eta, @@ -329,9 +329,9 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullKfs, "AOD", "HFXICXI2PIFULKF", hf_cand_xic_to_xi_pi_pi::DcaXYPi1Xi); DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullPs, "AOD", "HFXICXI2PIFULLP", - hf_cand_xic_to_xi_pi_pi::FlagMcMatchGen, - hf_cand_xic_to_xi_pi_pi::OriginMcGen, - hf_cand::PdgBhadMotherPart, + hf_cand_mc_flag::FlagMcMatchGen, + hf_cand_mc_flag::OriginMcGen, + hf_cand_mc_flag::PdgBhadMotherPart, full::Pt, full::Eta, full::Phi, @@ -363,12 +363,12 @@ struct HfTreeCreatorXicToXiPiPi { using MatchedGenXicToXiPiPi = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= selectionFlagXic; - Filter filterGenXicToXiPiPi = (nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi)) || nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi))); + Filter filterGenXicToXiPiPi = (nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi)) || nabs(aod::hf_cand_mc_flag::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi))); - Partition recSig = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) != int8_t(0); - Partition recBg = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) == int8_t(0); - Partition recSigKf = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) != int8_t(0); - Partition recBgKf = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) == int8_t(0); + Partition recSig = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != int8_t(0); + Partition recBg = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == int8_t(0); + Partition recSigKf = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) != int8_t(0); + Partition recBgKf = nabs(aod::hf_cand_mc_flag::flagMcMatchRec) == int8_t(0); void init(InitContext const&) { diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index cdc923ce96c..f30d99b5598 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -81,6 +81,8 @@ inline auto determineGapType(TCollision const& collision, float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) { using BCType = std::decay_t())>; + const float amplitudeThresholdsFDDA = -1.0f; // Not used in SGSelector, set to -1 to indicate unused + const float amplitudeThresholdsFDDC = -1.0f; // Not used in SGSelector, set to -1 to indicate unused // Configure SGSelector thresholds SGCutParHolder sgCuts; @@ -88,7 +90,7 @@ inline auto determineGapType(TCollision const& collision, sgCuts.SetMinNBCs(nBcsMin); sgCuts.SetNTracks(nContributorsPvMin, nContributorsPvMax); sgCuts.SetMaxFITtime(timeFitMax); - sgCuts.SetFITAmpLimits({amplitudeThresholdFV0A, amplitudeThresholdFT0A, amplitudeThresholdFT0C}); + sgCuts.SetFITAmpLimits({amplitudeThresholdFV0A, amplitudeThresholdFT0A, amplitudeThresholdFT0C, amplitudeThresholdsFDDA, amplitudeThresholdsFDDC}); // Get BC and BC range if (!collision.has_foundBC()) { diff --git a/PWGJE/Core/JetBkgSubUtils.cxx b/PWGJE/Core/JetBkgSubUtils.cxx index 32a2a0ed3bc..45f79a9fe97 100644 --- a/PWGJE/Core/JetBkgSubUtils.cxx +++ b/PWGJE/Core/JetBkgSubUtils.cxx @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -51,7 +52,7 @@ void JetBkgSubUtils::initialise() // Note: recommended to use R=0.2 jetDefBkg = fastjet::JetDefinition(algorithmBkg, jetBkgR, recombSchemeBkg, fastjet::Best); areaDefBkg = fastjet::AreaDefinition(fastjet::active_area_explicit_ghosts, ghostAreaSpec); - selRho = fastjet::SelectorEtaRange(bkgEtaMin, bkgEtaMax) && fastjet::SelectorPhiRange(bkgPhiMin, bkgPhiMax) && !fastjet::SelectorNHardest(nHardReject); // here we have to put rap range, to be checked! + selRho = fastjet::SelectorEtaRange(bkgEtaMin + jetBkgR, bkgEtaMax - jetBkgR) && fastjet::SelectorPhiRange(bkgPhiMin, bkgPhiMax) && !fastjet::SelectorNHardest(nHardReject); // here we have to put rap range, to be checked! } std::tuple JetBkgSubUtils::estimateRhoAreaMedian(const std::vector& inputParticles, bool doSparseSub) diff --git a/PWGJE/Core/JetDerivedDataUtilities.h b/PWGJE/Core/JetDerivedDataUtilities.h index 1d342bc8f96..113e240bc2b 100644 --- a/PWGJE/Core/JetDerivedDataUtilities.h +++ b/PWGJE/Core/JetDerivedDataUtilities.h @@ -51,9 +51,9 @@ enum JCollisionSel { selIsGoodZvtxFT0vsPV = 7, selNoCollInTimeRangeStandard = 8, selNoCollInRofStandard = 9, - selUpcSingleGapA = 10, - selUpcSingleGapC = 11, - selUpcDoubleGap = 12, + selUPCSingleGapA = 10, + selUPCSingleGapC = 11, + selUPCDoubleGap = 12, }; enum JCollisionSubGeneratorId { @@ -62,8 +62,9 @@ enum JCollisionSubGeneratorId { }; template -bool commonCollisionSelection(T const& collision, bool skipMBGapEvents = true, bool rctSelection = true, std::string rctLabel = "CBT_hadronPID", bool rejectLimitedAcceptanceRct = false, bool requireZDCRct = false) +bool selectCollision(T const& collision, const std::vector& eventSelectionMaskBits, bool skipMBGapEvents = true, bool rctSelection = true, std::string rctLabel = "CBT_hadronPID", bool rejectLimitedAcceptanceRct = false, bool requireZDCRct = false) { + if (skipMBGapEvents && collision.getSubGeneratorId() == JCollisionSubGeneratorId::mbGap) { return false; } @@ -72,22 +73,6 @@ bool commonCollisionSelection(T const& collision, bool skipMBGapEvents = true, b if (rctSelection && !rctChecker.checkTable(collision)) { // CBT_hadronPID given as default so that TOF is included in RCT selection to benefit from better timing for tracks. Impact of this for inclusive jets should be studied return false; } - return true; -} - -template -bool selectMcCollision(T const& mcCollision, bool skipMBGapEvents = true, bool rctSelection = true, std::string rctLabel = "CBT_hadronPID", bool rejectLimitedAcceptanceRct = false, bool requireZDCRct = false) -{ - return commonCollisionSelection(mcCollision, skipMBGapEvents, rctSelection, rctLabel, rejectLimitedAcceptanceRct, requireZDCRct); -} - -template -bool selectCollision(T const& collision, const std::vector& eventSelectionMaskBits, bool skipMBGapEvents = true, bool rctSelection = true, std::string rctLabel = "CBT_hadronPID", bool rejectLimitedAcceptanceRct = false, bool requireZDCRct = false) -{ - - if (!commonCollisionSelection(collision, skipMBGapEvents, rctSelection, rctLabel, rejectLimitedAcceptanceRct, requireZDCRct)) { - return false; - } if (eventSelectionMaskBits.size() == 0) { return true; } @@ -192,13 +177,13 @@ std::vector initialiseEventSelectionBits(const std::string& eventSelectionM eventSelectionMaskBits.push_back(JCollisionSel::selKINT7); } if (eventSelectionMasksContainSelection(eventSelectionMasks, "selUPCSingleGapA")) { - eventSelectionMaskBits.push_back(JCollisionSel::selUpcSingleGapA); + eventSelectionMaskBits.push_back(JCollisionSel::selUPCSingleGapA); } if (eventSelectionMasksContainSelection(eventSelectionMasks, "selUPCSingleGapC")) { - eventSelectionMaskBits.push_back(JCollisionSel::selUpcSingleGapC); + eventSelectionMaskBits.push_back(JCollisionSel::selUPCSingleGapC); } if (eventSelectionMasksContainSelection(eventSelectionMasks, "selUPCDoubleGap")) { - eventSelectionMaskBits.push_back(JCollisionSel::selUpcDoubleGap); + eventSelectionMaskBits.push_back(JCollisionSel::selUPCDoubleGap); } return eventSelectionMaskBits; @@ -239,14 +224,37 @@ uint16_t setEventSelectionBit(T const& collision, int upcSelectionResult = o2::a SETBIT(bit, JCollisionSel::selNoCollInRofStandard); } if (upcSelectionResult == o2::aod::sgselector::SingleGapA) { - SETBIT(bit, JCollisionSel::selUpcSingleGapA); + SETBIT(bit, JCollisionSel::selUPCSingleGapA); } if (upcSelectionResult == o2::aod::sgselector::SingleGapC) { - SETBIT(bit, JCollisionSel::selUpcSingleGapC); + SETBIT(bit, JCollisionSel::selUPCSingleGapC); } if (upcSelectionResult == o2::aod::sgselector::DoubleGap) { - SETBIT(bit, JCollisionSel::selUpcDoubleGap); + SETBIT(bit, JCollisionSel::selUPCDoubleGap); + } + + return bit; +} + +template +uint16_t setMCEventSelectionBit(T const& bc) +{ + uint16_t bit = 0; + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + SETBIT(bit, JCollisionSel::sel8); + SETBIT(bit, JCollisionSel::sel7); + SETBIT(bit, JCollisionSel::selKINT7); + SETBIT(bit, JCollisionSel::selTVX); } + SETBIT(bit, JCollisionSel::selNoTimeFrameBorder); + SETBIT(bit, JCollisionSel::selNoITSROFrameBorder); + SETBIT(bit, JCollisionSel::selNoSameBunchPileup); + SETBIT(bit, JCollisionSel::selIsGoodZvtxFT0vsPV); + SETBIT(bit, JCollisionSel::selNoCollInTimeRangeStandard); + SETBIT(bit, JCollisionSel::selNoCollInRofStandard); + SETBIT(bit, JCollisionSel::selUPCSingleGapA); + SETBIT(bit, JCollisionSel::selUPCSingleGapC); + SETBIT(bit, JCollisionSel::selUPCDoubleGap); return bit; } diff --git a/PWGJE/Core/JetHFUtilities.h b/PWGJE/Core/JetHFUtilities.h index f64725aa241..a018c0c177b 100644 --- a/PWGJE/Core/JetHFUtilities.h +++ b/PWGJE/Core/JetHFUtilities.h @@ -1366,6 +1366,10 @@ void fillBplusCandidateTable(T const& candidate, U& BplusParTable, V& BplusParET candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1(), + candidate.pProng0(), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), candidate.errorImpactParameter1(), candidate.cosThetaStar(), candidate.ct()); diff --git a/PWGJE/Core/JetMatchingUtilities.h b/PWGJE/Core/JetMatchingUtilities.h index 8fb24f29b50..38c5bc29774 100644 --- a/PWGJE/Core/JetMatchingUtilities.h +++ b/PWGJE/Core/JetMatchingUtilities.h @@ -293,7 +293,7 @@ std::tuple, std::vector> MatchJetsGeometrically( } template -void MatchGeo(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingGeo, std::vector>& tagToBaseMatchingGeo, float maxMatchingDistance) +void MatchGeo(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingGeo, std::vector>& tagToBaseMatchingGeo, std::vector const& jetRadiiForMatchingDistance, std::vector const& maxMatchingDistancePerJetR) { std::vector jetsR; for (const auto& jetBase : jetsBasePerCollision) { @@ -307,6 +307,16 @@ void MatchGeo(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std:: } } for (auto jetR : jetsR) { + float effectiveMatchingDistance = -1.0f; + for (std::size_t i = 0; i < jetRadiiForMatchingDistance.size(); i++) { + if (std::round(jetRadiiForMatchingDistance[i] * 100.0) == std::round(jetR)) { + effectiveMatchingDistance = maxMatchingDistancePerJetR[i]; + break; + } + } + if (effectiveMatchingDistance < 0.0f) { + LOGP(fatal, "No matching distance configured for jet R={:.2f}. Add it to jetRadiiForMatchingDistance and maxMatchingDistancePerJetR.", jetR / 100.0); + } std::vector jetsBasePhi; std::vector jetsBaseEta; std::vector jetsBaseGlobalIndex; @@ -332,7 +342,7 @@ void MatchGeo(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std:: jetsTagEta.emplace_back(jetTag.eta()); jetsTagGlobalIndex.emplace_back(jetTag.globalIndex()); } - std::tie(baseToTagMatchingGeoIndex, tagToBaseMatchingGeoIndex) = MatchJetsGeometrically(jetsBasePhi, jetsBaseEta, jetsTagPhi, jetsTagEta, maxMatchingDistance); // change max distnace to a function call + std::tie(baseToTagMatchingGeoIndex, tagToBaseMatchingGeoIndex) = MatchJetsGeometrically(jetsBasePhi, jetsBaseEta, jetsTagPhi, jetsTagEta, effectiveMatchingDistance); int jetBaseIndex = 0; int jetTagIndex = 0; for (const auto& jetBase : jetsBasePerCollision) { @@ -564,11 +574,11 @@ void MatchPt(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::v // function that calls all the Match functions template -void doAllMatching(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingGeo, std::vector>& baseToTagMatchingPt, std::vector>& baseToTagMatchingHF, std::vector>& tagToBaseMatchingGeo, std::vector>& tagToBaseMatchingPt, std::vector>& tagToBaseMatchingHF, V const& candidatesBase, M const& tracksBase, N const& clustersBase, O const& candidatesTag, P const& tracksTag, R const& clustersTag, bool doMatchingGeo, bool doMatchingHf, bool doMatchingPt, float maxMatchingDistance, float minPtFraction) +void doAllMatching(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingGeo, std::vector>& baseToTagMatchingPt, std::vector>& baseToTagMatchingHF, std::vector>& tagToBaseMatchingGeo, std::vector>& tagToBaseMatchingPt, std::vector>& tagToBaseMatchingHF, V const& candidatesBase, M const& tracksBase, N const& clustersBase, O const& candidatesTag, P const& tracksTag, R const& clustersTag, bool doMatchingGeo, bool doMatchingHf, bool doMatchingPt, float minPtFraction, std::vector const& jetRadiiForMatchingDistance, std::vector const& maxMatchingDistancePerJetR) { // geometric matching if (doMatchingGeo) { - MatchGeo(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingGeo, tagToBaseMatchingGeo, maxMatchingDistance); + MatchGeo(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingGeo, tagToBaseMatchingGeo, jetRadiiForMatchingDistance, maxMatchingDistancePerJetR); } // pt matching if (doMatchingPt) { diff --git a/PWGJE/Core/JetTaggingUtilities.h b/PWGJE/Core/JetTaggingUtilities.h index 4e685b41bf8..0e8b08c3fa2 100644 --- a/PWGJE/Core/JetTaggingUtilities.h +++ b/PWGJE/Core/JetTaggingUtilities.h @@ -1095,9 +1095,9 @@ void analyzeJetTrackInfo4MLnoSV(AnalysisJet const& analysisJet, AnyTracks const& std::sort(tracksParams.begin(), tracksParams.end(), compare); } -// Looping over the track info and putting them in the input vector (for GNN b-jet tagging) +// Looping over the track info and putting them in the input vector, with extra input features (for GNN b-jet tagging) template -void analyzeJetTrackInfo4GNN(AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, AnyOriginalTracks const& /*origTracks*/, std::vector>& tracksParams, float trackPtMin = 0.5, float trackDcaXYMax = 10.0, float trackDcaZMax = 10.0, int64_t nMaxConstit = 40) +void analyzeJetTrackInfo4GNNwExtra(AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, AnyOriginalTracks const& /*origTracks*/, std::vector>& tracksParams, float trackPtMin = 0.5, float trackDcaXYMax = 10.0, float trackDcaZMax = 10.0, int64_t nMaxConstit = 40) { for (const auto& constituent : analysisJet.template tracks_as()) { @@ -1124,6 +1124,33 @@ void analyzeJetTrackInfo4GNN(AnalysisJet const& analysisJet, AnyTracks const& /* } } +// Looping over the track info and putting them in the input vector (for GNN b-jet tagging) +template +void analyzeJetTrackInfo4GNN(AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, std::vector>& tracksParams, float trackPtMin = 0.5, float trackDcaXYMax = 10.0, float trackDcaZMax = 10.0, int64_t nMaxConstit = 40) +{ + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin || !trackAcceptanceWithDca(constituent, trackDcaXYMax, trackDcaZMax)) { + continue; + } + + int sign = getGeoSign(analysisJet, constituent); + + if (static_cast(tracksParams.size()) < nMaxConstit) { + tracksParams.emplace_back(std::vector{constituent.pt(), constituent.phi(), constituent.eta(), static_cast(constituent.sign()), std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaZ()) * sign, constituent.sigmadcaZ()}); + } else { + // If there are more than nMaxConstit constituents in the jet, select only nMaxConstit constituents with the highest DCA_XY significance. + size_t minIdx = 0; + for (size_t i = 0; i < tracksParams.size(); ++i) { + if (tracksParams[i][4] / tracksParams[i][5] < tracksParams[minIdx][4] / tracksParams[minIdx][5]) + minIdx = i; + } + if (std::abs(constituent.dcaXY()) * sign / constituent.sigmadcaXY() > tracksParams[minIdx][4] / tracksParams[minIdx][5]) + tracksParams[minIdx] = std::vector{constituent.pt(), constituent.phi(), constituent.eta(), static_cast(constituent.sign()), std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaZ()) * sign, constituent.sigmadcaZ()}; + } + } +} + // Discriminant value for GNN b-jet tagging template T getDb(const std::vector& logits, double fC = 0.018) diff --git a/PWGJE/DataModel/JetReducedData.h b/PWGJE/DataModel/JetReducedData.h index c2a3f95d485..039a1ec46de 100644 --- a/PWGJE/DataModel/JetReducedData.h +++ b/PWGJE/DataModel/JetReducedData.h @@ -219,6 +219,7 @@ DECLARE_SOA_COLUMN(XsectGen, xsectGen, float); DECLARE_SOA_COLUMN(XsectErr, xsectErr, float); DECLARE_SOA_COLUMN(PtHard, ptHard, float); DECLARE_SOA_COLUMN(IsOutlier, isOutlier, bool); +DECLARE_SOA_COLUMN(EventSel, eventSel, uint16_t); DECLARE_SOA_BITMAP_COLUMN(Rct, rct, 32); DECLARE_SOA_COLUMN(GetGeneratorId, getGeneratorId, int); DECLARE_SOA_COLUMN(GetSubGeneratorId, getSubGeneratorId, int); @@ -243,6 +244,7 @@ DECLARE_SOA_TABLE_STAGED(JMcCollisions, "JMCCOLLISION", jmccollision::XsectGen, jmccollision::XsectErr, jmccollision::PtHard, + jmccollision::EventSel, jmccollision::Rct, jmccollision::GetGeneratorId, jmccollision::GetSubGeneratorId, diff --git a/PWGJE/JetFinders/jetFinder.h b/PWGJE/JetFinders/jetFinder.h index 7b2a4d0bc80..d664e5781da 100644 --- a/PWGJE/JetFinders/jetFinder.h +++ b/PWGJE/JetFinders/jetFinder.h @@ -251,7 +251,7 @@ struct JetFinderTask { void processParticleLevelChargedJets(o2::soa::Filtered::iterator const& mcCollision, o2::soa::Filtered const& particles) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections)) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } inputParticles.clear(); @@ -262,7 +262,7 @@ struct JetFinderTask { void processParticleLevelChargedEvtWiseSubJets(o2::soa::Filtered::iterator const& mcCollision, o2::soa::Filtered const& particles) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections)) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } inputParticles.clear(); @@ -273,7 +273,7 @@ struct JetFinderTask { void processParticleLevelNeutralJets(o2::soa::Filtered::iterator const& mcCollision, o2::soa::Filtered const& particles) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections, "CBT_calo")) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections, "CBT_calo")) { return; } inputParticles.clear(); @@ -284,7 +284,7 @@ struct JetFinderTask { void processParticleLevelFullJets(o2::soa::Filtered::iterator const& mcCollision, o2::soa::Filtered const& particles) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections, "CBT_calo")) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections, "CBT_calo")) { return; } inputParticles.clear(); diff --git a/PWGJE/JetFinders/jetFinderHF.h b/PWGJE/JetFinders/jetFinderHF.h index 47289f4691f..b5e9a531ff3 100644 --- a/PWGJE/JetFinders/jetFinderHF.h +++ b/PWGJE/JetFinders/jetFinderHF.h @@ -239,7 +239,7 @@ struct JetFinderHFTask { template void analyseMCP(T const& mcCollision, U const& particles, V const& candidate, M& jetsTableInput, N& constituentsTableInput, int jetTypeParticleLevel, float minJetPt, float maxJetPt) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections)) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } diff --git a/PWGJE/JetFinders/jetFinderHFHFBar.h b/PWGJE/JetFinders/jetFinderHFHFBar.h index 28d3a4000bf..77635798346 100644 --- a/PWGJE/JetFinders/jetFinderHFHFBar.h +++ b/PWGJE/JetFinders/jetFinderHFHFBar.h @@ -250,7 +250,7 @@ struct JetFinderHFHFBarTask { return; } } - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections)) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } diff --git a/PWGJE/JetFinders/jetFinderV0.h b/PWGJE/JetFinders/jetFinderV0.h index 8314173e0e3..2b9b1d76dbd 100644 --- a/PWGJE/JetFinders/jetFinderV0.h +++ b/PWGJE/JetFinders/jetFinderV0.h @@ -206,7 +206,7 @@ struct JetFinderV0Task { void analyseMCP(T const& mcCollision, U const& particles, V const& candidates, int jetTypeParticleLevel, float minJetPt, float maxJetPt) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections)) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } diff --git a/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.h b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.h index 504219671fd..d1adaf02e28 100644 --- a/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.h +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.h @@ -34,7 +34,8 @@ struct JetMatchingDuplicates { o2::framework::Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; o2::framework::Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; o2::framework::Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; - o2::framework::Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + o2::framework::Configurable> jetRadiiForMatchingDistance{"jetRadiiForMatchingDistance", {0.2, 0.3, 0.4, 0.5, 0.6}, "Jet R values for per-R matching distance"}; + o2::framework::Configurable> maxMatchingDistancePerJetR{"maxMatchingDistancePerJetR", {0.12, 0.18, 0.24, 0.30, 0.36}, "Max matching distance (0.6*R, see ALICE-AN-852) for each R in jetRadiiForMatchingDistance"}; o2::framework::Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; o2::framework::Produces jetsBasetoTagMatchingTable; @@ -49,6 +50,12 @@ struct JetMatchingDuplicates { void init(o2::framework::InitContext const&) { + if (jetRadiiForMatchingDistance->empty() || maxMatchingDistancePerJetR->empty()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must not be empty"); + } + if (jetRadiiForMatchingDistance->size() != maxMatchingDistancePerJetR->size()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must have the same number of entries"); + } } void processJets(o2::aod::JetCollisions const& collisions, @@ -72,7 +79,7 @@ struct JetMatchingDuplicates { const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, collision.globalIndex()); const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, collision.globalIndex()); // initialise template parameters as false since even if they are Mc we are not matching between detector and particle level - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracks, tracks, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracks, tracks, doMatchingGeo, doMatchingHf, doMatchingPt, minPtFraction, jetRadiiForMatchingDistance, maxMatchingDistancePerJetR); } for (auto i = 0; i < jetsBase.size(); ++i) { diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.h b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.h index a971c1a7e8e..afc68acaa6b 100644 --- a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.h +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.h @@ -41,7 +41,8 @@ struct JetSubstructureMatching { o2::framework::Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; o2::framework::Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; o2::framework::Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; - o2::framework::Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + o2::framework::Configurable> jetRadiiForMatchingDistance{"jetRadiiForMatchingDistance", {0.2, 0.3, 0.4, 0.5, 0.6}, "Jet R values for per-R matching distance"}; + o2::framework::Configurable> maxMatchingDistancePerJetR{"maxMatchingDistancePerJetR", {0.12, 0.18, 0.24, 0.30, 0.36}, "Max matching distance (0.6*R, see ALICE-AN-852) for each R in jetRadiiForMatchingDistance"}; o2::framework::Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; o2::framework::Configurable requireGeoMatchedJets{"requireGeoMatchedJets", false, "require jets are geo matched as well"}; o2::framework::Configurable requirePtMatchedJets{"requirePtMatchedJets", false, "require jets are pT matched as well"}; @@ -52,6 +53,12 @@ struct JetSubstructureMatching { void init(o2::framework::InitContext const&) { + if (jetRadiiForMatchingDistance->empty() || maxMatchingDistancePerJetR->empty()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must not be empty"); + } + if (jetRadiiForMatchingDistance->size() != maxMatchingDistancePerJetR->size()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must have the same number of entries"); + } } o2::framework::PresliceOptional BaseSplittingsPerBaseJetInclusive = o2::aod::chargedmcdetectorlevelsplitting::jetId; @@ -218,7 +225,7 @@ struct JetSubstructureMatching { jetBaseSplittingsMap[jetBaseSplitting.globalIndex()] = baseSplittingIndex; baseSplittingIndex++; } - jetmatchingutilities::doAllMatching(jetBaseSplittings, jetTagSplittings, jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF, jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF, candidatesBase, tracksBase, clustersBase, candidatesTag, tracksTag, tracksTag, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetBaseSplittings, jetTagSplittings, jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF, jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF, candidatesBase, tracksBase, clustersBase, candidatesTag, tracksTag, tracksTag, doMatchingGeo, doMatchingHf, doMatchingPt, minPtFraction, jetRadiiForMatchingDistance, maxMatchingDistancePerJetR); // auto const& jetBasePairs = jetsBasePairs.sliceBy(BasePairsPerBaseJet, jetBase.globalIndex()); auto const& jetBasePairs = slicedPerJetForMatching(jetsBasePairs, jetBase, BasePairsPerBaseJetInclusive, BasePairsPerBaseJetD0, BasePairsPerBaseJetDplus, BasePairsPerBaseJetDs, BasePairsPerBaseJetDstar, BasePairsPerBaseJetLc, BasePairsPerBaseJetB0, BasePairsPerBaseJetBplus, BasePairsPerBaseJetXicToXiPiPi, BasePairsPerBaseJetDielectron); int basePairIndex = 0; diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.h b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.h index bcce8a6103f..6075d86cd55 100644 --- a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.h +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.h @@ -42,7 +42,8 @@ struct JetSubstructureMatchingSub { o2::framework::Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; o2::framework::Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; o2::framework::Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; - o2::framework::Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + o2::framework::Configurable> jetRadiiForMatchingDistance{"jetRadiiForMatchingDistance", {0.2, 0.3, 0.4, 0.5, 0.6}, "Jet R values for per-R matching distance"}; + o2::framework::Configurable> maxMatchingDistancePerJetR{"maxMatchingDistancePerJetR", {0.12, 0.18, 0.24, 0.30, 0.36}, "Max matching distance (0.6*R, see ALICE-AN-852) for each R in jetRadiiForMatchingDistance"}; o2::framework::Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; o2::framework::Configurable requireGeoMatchedJets{"requireGeoMatchedJets", false, "require jets are geo matched as well"}; o2::framework::Configurable requirePtMatchedJets{"requirePtMatchedJets", false, "require jets are pT matched as well"}; @@ -53,6 +54,12 @@ struct JetSubstructureMatchingSub { void init(o2::framework::InitContext const&) { + if (jetRadiiForMatchingDistance->empty() || maxMatchingDistancePerJetR->empty()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must not be empty"); + } + if (jetRadiiForMatchingDistance->size() != maxMatchingDistancePerJetR->size()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must have the same number of entries"); + } } o2::framework::PresliceOptional BaseSplittingsPerBaseJetInclusive = o2::aod::chargedsplitting::jetId; @@ -219,7 +226,7 @@ struct JetSubstructureMatchingSub { jetBaseSplittingsMap[jetBaseSplitting.globalIndex()] = baseSplittingIndex; baseSplittingIndex++; } - jetmatchingutilities::doAllMatching(jetBaseSplittings, jetTagSplittings, jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF, jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF, candidates, tracksBase, clustersBase, candidates, tracksTag, tracksTag, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetBaseSplittings, jetTagSplittings, jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF, jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF, candidates, tracksBase, clustersBase, candidates, tracksTag, tracksTag, doMatchingGeo, doMatchingHf, doMatchingPt, minPtFraction, jetRadiiForMatchingDistance, maxMatchingDistancePerJetR); // auto const& jetBasePairs = jetsBasePairs.sliceBy(BasePairsPerBaseJet, jetBase.globalIndex()); auto const& jetBasePairs = slicedPerJetForMatching(jetsBasePairs, jetBase, BasePairsPerBaseJetInclusive, BasePairsPerBaseJetD0, BasePairsPerBaseJetDplus, BasePairsPerBaseJetDs, BasePairsPerBaseJetDstar, BasePairsPerBaseJetLc, BasePairsPerBaseJetB0, BasePairsPerBaseJetBplus, BasePairsPerBaseJetXicToXiPiPi, BasePairsPerBaseJetDielectron); int basePairIndex = 0; diff --git a/PWGJE/TableProducer/Matching/jetMatchingMC.h b/PWGJE/TableProducer/Matching/jetMatchingMC.h index 10257b94ba7..a78c48a2800 100644 --- a/PWGJE/TableProducer/Matching/jetMatchingMC.h +++ b/PWGJE/TableProducer/Matching/jetMatchingMC.h @@ -37,7 +37,8 @@ struct JetMatchingMc { o2::framework::Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; o2::framework::Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; o2::framework::Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; - o2::framework::Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + o2::framework::Configurable> jetRadiiForMatchingDistance{"jetRadiiForMatchingDistance", {0.2, 0.3, 0.4, 0.5, 0.6}, "Jet R values for per-R matching distance"}; + o2::framework::Configurable> maxMatchingDistancePerJetR{"maxMatchingDistancePerJetR", {0.12, 0.18, 0.24, 0.30, 0.36}, "Max matching distance (0.6*R, see ALICE-AN-852) for each R in jetRadiiForMatchingDistance"}; o2::framework::Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; o2::framework::Produces jetsBasetoTagMatchingTable; @@ -54,6 +55,12 @@ struct JetMatchingMc { void init(o2::framework::InitContext const&) { + if (jetRadiiForMatchingDistance->empty() || maxMatchingDistancePerJetR->empty()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must not be empty"); + } + if (jetRadiiForMatchingDistance->size() != maxMatchingDistancePerJetR->size()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must have the same number of entries"); + } } void processJets(o2::aod::JetMcCollisions const& mcCollisions, o2::aod::JetCollisionsMCD const& collisions, @@ -84,7 +91,7 @@ struct JetMatchingMc { const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, jetsBaseIsMc ? mcCollision.globalIndex() : collision.globalIndex()); const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, jetsTagIsMc ? mcCollision.globalIndex() : collision.globalIndex()); - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidatesBase, tracks, clusters, candidatesTag, particles, particles, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidatesBase, tracks, clusters, candidatesTag, particles, particles, doMatchingGeo, doMatchingHf, doMatchingPt, minPtFraction, jetRadiiForMatchingDistance, maxMatchingDistancePerJetR); } } for (auto i = 0; i < jetsBase.size(); ++i) { diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSub.h b/PWGJE/TableProducer/Matching/jetMatchingMCSub.h index 51a0b3d8424..395783865b4 100644 --- a/PWGJE/TableProducer/Matching/jetMatchingMCSub.h +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSub.h @@ -33,7 +33,8 @@ struct JetMatchingMcSub { o2::framework::Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; o2::framework::Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; o2::framework::Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; - o2::framework::Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + o2::framework::Configurable> jetRadiiForMatchingDistance{"jetRadiiForMatchingDistance", {0.2, 0.3, 0.4, 0.5, 0.6}, "Jet R values for per-R matching distance"}; + o2::framework::Configurable> maxMatchingDistancePerJetR{"maxMatchingDistancePerJetR", {0.12, 0.18, 0.24, 0.30, 0.36}, "Max matching distance (0.6*R, see ALICE-AN-852) for each R in jetRadiiForMatchingDistance"}; o2::framework::Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; o2::framework::Produces jetsBasetoTagMatchingTable; @@ -48,6 +49,12 @@ struct JetMatchingMcSub { void init(o2::framework::InitContext const&) { + if (jetRadiiForMatchingDistance->empty() || maxMatchingDistancePerJetR->empty()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must not be empty"); + } + if (jetRadiiForMatchingDistance->size() != maxMatchingDistancePerJetR->size()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must have the same number of entries"); + } } void processJets(o2::aod::JetCollisions const& collisions, @@ -73,7 +80,7 @@ struct JetMatchingMcSub { const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, collision.globalIndex()); const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, collision.globalIndex()); - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracksSub, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracksSub, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, minPtFraction, jetRadiiForMatchingDistance, maxMatchingDistancePerJetR); } for (auto i = 0; i < jetsBase.size(); ++i) { diff --git a/PWGJE/TableProducer/Matching/jetMatchingSub.h b/PWGJE/TableProducer/Matching/jetMatchingSub.h index 0aa035794c3..b5d1db2491c 100644 --- a/PWGJE/TableProducer/Matching/jetMatchingSub.h +++ b/PWGJE/TableProducer/Matching/jetMatchingSub.h @@ -34,7 +34,8 @@ struct JetMatchingSub { o2::framework::Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; o2::framework::Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; o2::framework::Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; - o2::framework::Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + o2::framework::Configurable> jetRadiiForMatchingDistance{"jetRadiiForMatchingDistance", {0.2, 0.3, 0.4, 0.5, 0.6}, "Jet R values for per-R matching distance"}; + o2::framework::Configurable> maxMatchingDistancePerJetR{"maxMatchingDistancePerJetR", {0.12, 0.18, 0.24, 0.30, 0.36}, "Max matching distance (0.6*R, see ALICE-AN-852) for each R in jetRadiiForMatchingDistance"}; o2::framework::Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; o2::framework::Produces jetsBasetoTagMatchingTable; @@ -49,6 +50,12 @@ struct JetMatchingSub { void init(o2::framework::InitContext const&) { + if (jetRadiiForMatchingDistance->empty() || maxMatchingDistancePerJetR->empty()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must not be empty"); + } + if (jetRadiiForMatchingDistance->size() != maxMatchingDistancePerJetR->size()) { + LOGP(fatal, "jetRadiiForMatchingDistance and maxMatchingDistancePerJetR must have the same number of entries"); + } } void processJets(o2::aod::JetCollisions const& collisions, @@ -72,7 +79,7 @@ struct JetMatchingSub { const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, collision.globalIndex()); const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, collision.globalIndex()); - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracksSub, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracksSub, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, minPtFraction, jetRadiiForMatchingDistance, maxMatchingDistancePerJetR); } for (auto i = 0; i < jetsBase.size(); ++i) { diff --git a/PWGJE/TableProducer/derivedDataProducer.cxx b/PWGJE/TableProducer/derivedDataProducer.cxx index e21627baea2..7182fbcec05 100644 --- a/PWGJE/TableProducer/derivedDataProducer.cxx +++ b/PWGJE/TableProducer/derivedDataProducer.cxx @@ -193,6 +193,7 @@ struct JetDerivedDataProducerTask { std::vector trackMCSelection; + std::vector bcSelMapping; std::vector bcRctMapping; ctpRateFetcher rateFetcher; @@ -267,11 +268,14 @@ struct JetDerivedDataProducerTask { void processBunchCrossings(soa::Join const& bcs) { + bcSelMapping.clear(); + bcSelMapping.resize(bcs.size(), ~uint16_t{0}); bcRctMapping.clear(); bcRctMapping.resize(bcs.size(), ~uint32_t{0}); for (const auto& bc : bcs) { products.jBCsTable(bc.runNumber(), bc.globalBC(), bc.triggerMask(), bc.timestamp(), bc.alias_raw(), bc.selection_raw(), bc.rct_raw()); products.jBCParentIndexTable(bc.globalIndex()); + bcSelMapping[bc.globalIndex()] = jetderiveddatautilities::setMCEventSelectionBit(bc); bcRctMapping[bc.globalIndex()] = bc.rct_raw(); } } @@ -279,6 +283,8 @@ struct JetDerivedDataProducerTask { void processBunchCrossingsWithoutSels(soa::Join const& bcs) { + bcSelMapping.clear(); + bcSelMapping.resize(bcs.size(), ~uint16_t{0}); bcRctMapping.clear(); bcRctMapping.resize(bcs.size(), ~uint32_t{0}); for (const auto& bc : bcs) { @@ -377,64 +383,73 @@ struct JetDerivedDataProducerTask { void processMcCollisions(soa::Join::iterator const& mcCollision) { + uint32_t selDecision = ~uint16_t{0}; uint32_t rctDecision = ~uint32_t{0}; int32_t bcId = -1; if (!config.isMCGenOnly) { bcId = mcCollision.bcId(); + selDecision = bcSelMapping[bcId]; rctDecision = bcRctMapping[bcId]; } else { products.jBCsTable(-1, -1, -1, -1, ~uint32_t{0}, ~uint32_t{0}, ~uint32_t{0}); bcId = products.jBCsTable.lastIndex(); } - products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multMCFV0A(), mcCollision.multMCFT0A(), mcCollision.multMCFT0C(), mcCollision.centFT0M(), mcCollision.weight(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard(), rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multMCFV0A(), mcCollision.multMCFT0A(), mcCollision.multMCFT0C(), mcCollision.centFT0M(), mcCollision.weight(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard(), selDecision, rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); } PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisions, "produces derived MC collision table", false); void processMcCollisionsWithoutCentralityAndMultiplicity(soa::Join::iterator const& mcCollision) { + + uint32_t selDecision = ~uint16_t{0}; uint32_t rctDecision = ~uint32_t{0}; int32_t bcId = -1; if (!config.isMCGenOnly) { bcId = mcCollision.bcId(); + selDecision = bcSelMapping[bcId]; rctDecision = bcRctMapping[bcId]; } else { products.jBCsTable(-1, -1, -1, -1, ~uint32_t{0}, ~uint32_t{0}, ~uint32_t{0}); bcId = products.jBCsTable.lastIndex(); } - products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), -1.0, -1.0, -1.0, -1.0, mcCollision.weight(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard(), rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), -1.0, -1.0, -1.0, -1.0, mcCollision.weight(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard(), selDecision, rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); } PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionsWithoutCentralityAndMultiplicity, "produces derived MC collision table without centraility and multiplicity", false); void processMcCollisionsWithoutXsection(soa::Join::iterator const& mcCollision) { + uint32_t selDecision = ~uint16_t{0}; uint32_t rctDecision = ~uint32_t{0}; int32_t bcId = -1; if (!config.isMCGenOnly) { bcId = mcCollision.bcId(); + selDecision = bcSelMapping[bcId]; rctDecision = bcRctMapping[bcId]; } else { products.jBCsTable(-1, -1, -1, -1, ~uint32_t{0}, ~uint32_t{0}, ~uint32_t{0}); bcId = products.jBCsTable.lastIndex(); } - products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multMCFV0A(), mcCollision.multMCFT0A(), mcCollision.multMCFT0C(), mcCollision.centFT0M(), mcCollision.weight(), 1, 1, 1.0, 1.0, 999.0, rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multMCFV0A(), mcCollision.multMCFT0A(), mcCollision.multMCFT0C(), mcCollision.centFT0M(), mcCollision.weight(), 1, 1, 1.0, 1.0, 999.0, selDecision, rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); } PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionsWithoutXsection, "produces derived MC collision table without cross section information", false); void processMcCollisionsWithoutCentralityAndMultiplicityAndXsection(aod::McCollision const& mcCollision) { + uint32_t selDecision = ~uint16_t{0}; uint32_t rctDecision = ~uint32_t{0}; int32_t bcId = -1; if (!config.isMCGenOnly) { bcId = mcCollision.bcId(); + selDecision = bcSelMapping[bcId]; rctDecision = bcRctMapping[bcId]; } else { products.jBCsTable(-1, -1, -1, -1, ~uint32_t{0}, ~uint32_t{0}, ~uint32_t{0}); bcId = products.jBCsTable.lastIndex(); } - products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), -1.0, -1.0, -1.0, -1.0, mcCollision.weight(), 1, 1, 1.0, 1.0, 999.0, rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + products.jMcCollisionsTable(bcId, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), -1.0, -1.0, -1.0, -1.0, mcCollision.weight(), 1, 1, 1.0, 1.0, 999.0, selDecision, rctDecision, mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); } PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionsWithoutCentralityAndMultiplicityAndXsection, "produces derived MC collision table without centrality, multiplicity and cross section information", false); diff --git a/PWGJE/TableProducer/derivedDataSelector.cxx b/PWGJE/TableProducer/derivedDataSelector.cxx index fcd4c3f5ffe..371dbc73f34 100644 --- a/PWGJE/TableProducer/derivedDataSelector.cxx +++ b/PWGJE/TableProducer/derivedDataSelector.cxx @@ -50,8 +50,6 @@ struct JetDerivedDataSelector { Configurable thresholdChargedJetPtMin{"thresholdChargedJetPtMin", 0.0, "Minimum charged jet pt to accept event"}; Configurable thresholdChargedEventWiseSubtractedJetPtMin{"thresholdChargedEventWiseSubtractedJetPtMin", 0.0, "Minimum charged event-wise subtracted jet pt to accept event"}; Configurable thresholdChargedMCPJetPtMin{"thresholdChargedMCPJetPtMin", 0.0, "Minimum charged mcp jet pt to accept event"}; - Configurable thresholdNeutralJetPtMin{"thresholdNeutralJetPtMin", 0.0, "Minimum neutral jet pt to accept event"}; - Configurable thresholdNeutralMCPJetPtMin{"thresholdNeutralMCPJetPtMin", 0.0, "Minimum neutal mcp jet pt to accept event"}; Configurable thresholdFullJetPtMin{"thresholdFullJetPtMin", 0.0, "Minimum full jet pt to accept event"}; Configurable thresholdFullMCPJetPtMin{"thresholdFullMCPJetPtMin", 0.0, "Minimum full mcp jet pt to accept event"}; Configurable thresholdD0PtMin{"thresholdD0PtMin", 0.0, "Minimum D0 pt to accept event"}; @@ -100,7 +98,9 @@ struct JetDerivedDataSelector { Configurable thresholdChargedEventWiseSubtractedDielectronJetPtMin{"thresholdChargedEventWiseSubtractedDielectronJetPtMin", 0.0, "Minimum charged event-wise subtracted Dielectron jet pt to accept event"}; Configurable thresholdChargedDielectronMCPJetPtMin{"thresholdChargedDielectronMCPJetPtMin", 0.0, "Minimum charged Dielectron mcp jet pt to accept event"}; Configurable thresholdTriggerTrackPtMin{"thresholdTriggerTrackPtMin", 0.0, "Minimum trigger track pt to accept event"}; + Configurable thresholdTriggerTrackReferencePtMin{"thresholdTriggerTrackReferencePtMin", 0.0, "Minimum trigger track reference pt to accept event"}; Configurable thresholdTriggerParticlePtMin{"thresholdTriggerParticlePtMin", 0.0, "Minimum trigger particle pt to accept event"}; + Configurable thresholdTriggerParticleReferencePtMin{"thresholdTriggerParticleReferencePtMin", 0.0, "Minimum trigger particle reference pt to accept event"}; Configurable thresholdClusterEnergyMin{"thresholdClusterEnergyMin", 0.0, "Minimum cluster energy to accept event"}; Configurable downscaleFactor{"downscaleFactor", 1, "random downscale of selected events"}; @@ -116,12 +116,15 @@ struct JetDerivedDataSelector { Configurable performTrackSelection{"performTrackSelection", true, "only save tracks that pass one of the track selections"}; Configurable trackPtSelectionMin{"trackPtSelectionMin", 0.15, "only save tracks that have a pT larger than this pT"}; Configurable trackEtaSelectionMax{"trackEtaSelectionMax", 0.9, "only save tracks that have an eta smaller than this eta"}; + Configurable triggerTrackSignalFraction{"triggerTrackSignalFraction", 0.95, "fraction of events to scan for signal trigger track class"}; Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; } config; std::vector collisionFlag; - std::vector McCollisionFlag; + std::vector mcCollisionFlag; + std::vector collisionSplitFlag; + std::vector mcCollisionSplitFlag; TRandom3 randomNumber; @@ -146,8 +149,8 @@ struct JetDerivedDataSelector { void processSetupMcCollisions(aod::JMcCollisions const& mcCollisions) { - McCollisionFlag.clear(); - McCollisionFlag.resize(mcCollisions.size(), false); + mcCollisionFlag.clear(); + mcCollisionFlag.resize(mcCollisions.size(), false); } void processSelectMcCollisionsPerCollision(aod::JMcCollisions const& mcCollisions, soa::Join const& collisions) @@ -156,7 +159,7 @@ struct JetDerivedDataSelector { const auto collisionsPerMcCollision = collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex()); for (auto collision : collisionsPerMcCollision) { if (collisionFlag[collision.globalIndex()]) { - McCollisionFlag[mcCollision.globalIndex()] = true; + mcCollisionFlag[mcCollision.globalIndex()] = true; } } } @@ -165,7 +168,7 @@ struct JetDerivedDataSelector { void processSelectCollisionsPerMcCollision(soa::Join::iterator const& collision) { if (collision.has_mcCollision()) { - if (McCollisionFlag[collision.mcCollisionId()]) { + if (mcCollisionFlag[collision.mcCollisionId()]) { collisionFlag[collision.globalIndex()] = true; } } @@ -184,11 +187,11 @@ struct JetDerivedDataSelector { void processSetupAllMcCollisionsWithDownscaling(aod::JMcCollisions const& mcCollisions) { - McCollisionFlag.clear(); - McCollisionFlag.resize(mcCollisions.size(), false); + mcCollisionFlag.clear(); + mcCollisionFlag.resize(mcCollisions.size(), false); for (const auto& mcCollision : mcCollisions) { if (randomNumber.Integer(config.downscaleFactor) == 0) { - McCollisionFlag[mcCollision.globalIndex()] = true; + mcCollisionFlag[mcCollision.globalIndex()] = true; } } } @@ -203,8 +206,8 @@ struct JetDerivedDataSelector { } } if constexpr (std::is_same_v, aod::JMcCollisions>) { - if (McCollisionFlag[collision.globalIndex()] && randomNumber.Integer(config.downscaleFactor) != 0) { - McCollisionFlag[collision.globalIndex()] = false; + if (mcCollisionFlag[collision.globalIndex()] && randomNumber.Integer(config.downscaleFactor) != 0) { + mcCollisionFlag[collision.globalIndex()] = false; } } } @@ -227,7 +230,7 @@ struct JetDerivedDataSelector { if (jetderiveddatautilities::selectCollision(collision, eventSelectionBitsCharged, config.skipMBGapEvents, config.applyRCTSelectionsCharged)) { barrelRCTFlagSelection = true; } - if (doprocessSelectingNeutralJets || doprocessSelectingNeutralMCDJets || doprocessSelectingNeutralMCPJets || doprocessSelectingFullJets || doprocessSelectingFullMCDJets || doprocessSelectingFullMCPJets || doprocessSelectingClusters) { + if (doprocessSelectingFullJets || doprocessSelectingFullMCDJets || doprocessSelectingFullMCPJets || doprocessSelectingClusters) { if (jetderiveddatautilities::selectCollision(collision, eventSelectionBitsFull, config.skipMBGapEvents, config.applyRCTSelectionsFull, "CBT_calo")) { emcalRCTFlagSelection = true; } @@ -237,6 +240,33 @@ struct JetDerivedDataSelector { } } + void processCollisionSplitting(aod::JCollisions const& collisions) + { + collisionSplitFlag.clear(); + collisionSplitFlag.resize(collisions.size(), true); + for (auto const& collision : collisions) { + if (randomNumber.Rndm() > config.triggerTrackSignalFraction) { + collisionSplitFlag[collision.globalIndex()] = false; + } + } + } + + void processCollisionSplittingMC(aod::JMcCollisions const& mcCollisions, soa::Join const& collisions) + { + mcCollisionSplitFlag.clear(); + mcCollisionSplitFlag.resize(mcCollisions.size(), true); + collisionSplitFlag.clear(); + collisionSplitFlag.resize(collisions.size(), true); + for (auto const& mcCollision : mcCollisions) { + if (randomNumber.Rndm() > config.triggerTrackSignalFraction) { + mcCollisionSplitFlag[mcCollision.globalIndex()] = false; + for (auto const& collision : collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex())) { + collisionSplitFlag[collision.globalIndex()] = false; + } + } + } + } + template void processSelectionObjects(T const& selectionObjects) { @@ -247,10 +277,6 @@ struct JetDerivedDataSelector { selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedJetPtMin; } else if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets>) { selectionObjectPtMin = config.thresholdChargedMCPJetPtMin; - } else if constexpr (std::is_same_v, aod::NeutralJets> || std::is_same_v, aod::NeutralMCDetectorLevelJets>) { - selectionObjectPtMin = config.thresholdNeutralJetPtMin; - } else if constexpr (std::is_same_v, aod::NeutralMCParticleLevelJets>) { - selectionObjectPtMin = config.thresholdNeutralMCPJetPtMin; } else if constexpr (std::is_same_v, aod::FullJets> || std::is_same_v, aod::FullMCDetectorLevelJets>) { selectionObjectPtMin = config.thresholdFullJetPtMin; } else if constexpr (std::is_same_v, aod::FullMCParticleLevelJets>) { @@ -368,15 +394,37 @@ struct JetDerivedDataSelector { if (selectionObject.pt() < config.trackPtSelectionMin || std::abs(selectionObject.eta()) > config.trackEtaSelectionMax) { continue; } + if (doprocessCollisionSplitting || doprocessCollisionSplittingMC) { + if (collisionSplitFlag[selectionObject.collisionId()]) { + selectionObjectPtMin = config.thresholdTriggerTrackPtMin; + } else { + selectionObjectPtMin = config.thresholdTriggerTrackReferencePtMin; + } + } + } + if constexpr (std::is_same_v, aod::JMcParticles>) { + if (!selectionObject.isPhysicalPrimary()) { + continue; + } + if (selectionObject.pt() < config.trackPtSelectionMin || std::abs(selectionObject.eta()) > config.trackEtaSelectionMax) { + continue; + } + if (doprocessCollisionSplittingMC) { + if (mcCollisionSplitFlag[selectionObject.mcCollisionId()]) { + selectionObjectPtMin = config.thresholdTriggerParticlePtMin; + } else { + selectionObjectPtMin = config.thresholdTriggerParticleReferencePtMin; + } + } } if (selectionObject.pt() >= selectionObjectPtMin) { isTriggerObject = true; } } if (isTriggerObject) { - if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets> || std::is_same_v, aod::NeutralMCParticleLevelJets> || std::is_same_v, aod::FullMCParticleLevelJets> || std::is_same_v, aod::CandidatesD0MCP> || std::is_same_v, aod::D0ChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDplusMCP> || std::is_same_v, aod::DplusChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDsMCP> || std::is_same_v, aod::DsChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDstarMCP> || std::is_same_v, aod::DstarChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesLcMCP> || std::is_same_v, aod::LcChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesB0MCP> || std::is_same_v, aod::B0ChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesBplusMCP> || std::is_same_v, aod::BplusChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesXicToXiPiPiMCP> || std::is_same_v, aod::XicToXiPiPiChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDielectronMCP> || std::is_same_v, aod::DielectronChargedMCParticleLevelJets> || std::is_same_v, aod::JMcParticles>) { + if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets> || std::is_same_v, aod::FullMCParticleLevelJets> || std::is_same_v, aod::CandidatesD0MCP> || std::is_same_v, aod::D0ChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDplusMCP> || std::is_same_v, aod::DplusChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDsMCP> || std::is_same_v, aod::DsChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDstarMCP> || std::is_same_v, aod::DstarChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesLcMCP> || std::is_same_v, aod::LcChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesB0MCP> || std::is_same_v, aod::B0ChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesBplusMCP> || std::is_same_v, aod::BplusChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesXicToXiPiPiMCP> || std::is_same_v, aod::XicToXiPiPiChargedMCParticleLevelJets> || std::is_same_v, aod::CandidatesDielectronMCP> || std::is_same_v, aod::DielectronChargedMCParticleLevelJets> || std::is_same_v, aod::JMcParticles>) { if (selectionObject.mcCollisionId() >= 0) { - McCollisionFlag[selectionObject.mcCollisionId()] = true; + mcCollisionFlag[selectionObject.mcCollisionId()] = true; } } else { if (selectionObject.collisionId() >= 0) { @@ -392,14 +440,13 @@ struct JetDerivedDataSelector { PROCESS_SWITCH(JetDerivedDataSelector, processSetupAllCollisionsWithDownscaling, "setup the writing of untriggered collisions with downscaling", false); PROCESS_SWITCH(JetDerivedDataSelector, processSetupAllMcCollisionsWithDownscaling, "setup the writing of untriggered mccollisions with downscaling", false); PROCESS_SWITCH(JetDerivedDataSelector, processSetupEventTriggering, "process software triggers", false); + PROCESS_SWITCH(JetDerivedDataSelector, processCollisionSplitting, "process collision splitting for trigger tracks", false); + PROCESS_SWITCH(JetDerivedDataSelector, processCollisionSplittingMC, "process mcCollision and collision splitting for trigger tracks", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedJets, "process charged jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedEventWiseSubtractedJets, "process charged event-wise subtracted jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedMCDJets, "process charged mcd jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedMCDetectorLevelEventWiseSubtractedJets, "process charged event-wise subtracted mcd jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedMCPJets, "process charged mcp jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingNeutralJets, "process neutral jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingNeutralMCDJets, "process neutral mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingNeutralMCPJets, "process neutral mcp jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingFullJets, "process full jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingFullMCDJets, "process full mcd jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingFullMCPJets, "process full mcp jets", false); @@ -452,8 +499,8 @@ struct JetDerivedDataSelector { PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedMCDJets, "process Bplus charged mcd jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedMCDetectorLevelEventWiseSubtractedJets, "process Bplus event-wise subtracted charged mcd jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedMCPJets, "process Bplus charged mcp jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiCandidates, "process XicToXiPiPi candidates", false); - PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiCandidatesMCP, "process XicToXiPiPi particles", false); + // PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiCandidates, "process XicToXiPiPi candidates", false); + // PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiCandidatesMCP, "process XicToXiPiPi particles", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiChargedJets, "process XicToXiPiPi charged jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiChargedEventWiseSubtractedJets, "process XicToXiPiPi event-wise subtracted charged jets", false); PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiChargedMCDJets, "process XicToXiPiPi charged mcd jets", false); @@ -487,7 +534,7 @@ struct JetDerivedDataSelector { void processStoreMcCollisionDecision(aod::JMcCollision const& mcCollision) { - if (McCollisionFlag[mcCollision.globalIndex()]) { + if (mcCollisionFlag[mcCollision.globalIndex()]) { mcCollisionSelectionsTable(true); } else { mcCollisionSelectionsTable(false); diff --git a/PWGJE/TableProducer/derivedDataWriter.cxx b/PWGJE/TableProducer/derivedDataWriter.cxx index 61bbefed01a..e5676af0d58 100644 --- a/PWGJE/TableProducer/derivedDataWriter.cxx +++ b/PWGJE/TableProducer/derivedDataWriter.cxx @@ -685,7 +685,7 @@ struct JetDerivedDataWriter { mcCollisionMapping.resize(mcCollisions.size(), -1); for (auto const& mcCollision : mcCollisions) { if (mcCollision.isMcCollisionSelected()) { - products.storedJMcCollisionsTable(bcMapping[mcCollision.bcId()], mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multFV0A(), mcCollision.multFT0A(), mcCollision.multFT0C(), mcCollision.centFT0M(), mcCollision.weight(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard(), mcCollision.rct_raw(), mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + products.storedJMcCollisionsTable(bcMapping[mcCollision.bcId()], mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multFV0A(), mcCollision.multFT0A(), mcCollision.multFT0C(), mcCollision.centFT0M(), mcCollision.weight(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard(), mcCollision.eventSel(), mcCollision.rct_raw(), mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); products.storedJMcCollisionsParentIndexTable(mcCollision.mcCollisionId()); mcCollisionMapping[mcCollision.globalIndex()] = products.storedJMcCollisionsTable.lastIndex(); } diff --git a/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx b/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx index acb7a092ce2..33cafe0db0c 100644 --- a/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx +++ b/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx @@ -141,7 +141,7 @@ struct eventWiseConstituentSubtractorTask { template void analyseHFMc(T const& mcCollision, U const& particles, V const& candidates, M& particleSubTable) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections) || std::abs(mcCollision.posZ()) > vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections) || std::abs(mcCollision.posZ()) > vertexZCut) { return; } for (auto& candidate : candidates) { @@ -178,7 +178,7 @@ struct eventWiseConstituentSubtractorTask { void processMcCollisions(soa::Join::iterator const& mcCollision, soa::Filtered const& particles) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, skipMBGapEvents, applyRCTSelections) || std::abs(mcCollision.posZ()) > vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections) || std::abs(mcCollision.posZ()) > vertexZCut) { return; } inputParticles.clear(); diff --git a/PWGJE/TableProducer/jetTaggerHF.cxx b/PWGJE/TableProducer/jetTaggerHF.cxx index 90412b53207..6878544163a 100644 --- a/PWGJE/TableProducer/jetTaggerHF.cxx +++ b/PWGJE/TableProducer/jetTaggerHF.cxx @@ -277,7 +277,7 @@ struct JetTaggerHFTask { } } } - if (doprocessAlgorithmGNN) { + if (doprocessAlgorithmGNN || doprocessAlgorithmGNNwExtra) { if (jet.pt() >= jetpTMin) { float dbRange; if (scoreML[jet.globalIndex()] < dbMin) { @@ -513,7 +513,7 @@ struct JetTaggerHFTask { } } - if (doprocessAlgorithmML || doprocessAlgorithmGNN) { + if (doprocessAlgorithmML || doprocessAlgorithmGNN || doprocessAlgorithmGNNwExtra) { bMlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); if (loadModelsFromCCDB) { ccdbApi.init(ccdbUrl); @@ -525,7 +525,7 @@ struct JetTaggerHFTask { bMlResponse.init(); } - if (doprocessAlgorithmGNN) { + if (doprocessAlgorithmGNN || doprocessAlgorithmGNNwExtra) { tensorAlloc = o2::analysis::GNNBjetAllocator(nJetFeat.value, nTrkFeat.value, nClassesMl.value, nTrkOrigin.value, transformFeatureJetMean.value, transformFeatureJetStdev.value, transformFeatureTrkMean.value, transformFeatureTrkStdev.value, nJetConst, tfFuncTypeGNN.value); registry.add("h2_count_db", "#it{D}_{b} underflow/overflow;Jet flavour;#it{D}_{b} range", {HistType::kTH2F, {{4, 0., 4.}, {3, 0., 3.}}}); @@ -538,10 +538,10 @@ struct JetTaggerHFTask { h2CountDb->GetYaxis()->SetBinLabel(2, "in range"); h2CountDb->GetYaxis()->SetBinLabel(3, "overflow"); - registry.add("h_db_b", "#it{D}_{b} b-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -10., 35.}}}); - registry.add("h_db_c", "#it{D}_{b} c-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -10., 35.}}}); - registry.add("h_db_lf", "#it{D}_{b} lf-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -10., 35.}}}); - registry.add("h2_pt_db", "#it{p}_{T} vs. #it{D}_{b};#it{p}_{T}^{ch jet} (GeV/#it{c}^{2});#it{D}_{b}", {HistType::kTH2F, {{100, 0., 200.}, {50, -10., 35.}}}); + registry.add("h_db_b", "#it{D}_{b} b-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -20., 30.}}}); + registry.add("h_db_c", "#it{D}_{b} c-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -20., 30.}}}); + registry.add("h_db_lf", "#it{D}_{b} lf-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -20., 30.}}}); + registry.add("h2_pt_db", "#it{p}_{T} vs. #it{D}_{b};#it{p}_{T}^{ch jet} (GeV/#it{c}^{2});#it{D}_{b}", {HistType::kTH2F, {{100, 0., 200.}, {50, -20., 30.}}}); } } @@ -612,11 +612,40 @@ struct JetTaggerHFTask { } template - void analyzeJetAlgorithmGNN(AnyJets const& jets, AnyTracks const& tracks, AnyOriginalTracks const& origTracks) + void analyzeJetAlgorithmGNNwExtra(AnyJets const& jets, AnyTracks const& tracks, AnyOriginalTracks const& origTracks) { for (const auto& jet : jets) { std::vector> trkFeat; - jettaggingutilities::analyzeJetTrackInfo4GNN(jet, tracks, origTracks, trkFeat, trackPtMin, trackDcaXYMax, trackDcaZMax, nJetConst); + jettaggingutilities::analyzeJetTrackInfo4GNNwExtra(jet, tracks, origTracks, trkFeat, trackPtMin, trackDcaXYMax, trackDcaZMax, nJetConst); + + std::vector jetFeat{jet.pt(), jet.phi(), jet.eta(), jet.mass()}; + + if (trkFeat.size() > 0) { + std::vector feat; + std::vector gnnInput; + tensorAlloc.getGNNInput(jetFeat, trkFeat, feat, gnnInput); + + auto modelOutput = bMlResponse.getModelOutput(gnnInput, 0); + float db = jettaggingutilities::getDb(modelOutput, fC); + if (!std::isnan(db)) { + scoreML[jet.globalIndex()] = db; + } else { + scoreML[jet.globalIndex()] = 999.; + LOGF(debug, "doprocessAlgorithmGNNwExtra, Db is NaN (%d)", jet.globalIndex()); + } + } else { + scoreML[jet.globalIndex()] = -999.; + LOGF(debug, "doprocessAlgorithmGNNwExtra, trkFeat.size() <= 0 (%d)", jet.globalIndex()); + } + } + } + + template + void analyzeJetAlgorithmGNN(AnyJets const& jets, AnyTracks const& tracks) + { + for (const auto& jet : jets) { + std::vector> trkFeat; + jettaggingutilities::analyzeJetTrackInfo4GNN(jet, tracks, trkFeat, trackPtMin, trackDcaXYMax, trackDcaZMax, nJetConst); std::vector jetFeat{jet.pt(), jet.phi(), jet.eta(), jet.mass()}; @@ -684,9 +713,15 @@ struct JetTaggerHFTask { } PROCESS_SWITCH(JetTaggerHFTask, processAlgorithmMLnoSV, "Fill ML evaluation score for charged jets but without using SVs", false); - void processAlgorithmGNN(JetTable const& jets, JetTracksExt const& jtracks, OriginalTracks const& origTracks) + void processAlgorithmGNNwExtra(JetTable const& jets, JetTracksExt const& jtracks, OriginalTracks const& origTracks) + { + analyzeJetAlgorithmGNNwExtra(jets, jtracks, origTracks); + } + PROCESS_SWITCH(JetTaggerHFTask, processAlgorithmGNNwExtra, "Fill GNN evaluation score (D_b) for charged jets with extra input features", false); + + void processAlgorithmGNN(JetTable const& jets, JetTracksExt const& jtracks) { - analyzeJetAlgorithmGNN(jets, jtracks, origTracks); + analyzeJetAlgorithmGNN(jets, jtracks); } PROCESS_SWITCH(JetTaggerHFTask, processAlgorithmGNN, "Fill GNN evaluation score (D_b) for charged jets", false); diff --git a/PWGJE/TableProducer/rhoEstimator.cxx b/PWGJE/TableProducer/rhoEstimator.cxx index fb14c472885..71c183e9e83 100644 --- a/PWGJE/TableProducer/rhoEstimator.cxx +++ b/PWGJE/TableProducer/rhoEstimator.cxx @@ -79,10 +79,6 @@ struct RhoEstimatorTask { Configurable jetAlgorithm{"jetAlgorithm", 0, "jet clustering algorithm. 0 = kT, 1 = C/A, 2 = Anti-kT"}; Configurable jetRecombScheme{"jetRecombScheme", 0, "jet recombination scheme. 0 = E-scheme, 1 = pT-scheme, 2 = pT2-scheme"}; Configurable bkgjetR{"bkgjetR", 0.2, "jet resolution parameter for determining background density"}; - Configurable bkgEtaMin{"bkgEtaMin", -0.7, "minimim pseudorapidity for determining background density"}; - Configurable bkgEtaMax{"bkgEtaMax", 0.7, "maximum pseudorapidity for determining background density"}; - Configurable bkgPhiMin{"bkgPhiMin", -6.283, "minimim phi for determining background density"}; - Configurable bkgPhiMax{"bkgPhiMax", 6.283, "maximum phi for determining background density"}; Configurable doSparse{"doSparse", false, "perfom sparse estimation"}; Configurable ghostRapMax{"ghostRapMax", 0.9, "Ghost rapidity max"}; Configurable ghostRepeat{"ghostRepeat", 1, "Ghost tiling repeats"}; @@ -127,14 +123,14 @@ struct RhoEstimatorTask { bkgSub.setJetAlgorithmAndScheme(static_cast(static_cast(config.jetAlgorithm)), static_cast(static_cast(config.jetRecombScheme))); bkgSub.setJetBkgR(config.bkgjetR); - bkgSub.setEtaMinMax(config.bkgEtaMin, config.bkgEtaMax); - bkgPhiMax_ = config.bkgPhiMax; - bkgPhiMin_ = config.bkgPhiMin; - if (config.bkgPhiMax > 98.0) { + bkgSub.setEtaMinMax(config.trackEtaMin, config.trackEtaMax); + bkgPhiMax_ = config.trackPhiMax; + bkgPhiMin_ = config.trackPhiMin; + if (config.trackPhiMax > 98.0) { bkgPhiMax_ = 2.0 * M_PI; } - if (config.bkgPhiMin < -98.0) { - bkgPhiMin_ = -2.0 * M_PI; + if (config.trackPhiMin < -98.0) { + bkgPhiMin_ = -1.0 * M_PI; } bkgSub.setPhiMinMax(bkgPhiMin_, bkgPhiMax_); @@ -223,7 +219,7 @@ struct RhoEstimatorTask { void processChargedMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoChargedMcTable(0.0, 0.0); return; } @@ -253,7 +249,7 @@ struct RhoEstimatorTask { void processD0McCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesD0MCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoD0McTable(0.0, 0.0); continue; } @@ -286,7 +282,7 @@ struct RhoEstimatorTask { { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoDplusMcTable(0.0, 0.0); continue; } @@ -318,7 +314,7 @@ struct RhoEstimatorTask { void processDsMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesDsMCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoDsMcTable(0.0, 0.0); continue; } @@ -350,7 +346,7 @@ struct RhoEstimatorTask { void processDstarMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesDstarMCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoDstarMcTable(0.0, 0.0); continue; } @@ -382,7 +378,7 @@ struct RhoEstimatorTask { void processLcMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesLcMCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoLcMcTable(0.0, 0.0); continue; } @@ -414,7 +410,7 @@ struct RhoEstimatorTask { void processB0McCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesB0MCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoB0McTable(0.0, 0.0); continue; } @@ -446,7 +442,7 @@ struct RhoEstimatorTask { void processBplusMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesBplusMCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoBplusMcTable(0.0, 0.0); continue; } @@ -478,7 +474,7 @@ struct RhoEstimatorTask { void processXicToXiPiPiMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesXicToXiPiPiMCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoXicToXiPiPiMcTable(0.0, 0.0); continue; } @@ -510,7 +506,7 @@ struct RhoEstimatorTask { void processDielectronMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles, aod::CandidatesDielectronMCP const& candidates) { for (auto& candidate : candidates) { - if (!jetderiveddatautilities::selectMcCollision(mcCollision, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { + if (!jetderiveddatautilities::selectCollision(mcCollision, eventSelectionBits, config.skipMBGapEvents, config.applyRCTSelections) || std::abs(mcCollision.posZ()) > config.vertexZCut) { rhoDielectronMcTable(0.0, 0.0); continue; } diff --git a/PWGJE/Tasks/CMakeLists.txt b/PWGJE/Tasks/CMakeLists.txt index f05c735ef21..55ec23b2c44 100644 --- a/PWGJE/Tasks/CMakeLists.txt +++ b/PWGJE/Tasks/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(JetSubstructureHFPCH OBJECT jetSubstructureHFPCH.cxx) target_link_libraries(JetSubstructureHFPCH PUBLIC O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore) +if(NOT DEFINED ENV{USE_RECC}) target_precompile_headers(JetSubstructureHFPCH PRIVATE [["PWGJE/DataModel/Jet.h"]] [["PWGJE/DataModel/JetSubstructure.h"]] @@ -25,6 +26,7 @@ target_precompile_headers(JetSubstructureHFPCH PRIVATE ) +endif() o2physics_add_dpl_workflow(emc-cellmonitor SOURCES emcCellMonitor.cxx @@ -373,6 +375,10 @@ if(FastJet_FOUND) SOURCES jetFormationTimeReclustering.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-correlation-d0 + SOURCES jetCorrelationD0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hf-debug SOURCES hfDebug.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore @@ -389,6 +395,10 @@ if(FastJet_FOUND) SOURCES jetDsSpectrumAndSubstructure.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-d0-ang-substructure + SOURCES jetD0AngSubstructure.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-cent-mult SOURCES bjetCentMult.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore diff --git a/PWGJE/Tasks/bjetTaggingGnn.cxx b/PWGJE/Tasks/bjetTaggingGnn.cxx index 27850fa3011..be7ec455b65 100644 --- a/PWGJE/Tasks/bjetTaggingGnn.cxx +++ b/PWGJE/Tasks/bjetTaggingGnn.cxx @@ -15,12 +15,14 @@ /// \author Changhwan Choi , Pusan National University #include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" #include "PWGJE/Core/JetTaggingUtilities.h" #include "PWGJE/DataModel/Jet.h" #include "PWGJE/DataModel/JetReducedData.h" #include "PWGJE/DataModel/JetTagging.h" #include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/Zorro.h" #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/EventSelection.h" @@ -126,6 +128,7 @@ struct BjetTaggingGnn { Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; // track level configurables + Configurable trackSelections{"trackSelections", "QualityTracks", "set track selections"}; Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; @@ -175,6 +178,8 @@ struct BjetTaggingGnn { std::vector eventSelectionBitsSelMC; std::vector eventSelectionBitsSel8; + int trackSelectionBits; + std::vector jetRadiiValues; void init(InitContext const&) @@ -186,6 +191,8 @@ struct BjetTaggingGnn { eventSelectionBitsSel8 = jetderiveddatautilities::initialiseEventSelectionBits("sel8"); eventSelectionBitsSelMC = jetderiveddatautilities::initialiseEventSelectionBits("selMC"); + trackSelectionBits = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + if (doprocessDataJetsTrig) { zorroSummary.setObject(zorro.getZorroSummary()); } @@ -236,7 +243,7 @@ struct BjetTaggingGnn { const AxisSpec axisTrackpT{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec axisTrackpTFine{1000, 0., 10., "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec axisJetpT{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisJetpT{250, 0., 250., "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec axisJetEta{200, -0.8, 0.8, "#it{#eta}_{jet}"}; const AxisSpec axisDb{200, dbMin, dbMax, "#it{D}_{b}"}; const AxisSpec axisDbFine{dbNbins, dbMin, dbMax, "#it{D}_{b}"}; @@ -250,27 +257,30 @@ struct BjetTaggingGnn { registry.add("h_jetMass", "", {HistType::kTH1F, {axisJetMass}}); registry.add("h_Db", "", {HistType::kTH1F, {axisDbFine}}); registry.add("h2_jetpT_Db", "", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_nTracks_Db", "", {HistType::kTH2F, {axisNTracks, axisDb}}); registry.add("h_gnnfeat_trackpT", "", {HistType::kTH1F, {{200, 0., 100., "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("h_gnnfeat_trackPhi", "", {HistType::kTH1F, {{200, 0., 2. * M_PI, "#it{#phi}"}}}); registry.add("h_gnnfeat_trackEta", "", {HistType::kTH1F, {{200, -0.9, 0.9, "#it{#eta}"}}}); registry.add("h_gnnfeat_trackCharge", "", {HistType::kTH1F, {{3, -1., 2., "#it{q}"}}}); - registry.add("h_gnnfeat_trackDCAxy", "", {HistType::kTH1F, {{200, -5., 5., "DCA_#it{xy} (cm)"}}}); - registry.add("h_gnnfeat_trackSigmaDCAxy", "", {HistType::kTH1F, {{200, 0., 5., "#it{#sigma}_{{DCA_#it{xy}} (cm)"}}}); - registry.add("h_gnnfeat_trackDCAz", "", {HistType::kTH1F, {{200, -5., 5., "DCA_#it{z} (cm)"}}}); - registry.add("h_gnnfeat_trackSigmaDCAz", "", {HistType::kTH1F, {{200, 0., 5., "#it{#sigma}_{{DCA_#it{z}} (cm)"}}}); + registry.add("h_gnnfeat_trackDCAxy", "", {HistType::kTH1F, {{200, -5., 5., "DCA_{#it{xy}} (cm)"}}}); + registry.add("h_gnnfeat_trackSigmaDCAxy", "", {HistType::kTH1F, {{200, 0., 5., "#it{#sigma}_{{DCA_{#it{xy}}} (cm)"}}}); + registry.add("h_gnnfeat_trackDCAz", "", {HistType::kTH1F, {{200, -5., 5., "DCA_{#it{z}} (cm)"}}}); + registry.add("h_gnnfeat_trackSigmaDCAz", "", {HistType::kTH1F, {{200, 0., 5., "#it{#sigma}_{{DCA_{#it{z}}} (cm)"}}}); registry.add("h_gnnfeat_trackITSChi2NCl", "", {HistType::kTH1F, {{200, 0., 40., "ITS #it{#chi}^{2}/ndf"}}}); registry.add("h_gnnfeat_trackTPCChi2NCl", "", {HistType::kTH1F, {{200, 0., 5., "TPC #it{#chi}^{2}/ndf"}}}); registry.add("h_gnnfeat_trackITSNCls", "", {HistType::kTH1F, {{8, 0., 8., "ITS NCls"}}}); registry.add("h_gnnfeat_trackTPCNCls", "", {HistType::kTH1F, {{153, 0., 153., "TPC NCls"}}}); registry.add("h_gnnfeat_trackTPCNCrossedRows", "", {HistType::kTH1F, {{153, 0., 153., "TPC NCrossedRows"}}}); - registry.add("h_gnnfeat_tracksIPxy", "", {HistType::kTH1F, {{200, -5., 5., "{sIP}_#it{xy}"}}}); - registry.add("h_gnnfeat_tracksIPz", "", {HistType::kTH1F, {{200, -5., 5., "{sIP}_#it{z}"}}}); + registry.add("h_gnnfeat_tracksIPxy", "", {HistType::kTH1F, {{200, -5., 5., "{sIP}_{#it{xy}}"}}}); + registry.add("h_gnnfeat_tracksIPz", "", {HistType::kTH1F, {{200, -5., 5., "{sIP}_{#it{z}}"}}}); if (doprocessDataTracks || doprocessMCDTracks) { registry.add("h_trackpT", "", {HistType::kTH1F, {axisTrackpT}}, callSumw2); registry.add("h_tracketa", "", {HistType::kTH1F, {{100, trackEtaMin, trackEtaMax, "#it{#eta}"}}}, callSumw2); registry.add("h_trackphi", "", {HistType::kTH1F, {{100, 0.0, 2.0 * M_PI, "#it{#phi}"}}}, callSumw2); + registry.add("h_dcaXY", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); } if (doprocessMCDTracks) { @@ -278,6 +288,23 @@ struct BjetTaggingGnn { registry.add("h_partpT_matched_fine", "", {HistType::kTH1F, {axisTrackpTFine}}, callSumw2); registry.add("h_partpT", "", {HistType::kTH1F, {axisTrackpT}}, callSumw2); registry.add("h_partpT_fine", "", {HistType::kTH1F, {axisTrackpTFine}}, callSumw2); + // DCA cut study histograms (pT > pTMin) + registry.add("h_dcaXY_coll_fake", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // tracks from fake collisions + registry.add("h_dcaXY_fake", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // fake tracks (no matched particle) + registry.add("h_dcaXY_coll_matched", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // tracks from matched collisions + registry.add("h_dcaXY_coll_matched_b", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // tracks from matched collisions, b hadron decay + registry.add("h_dcaXY_coll_matched_c", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // tracks from matched collisions, c hadron decay + registry.add("h_dcaXY_coll_matched_lf", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // tracks from matched collisions, others + registry.add("h_dcaXY_coll_mismatched", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // tracks from mismatched collisions + registry.add("h_dcaXY_npp", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{xy}}| (cm)"}}}, callSumw2); // non-physical primary tracks (GenStatusCode=-1) + registry.add("h_dcaZ_coll_fake", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ_fake", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ_coll_matched", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ_coll_matched_b", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ_coll_matched_c", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ_coll_matched_lf", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ_coll_mismatched", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); + registry.add("h_dcaZ_npp", "", {HistType::kTH1F, {{200, 0., 4., "|DCA_{#it{z}}| (cm)"}}}, callSumw2); } if (doprocessDataJetsSel || doprocessMCDJetsSel) { @@ -302,6 +329,9 @@ struct BjetTaggingGnn { registry.add("h2_jetpT_Db_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); registry.add("h2_jetpT_Db_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); registry.add("h2_jetpT_Db_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_nTracks_Db_b", "b-jet", {HistType::kTH2F, {axisNTracks, axisDb}}); + registry.add("h2_nTracks_Db_c", "c-jet", {HistType::kTH2F, {axisNTracks, axisDb}}); + registry.add("h2_nTracks_Db_lf", "lf-jet", {HistType::kTH2F, {axisNTracks, axisDb}}); registry.add("h2_Response_DetjetpT_PartjetpT", "", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); registry.add("h2_Response_DetjetpT_PartjetpT_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); registry.add("h2_Response_DetjetpT_PartjetpT_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); @@ -513,6 +543,7 @@ struct BjetTaggingGnn { registry.fill(HIST("h_jetMass"), analysisJet.mass()); registry.fill(HIST("h_Db"), analysisJet.scoreML()); registry.fill(HIST("h2_jetpT_Db"), analysisJet.pt(), analysisJet.scoreML()); + registry.fill(HIST("h2_nTracks_Db"), nTracks, analysisJet.scoreML()); if (doDataDriven) { if (doDataDrivenExtra) { @@ -567,19 +598,23 @@ struct BjetTaggingGnn { registry.fill(HIST("h_jetMass"), analysisJet.mass(), weightEvt); registry.fill(HIST("h_Db"), analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_jetpT_Db"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_nTracks_Db"), nTracks, analysisJet.scoreML(), weightEvt); if (jetFlavor == JetTaggingSpecies::beauty) { registry.fill(HIST("h_jetpT_b"), analysisJet.pt(), weightEvt); registry.fill(HIST("h_Db_b"), analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_jetpT_Db_b"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_nTracks_Db_b"), nTracks, analysisJet.scoreML(), weightEvt); } else if (jetFlavor == JetTaggingSpecies::charm) { registry.fill(HIST("h_jetpT_c"), analysisJet.pt(), weightEvt); registry.fill(HIST("h_Db_c"), analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_jetpT_Db_c"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_nTracks_Db_c"), nTracks, analysisJet.scoreML(), weightEvt); } else { registry.fill(HIST("h_jetpT_lf"), analysisJet.pt(), weightEvt); registry.fill(HIST("h_Db_lf"), analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_jetpT_Db_lf"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_nTracks_Db_lf"), nTracks, analysisJet.scoreML(), weightEvt); if (jetFlavor == JetTaggingSpecies::none) { registry.fill(HIST("h2_jetpT_Db_lf_none"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); } else { @@ -794,6 +829,10 @@ struct BjetTaggingGnn { registry.fill(HIST("h_trackpT"), track.pt()); registry.fill(HIST("h_tracketa"), track.eta()); registry.fill(HIST("h_trackphi"), track.phi()); + if (track.pt() >= trackPtMin) { + registry.fill(HIST("h_dcaXY"), std::fabs(track.dcaXY())); + registry.fill(HIST("h_dcaZ"), std::fabs(track.dcaZ())); + } } } PROCESS_SWITCH(BjetTaggingGnn, processDataTracks, "track information in Data", false); @@ -1061,20 +1100,63 @@ struct BjetTaggingGnn { bool matchedMcColl = collision.has_mcCollision() && std::fabs(collision.template mcCollision_as().posZ()) < vertexZCut; for (const auto& track : tracks) { - if (track.eta() <= trackEtaMin || track.eta() >= trackEtaMax) { + if (!jetderiveddatautilities::selectTrack(track, trackSelectionBits) || track.eta() <= trackEtaMin || track.eta() >= trackEtaMax) { continue; } registry.fill(HIST("h_trackpT"), track.pt(), weightEvt); registry.fill(HIST("h_tracketa"), track.eta(), weightEvt); registry.fill(HIST("h_trackphi"), track.phi(), weightEvt); + if (track.pt() >= trackPtMin) { + registry.fill(HIST("h_dcaXY"), std::fabs(track.dcaXY()), weightEvt); + registry.fill(HIST("h_dcaZ"), std::fabs(track.dcaZ()), weightEvt); + } - if (!matchedMcColl || !track.has_mcParticle()) { + if (!matchedMcColl) { + if (track.pt() >= trackPtMin) { + registry.fill(HIST("h_dcaXY_coll_fake"), std::fabs(track.dcaXY()), weightEvt); + registry.fill(HIST("h_dcaZ_coll_fake"), std::fabs(track.dcaZ()), weightEvt); + } + continue; + } + if (!track.has_mcParticle()) { + if (track.pt() >= trackPtMin) { + registry.fill(HIST("h_dcaXY_fake"), std::fabs(track.dcaXY()), weightEvt); + registry.fill(HIST("h_dcaZ_fake"), std::fabs(track.dcaZ()), weightEvt); + } continue; } auto particle = track.template mcParticle_as(); - if (particle.isPhysicalPrimary() && particle.eta() > trackEtaMin && particle.eta() < trackEtaMax) { - registry.fill(HIST("h2_trackpT_partpT"), track.pt(), particle.pt(), weightEvt); - registry.fill(HIST("h_partpT_matched_fine"), particle.pt(), weightEvt); + if (particle.eta() > trackEtaMin && particle.eta() < trackEtaMax) { + if (particle.isPhysicalPrimary()) { + registry.fill(HIST("h2_trackpT_partpT"), track.pt(), particle.pt(), weightEvt); + registry.fill(HIST("h_partpT_matched_fine"), particle.pt(), weightEvt); + } + if (track.pt() >= trackPtMin) { + // Track association accuracy as a function of DCA + if (particle.isPhysicalPrimary()) { + if (particle.mcCollisionId() == collision.mcCollisionId()) { + registry.fill(HIST("h_dcaXY_coll_matched"), std::fabs(track.dcaXY()), weightEvt); // Matched to particle from the same MC collision + registry.fill(HIST("h_dcaZ_coll_matched"), std::fabs(track.dcaZ()), weightEvt); + int origin = RecoDecay::getParticleOrigin(allParticles, particle, false); + if (origin == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("h_dcaXY_coll_matched_b"), std::fabs(track.dcaXY()), weightEvt); + registry.fill(HIST("h_dcaZ_coll_matched_b"), std::fabs(track.dcaZ()), weightEvt); + } else if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("h_dcaXY_coll_matched_c"), std::fabs(track.dcaXY()), weightEvt); + registry.fill(HIST("h_dcaZ_coll_matched_c"), std::fabs(track.dcaZ()), weightEvt); + } else { + registry.fill(HIST("h_dcaXY_coll_matched_lf"), std::fabs(track.dcaXY()), weightEvt); + registry.fill(HIST("h_dcaZ_coll_matched_lf"), std::fabs(track.dcaZ()), weightEvt); + } + } else { + registry.fill(HIST("h_dcaXY_coll_mismatched"), std::fabs(track.dcaXY()), weightEvt); // Matched to particle from a different MC collision + registry.fill(HIST("h_dcaZ_coll_mismatched"), std::fabs(track.dcaZ()), weightEvt); + } + } else { + registry.fill(HIST("h_dcaXY_npp"), std::fabs(track.dcaXY()), weightEvt); + registry.fill(HIST("h_dcaZ_npp"), std::fabs(track.dcaZ()), weightEvt); + } + } } } diff --git a/PWGJE/Tasks/jetBackgroundAnalysis.cxx b/PWGJE/Tasks/jetBackgroundAnalysis.cxx index 4760c63e1e4..84925d2dafe 100644 --- a/PWGJE/Tasks/jetBackgroundAnalysis.cxx +++ b/PWGJE/Tasks/jetBackgroundAnalysis.cxx @@ -119,37 +119,38 @@ struct JetBackgroundAnalysisTask { template void bkgFluctuationsRandomCone(TCollisions const& collision, TJets const& jets, TTracks const& tracks, float centrality) { - if (jets.size() > 0) { // Since the purpose of the fluctuation measurement is jet correction, events with zero accepted jets (from the jetfinder cuts) are excluded - float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); - float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); - float randomConePt = 0; - for (auto const& track : tracks) { - if (jetderiveddatautilities::selectTrack(track, trackSelection)) { - float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); - float dEta = track.eta() - randomConeEta; - if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - randomConePt += track.pt(); - } + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + float randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); } } - registry.fill(HIST("h2_centrality_rhorandomcone"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + } + registry.fill(HIST("h2_centrality_rhorandomcone"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); - // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles - { - float randomConePt = 0; - for (auto const& track : tracks) { - if (jetderiveddatautilities::selectTrack(track, trackSelection)) { - float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, static_cast(-o2::constants::math::PI)); // ignores actual phi of track - float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track - if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - randomConePt += track.pt(); - } - } + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles + float randomConePtRandomTrackDirection = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, static_cast(-o2::constants::math::PI)); // ignores actual phi of track + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePtRandomTrackDirection += track.pt(); } - registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirection"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); } + } + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirection"), centrality, randomConePtRandomTrackDirection - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); - // removing the leading jet from the random cone + // removing the leading jet from the random cone + const bool hasLead = jets.size() >= 1; + const bool hasSub = jets.size() >= 2; + float randomConePtWithoutLeadingJet = randomConePt; + if (hasLead) { float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-o2::constants::math::PI)); float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; @@ -162,41 +163,45 @@ struct JetBackgroundAnalysisTask { dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; } if (jetWasInCone) { - randomConePt = 0.0; + randomConePtWithoutLeadingJet = 0.0; for (auto const& track : tracks) { if (jetderiveddatautilities::selectTrack(track, trackSelection)) { // if track selection is uniformTrack, dcaXY and dcaZ cuts need to be added as they aren't in the selection so that they can be studied here float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); float dEta = track.eta() - randomConeEta; if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - randomConePt += track.pt(); + randomConePtWithoutLeadingJet += track.pt(); } } } } - registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); - - // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles, removing tracks from 2 leading jets - double randomConePtWithoutOneLeadJet = 0; - double randomConePtWithoutTwoLeadJet = 0; + } + registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), centrality, randomConePtWithoutLeadingJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles, removing tracks from 2 leading jets + double randomConePtWithoutOneLeadJet = randomConePtRandomTrackDirection; + double randomConePtWithoutTwoLeadJet = randomConePtRandomTrackDirection; + if (hasLead) { + randomConePtWithoutOneLeadJet = 0.0; + randomConePtWithoutTwoLeadJet = 0.0; for (auto const& track : tracks) { if (jetderiveddatautilities::selectTrack(track, trackSelection)) { float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, static_cast(-o2::constants::math::PI)); // ignores actual phi of track float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - if (!trackIsInJet(track, jets.iteratorAt(0))) { + const bool inLead = hasLead && trackIsInJet(track, jets.iteratorAt(0)); + const bool inSub = hasSub && trackIsInJet(track, jets.iteratorAt(1)); + if (!inLead) { randomConePtWithoutOneLeadJet += track.pt(); - if (jets.size() > 1 && !trackIsInJet(track, jets.iteratorAt(1))) { // if there are jets in the acceptance (from the jetfinder cuts) less than two then one cannot find 2 leading jets + if (!hasSub || !inSub) { randomConePtWithoutTwoLeadJet += track.pt(); } } } } } - registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithoutoneleadingjets"), centrality, randomConePtWithoutOneLeadJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); - if (jets.size() > 1) { - registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), centrality, randomConePtWithoutTwoLeadJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); - } } + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithoutoneleadingjets"), centrality, randomConePtWithoutOneLeadJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), centrality, randomConePtWithoutTwoLeadJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); } void processRho(soa::Filtered>::iterator const& collision, soa::Filtered const& tracks) diff --git a/PWGJE/Tasks/jetCorrelationD0.cxx b/PWGJE/Tasks/jetCorrelationD0.cxx new file mode 100644 index 00000000000..22c08b9b272 --- /dev/null +++ b/PWGJE/Tasks/jetCorrelationD0.cxx @@ -0,0 +1,383 @@ +// 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 jetCorrelationD0.cxx +/// \brief Task for analysing D0 triggered jet events. +/// \author Matthew Ockleton matthew.ockleton@cern.ch, University of Liverpool + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Common/Core/RecoDecay.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ + +namespace d0collisionInfo +{ +DECLARE_SOA_COLUMN(PosZ, posZ, float); +} // namespace d0collisionInfo + +DECLARE_SOA_TABLE(CollisionTables, "AOD", "COLLINFOTABLE", + o2::soa::Index<>, + d0collisionInfo::PosZ); + +DECLARE_SOA_TABLE(McCollisionTables, "AOD", "MCCOLLINFOTABLE", + o2::soa::Index<>, + d0collisionInfo::PosZ); + +namespace collisionInfo +{ +// DECLARE_SOA_INDEX_COLUMN(CollisionTable, collisionTable); +DECLARE_SOA_INDEX_COLUMN_CUSTOM(CollisionTable, collisionTable, "COLLINFOTABLES"); +// DECLARE_SOA_INDEX_COLUMN(McCollisionTable, mcCollisionTable); +DECLARE_SOA_INDEX_COLUMN_CUSTOM(McCollisionTable, mcCollisionTable, "MCCOLLINFOTABLES"); +} // namespace collisionInfo +namespace d0Info +{ +// D0 +DECLARE_SOA_COLUMN(D0PromptBDT, d0PromptBDT, float); +DECLARE_SOA_COLUMN(D0NonPromptBDT, d0NonPromptBDT, float); +DECLARE_SOA_COLUMN(D0BkgBDT, d0BkgBDT, float); +DECLARE_SOA_COLUMN(D0M, d0M, float); +DECLARE_SOA_COLUMN(D0Pt, d0Pt, float); +DECLARE_SOA_COLUMN(D0Eta, d0Eta, float); +DECLARE_SOA_COLUMN(D0Phi, d0Phi, float); +DECLARE_SOA_COLUMN(D0Y, d0Y, float); +DECLARE_SOA_COLUMN(D0McOrigin, d0McOrigin, float); +DECLARE_SOA_COLUMN(D0MD, d0MD, float); +DECLARE_SOA_COLUMN(D0PtD, d0PtD, float); +DECLARE_SOA_COLUMN(D0EtaD, d0EtaD, float); +DECLARE_SOA_COLUMN(D0PhiD, d0PhiD, float); +DECLARE_SOA_COLUMN(D0Reflection, d0Reflection, int); +} // namespace d0Info + +DECLARE_SOA_TABLE(D0DataTables, "AOD", "D0DATATABLE", + o2::soa::Index<>, + collisionInfo::CollisionTableId, + d0Info::D0PromptBDT, + d0Info::D0NonPromptBDT, + d0Info::D0BkgBDT, + d0Info::D0M, + d0Info::D0Pt, + d0Info::D0Eta, + d0Info::D0Phi, + d0Info::D0Y); + +DECLARE_SOA_TABLE(D0McPTables, "AOD", "D0MCPTABLE", + o2::soa::Index<>, + collisionInfo::McCollisionTableId, + d0Info::D0McOrigin, + d0Info::D0Pt, + d0Info::D0Eta, + d0Info::D0Phi, + d0Info::D0Y); + +namespace jetInfo +{ +// D0 tables +DECLARE_SOA_INDEX_COLUMN(D0DataTable, d0DataTable); +DECLARE_SOA_INDEX_COLUMN(D0McPTable, d0McPTable); +// Jet +DECLARE_SOA_COLUMN(JetPt, jetPt, float); +DECLARE_SOA_COLUMN(JetEta, jetEta, float); +DECLARE_SOA_COLUMN(JetPhi, jetPhi, float); +// D0-jet +DECLARE_SOA_COLUMN(D0JetDeltaPhi, d0JetDeltaPhi, float); +} // namespace jetInfo + +DECLARE_SOA_TABLE_STAGED(JetDataTables, "JETDATATABLE", + o2::soa::Index<>, + collisionInfo::CollisionTableId, + jetInfo::D0DataTableId, + jetInfo::JetPt, + jetInfo::JetEta, + jetInfo::JetPhi, + jetInfo::D0JetDeltaPhi); + +DECLARE_SOA_TABLE_STAGED(JetMCPTables, "JETMCPTABLE", + o2::soa::Index<>, + collisionInfo::McCollisionTableId, + jetInfo::D0McPTableId, + jetInfo::JetPt, + jetInfo::JetEta, + jetInfo::JetPhi, + jetInfo::D0JetDeltaPhi); + +} // namespace o2::aod + +struct JetCorrelationD0 { + // Define new table + Produces tableCollision; + Produces tableMcCollision; + Produces tableD0; + Produces tableD0MCParticle; + Produces tableJet; + Produces tableJetMCParticle; + + // Configurables + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "decide to run over MB gap events or not"}; + Configurable applyRCTSelections{"applyRCTSelections", true, "decide to apply RCT selections"}; + // Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + Configurable jetPtCutMin{"jetPtCutMin", 5.0, "minimum value of jet pt"}; + Configurable d0PtCutMin{"d0PtCutMin", 1.0, "minimum value of d0 pt"}; + Configurable vertexZCut{"vertexZCut", 10.0, "Accepted z-vertex range"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; + + // Filters + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut); + std::vector eventSelectionBits; + + // Histograms + HistogramRegistry registry{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + template + void fillD0Histograms(T const& d0, U const& scores) + { + registry.fill(HIST("hD0MlBkg"), scores[0]); + registry.fill(HIST("hD0MlNonPrompt"), scores[1]); + registry.fill(HIST("hD0MlPrompt"), scores[2]); + + registry.fill(HIST("hD0Pt"), d0.pt()); + registry.fill(HIST("hD0M"), d0.m()); + registry.fill(HIST("hD0Eta"), d0.eta()); + registry.fill(HIST("hD0Phi"), d0.phi()); + } + template + void fillJetHistograms(T const& jet, U const& dphi) + { + registry.fill(HIST("hJetPt"), jet.pt()); + registry.fill(HIST("hJetEta"), jet.eta()); + registry.fill(HIST("hJetPhi"), jet.phi()); + registry.fill(HIST("hJet3D"), jet.pt(), jet.eta(), jet.phi()); + registry.fill(HIST("h_Jet_pT_D0_Jet_dPhi"), jet.pt(), dphi); + } + + template + bool applyCollisionSelections(T const& collision) + { + registry.fill(HIST("hCollisions"), 0.5); // All collisions + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { + return false; + } + registry.fill(HIST("hCollisions"), 1.5); // Selected collisions + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + return true; + } + + template + // Jetbase is an MCD jet. We then loop through jettagv(MCP jets) to test if they match + // void fillMatchedHistograms(T const& jetBase, float weight = 1.0) // float leadingTrackPtBase, + void fillMatchedHistograms(T const& jetsBase, U const&, float weight = 1.0, float rho = 0.0) + { + for (const auto& jetBase : jetsBase) { + if (jetBase.has_matchedJetGeo()) { // geometric matching + for (auto const& jetTag : jetBase.template matchedJetGeo_as>()) { + registry.fill(HIST("hPtMatched"), jetBase.pt() - (rho * jetBase.area()), jetTag.pt(), weight); + registry.fill(HIST("hPtMatched1d"), jetTag.pt(), weight); + registry.fill(HIST("hPhiMatched"), jetBase.phi(), jetTag.phi(), weight); + registry.fill(HIST("hEtaMatched"), jetBase.eta(), jetTag.eta(), weight); + registry.fill(HIST("hPtResolution"), jetTag.pt(), (jetTag.pt() - (jetBase.pt() - (rho * jetBase.area()))) / jetTag.pt(), weight); + registry.fill(HIST("hPhiResolution"), jetTag.pt(), jetTag.phi() - jetBase.phi(), weight); + registry.fill(HIST("hEtaResolution"), jetTag.pt(), jetTag.eta() - jetBase.eta(), weight); + } + } + } + } + void init(InitContext const&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + // General Axes + AxisSpec axisEta = {100, -1.0, 1.0, "#eta"}; + AxisSpec axisPhi = {100, 0.0, o2::constants::math::TwoPI, "#phi"}; + AxisSpec axisInvMass = {500, 0, 10, "M (GeV/c)"}; + + // General Histograms + registry.add("hCollisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("hZvtxSelected", "Z vertex position;Z_{vtx};entries", {HistType::kTH1F, {{80, -20, 20}}}); + + // D0 Histograms + registry.add("hD0MlPrompt", "D0 ML Prompt Scores", {HistType::kTH1F, {{100, -1.0, 2.0}}}); + registry.add("hD0MlNonPrompt", "D0 ML NonPrompt Scores", {HistType::kTH1F, {{100, -1.0, 2.0}}}); + registry.add("hD0MlBkg", "D0 ML Background Scores", {HistType::kTH1F, {{100, -1.0, 2.0}}}); + + registry.add("hD0Pt", "D^{0} p_{T};p_{T}^{D^{0}} (GeV/c);entries", {HistType::kTH1F, {{500, -100, 400, "p_{T}^{D^{0}} (GeV/c)"}}}); + registry.add("hD0M", "D^{0} Mass;M_{#pi K} (GeV/c);entries", HistType::kTH1F, {axisInvMass}); + registry.add("hD0Eta", "D^{0} #eta ;#eta_{D^{0}};entries", HistType::kTH1F, {axisEta}); + registry.add("hD0Phi", "D^{0} #phi ;#phi_{D^{0}};entries", HistType::kTH1F, {axisPhi}); + + // Jet Histograms + registry.add("hJetPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}}); + registry.add("hJetEta", "jet #eta;#eta_{jet};entries", HistType::kTH1F, {axisEta}); + registry.add("hJetPhi", "jet #phi;#phi_{jet};entries", HistType::kTH1F, {axisPhi}); + registry.add("hJet3D", "3D jet distribution;p_{T};#eta;#phi", {HistType::kTH3F, {{500, -100, 400}, {100, -1.0, 1.0}, {100, 0.0, o2::constants::math::TwoPI}}}); + registry.add("h_Jet_pT_D0_Jet_dPhi", "p_{T, jet} vs #Delta #phi _{D^{0}, jet}", kTH2F, {{100, 0, 100}, {100, 0, o2::constants::math::TwoPI}}); + + // Matching histograms + registry.add("hPtMatched", "p_{T} matching;p_{T,det};p_{T,part}", {HistType::kTH2F, {{500, -100, 400}, {400, 0, 400}}}); + registry.add("hPtMatched1d", "p_{T} matching 1d;p_{T,part}", {HistType::kTH1F, {{400, 0, 400}}}); + registry.add("hPhiMatched", "#phi matching;#phi_{det};#phi_{part}", {HistType::kTH2F, {{100, 0.0, o2::constants::math::TwoPI}, {100, 0.0, o2::constants::math::TwoPI}}}); + registry.add("hEtaMatched", "#eta matching;#eta_{det};#eta_{part}", {HistType::kTH2F, {{100, -1, 1}, {100, -1, 1}}}); + registry.add("hPtResolution", "p_{T} resolution;p_{T,part};Relative Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -5.0, 5.0}}}); + registry.add("hPhiResolution", "#phi resolution;#p_{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -7.0, 7.0}}}); + registry.add("hEtaResolution", "#eta resolution;#p_{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -1.0, 1.0}}}); + } + void processData(soa::Filtered::iterator const& collision, + aod::CandidatesD0Data const& d0Candidates, + soa::Join const& jets) + { + if (!applyCollisionSelections(collision)) { + return; + } + tableCollision(collision.posZ()); + for (const auto& d0Candidate : d0Candidates) { + if (d0Candidate.pt() < d0PtCutMin) { // once settled on a mlcut, then add the lower bound of the systematics as a cut here + continue; + } + const auto scores = d0Candidate.mlScores(); + fillD0Histograms(d0Candidate, scores); + tableD0(tableCollision.lastIndex(), + scores[2], + scores[1], + scores[0], + d0Candidate.m(), + d0Candidate.pt(), + d0Candidate.eta(), + d0Candidate.phi(), + d0Candidate.y()); + for (const auto& jet : jets) { + if (jet.pt() < jetPtCutMin) { + continue; + } + float dphi = RecoDecay::constrainAngle(jet.phi() - d0Candidate.phi()); + if (std::abs(dphi - o2::constants::math::PI) > (o2::constants::math::PI / 2)) { // this is quite loose instead of pi/2 could do 0.6 + continue; + } + fillJetHistograms(jet, dphi); + tableJet(tableCollision.lastIndex(), + tableD0.lastIndex(), + jet.pt(), + jet.eta(), + jet.phi(), + dphi); + } + } + } + PROCESS_SWITCH(JetCorrelationD0, processData, "charged particle level jet analysis", true); + + void processMCDetector(soa::Filtered::iterator const& collision, + aod::CandidatesD0MCD const& d0Candidates, + soa::Join const& jets) + { + if (!applyCollisionSelections(collision)) { + return; + } + tableCollision(collision.posZ()); + for (const auto& d0Candidate : d0Candidates) { + if (d0Candidate.pt() < d0PtCutMin) { // once settled on a mlcut, then add the lower biund of the systematics as a cut here + continue; + } + const auto scores = d0Candidate.mlScores(); + fillD0Histograms(d0Candidate, scores); + tableD0(tableCollision.lastIndex(), // might want to add some more detector level D0 quantities like prompt or non prompt info + scores[2], + scores[1], + scores[0], + d0Candidate.m(), + d0Candidate.pt(), + d0Candidate.eta(), + d0Candidate.phi(), + d0Candidate.y()); + for (const auto& jet : jets) { + if (jet.pt() < jetPtCutMin) { + continue; + } + float dphi = RecoDecay::constrainAngle(jet.phi() - d0Candidate.phi()); + if (std::abs(dphi - o2::constants::math::PI) > (o2::constants::math::PI / 2)) { // this is quite loose instead of pi/2 could do 0.6 + continue; + } + fillJetHistograms(jet, dphi); + tableJet(tableCollision.lastIndex(), + tableD0.lastIndex(), + jet.pt(), + jet.eta(), + jet.phi(), + dphi); + } + } + } + PROCESS_SWITCH(JetCorrelationD0, processMCDetector, "charged particle level jet analysis", false); + + void processMCParticle(aod::JetMcCollision const& collision, + aod::CandidatesD0MCP const& d0MCPCandidates, + soa::Filtered> const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // build without this + return; + } + tableMcCollision(collision.posZ()); + for (const auto& d0MCPCandidate : d0MCPCandidates) { + if (d0MCPCandidate.pt() < d0PtCutMin) { + continue; + } + tableD0MCParticle(tableCollision.lastIndex(), + d0MCPCandidate.originMcGen(), + d0MCPCandidate.pt(), + d0MCPCandidate.eta(), + d0MCPCandidate.phi(), + d0MCPCandidate.y()); + + for (const auto& jet : jets) { + if (jet.pt() < jetPtCutMin) { + continue; + } + float dphi = RecoDecay::constrainAngle(jet.phi() - d0MCPCandidate.phi()); + if (std::abs(dphi - o2::constants::math::PI) > (o2::constants::math::PI / 2)) { + continue; + } + fillJetHistograms(jet, dphi); + tableJetMCParticle(tableCollision.lastIndex(), + tableD0MCParticle.lastIndex(), + jet.pt(), + jet.eta(), + jet.phi(), + dphi); + } + } + } + PROCESS_SWITCH(JetCorrelationD0, processMCParticle, "process MC Particle jets", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/jetD0AngSubstructure.cxx b/PWGJE/Tasks/jetD0AngSubstructure.cxx new file mode 100644 index 00000000000..05c1923dd96 --- /dev/null +++ b/PWGJE/Tasks/jetD0AngSubstructure.cxx @@ -0,0 +1,208 @@ +// 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 JetD0AngSubstructure.cxx +// +// \brief Analysis task for the reconstruction and study of charged jets +// containing D_0 mesons in pp collisions. +// \inherited from D0 fragmentation and Ds +// \P. Dhankher + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TVector3.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// Definition of a custom AOD table to store jet–D0 quantities +namespace o2::aod +{ +namespace jet_obj +{ +// Jet-related quantities +DECLARE_SOA_COLUMN(JetHfDist, jetHfDist, float); +DECLARE_SOA_COLUMN(JetPt, jetPt, float); +DECLARE_SOA_COLUMN(JetEta, jetEta, float); +DECLARE_SOA_COLUMN(JetPhi, jetPhi, float); +DECLARE_SOA_COLUMN(JetNConst, jetNConst, int); +DECLARE_SOA_COLUMN(JetAng, jetAng, float); +// D0 candidate quantities +DECLARE_SOA_COLUMN(HfPt, hfPt, float); +DECLARE_SOA_COLUMN(HfEta, hfEta, float); +DECLARE_SOA_COLUMN(HfPhi, hfPhi, float); +DECLARE_SOA_COLUMN(HfMass, hfMass, float); +DECLARE_SOA_COLUMN(HfY, hfY, float); +// ML scores +DECLARE_SOA_COLUMN(HfMlScore0, hfMlScore0, float); +DECLARE_SOA_COLUMN(HfMlScore1, hfMlScore1, float); +DECLARE_SOA_COLUMN(HfMlScore2, hfMlScore2, float); +} // namespace jet_obj +// AOD table definition +DECLARE_SOA_TABLE(JetObjTable, "AOD", "JETOBJTABLE", + jet_obj::JetHfDist, + jet_obj::JetPt, + jet_obj::JetEta, + jet_obj::JetPhi, + jet_obj::JetNConst, + jet_obj::JetAng, + jet_obj::HfPt, + jet_obj::HfEta, + jet_obj::HfPhi, + jet_obj::HfMass, + jet_obj::HfY, + jet_obj::HfMlScore0, + jet_obj::HfMlScore1, + jet_obj::HfMlScore2); +} // namespace o2::aod +struct JetD0AngSubstructure { + /** + * Histogram registry + * + * Contains: + * - Event and track histograms + * - Jet kinematic distributions + * - D0–jet substructure observables + */ + HistogramRegistry registry{"registry", + {{"h_collision_counter", "# of collisions;", {HistType::kTH1F, {{2, 0., 2.}}}}, + {"h_jet_counter", ";# of D^{0} jets;", {HistType::kTH1F, {{6, 0., 3.0}}}}, + {"h_d0_jet_projection", ";z^{D^{0},jet}_{||};dN/dz^{D^{0},jet}_{||}", {HistType::kTH1F, {{1000, 0., 10.}}}}, + {"h_d0_jet_distance_vs_projection", ";#DeltaR_{D^{0},jet};z^{D^{0},jet}_{||}", {HistType::kTH2F, {{1000, 0., 10.}, {1000, 0., 10.}}}}, + {"h_d0_jet_distance", ";#DeltaR_{D^{0},jet};dN/d(#DeltaR)", {HistType::kTH1F, {{1000, 0., 10.}}}}, + {"h_d0_jet_pt", ";p_{T,D^{0} jet};dN/dp_{T,D^{0} jet}", {HistType::kTH1F, {{200, 0., 10.}}}}, + {"h_d0_jet_eta", ";#eta_{T,D^{0} jet};dN/d#eta_{D^{0} jet}", {HistType::kTH1F, {{250, -5., 5.}}}}, + {"h_d0_jet_phi", ";#phi_{T,D^{0} jet};dN/d#phi_{D^{0} jet}", {HistType::kTH1F, {{250, -10., 10.}}}}, + {"h_d0_mass", ";m_{D^{0}});dN/dm_{D^{0}}", {HistType::kTH1F, {{1000, 0., 10.}}}}, + {"h_d0_eta", ";#eta_{D^{0}});dN/d#eta_{D_{}}", {HistType::kTH1F, {{250, -5., 5.}}}}, + {"h_d0_phi", ";#phi_{D^{0}});dN/d#phi_{D^{0}}", {HistType::kTH1F, {{250, -10., 10.}}}}, + {"h_d0_ang", ";#lambda_{#kappa}^{#alpha};counts", {HistType::kTH1F, {{100, 0., 1.}}}}}}; + + // Configurables + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; + Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; + + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable kappa{"kappa", 1.0, "angularity kappa"}; // to do: configurable from json + Configurable alpha{"alpha", 1.0, "angularity alpha"}; + + std::vector eventSelectionBits; + int trackSelection = -1; + + // Output table producer + Produces ObjJetTable; + + float angularity; + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + } + + template + void jetCalculateAngularity(T const& jet, U const& /*tracks*/) + { + angularity = 0.0; + for (auto& constituent : jet.template tracks_as()) { + angularity += std::pow(constituent.pt(), kappa) * std::pow(jetutilities::deltaR(jet, constituent) / (jet.r() / 100.f), alpha); + } + angularity /= std::pow(jet.pt(), kappa); + } + + void processDataChargedSubstructure(aod::JetCollision const& collision, + soa::Join const& jets, + aod::CandidatesD0Data const&, aod::JetTracks const& tracks) + { + // apply event selection and fill histograms for sanity check + registry.fill(HIST("h_collision_counter"), 0.5); + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !(std::abs(collision.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("h_collision_counter"), 1.5); + + // Loop over jets containing D0 candidates + for (const auto& jet : jets) { + // number of charged jets with D0 + registry.fill(HIST("h_jet_counter"), 0.5); + // obtaining jet 3-vector + TVector3 jetVector(jet.px(), jet.py(), jet.pz()); + + // Loop over D0 candidates associated to the jet + for (const auto& d0Candidate : jet.candidates_as()) { + // obtaining jet 3-vector + TVector3 d0Vector(d0Candidate.px(), d0Candidate.py(), d0Candidate.pz()); + + // calculating fraction of the jet momentum carried by the D0 along the direction of the jet axis + double zParallel = (jetVector * d0Vector) / (jetVector * jetVector); + + // calculating angular distance in eta-phi plane + double axisDistance = jetutilities::deltaR(jet, d0Candidate); + + jetCalculateAngularity(jet, tracks); + + // filling histograms + registry.fill(HIST("h_d0_jet_projection"), zParallel); + registry.fill(HIST("h_d0_jet_distance_vs_projection"), axisDistance, zParallel); + registry.fill(HIST("h_d0_jet_distance"), axisDistance); + registry.fill(HIST("h_d0_jet_pt"), jet.pt()); + registry.fill(HIST("h_d0_jet_eta"), jet.eta()); + registry.fill(HIST("h_d0_jet_phi"), jet.phi()); + registry.fill(HIST("h_d0_mass"), d0Candidate.m()); + registry.fill(HIST("h_d0_eta"), d0Candidate.eta()); + registry.fill(HIST("h_d0_phi"), d0Candidate.phi()); + registry.fill(HIST("h_d0_ang"), angularity); // add more axis + + // filling table + ObjJetTable(axisDistance, + jet.pt(), jet.eta(), jet.phi(), jet.tracks_as().size(), angularity, + d0Candidate.pt(), d0Candidate.eta(), d0Candidate.phi(), d0Candidate.m(), d0Candidate.y(), d0Candidate.mlScores()[0], d0Candidate.mlScores()[1], d0Candidate.mlScores()[2]); + + break; // get out of candidates' loop after first HF particle is found in jet + } // end of D0 candidates loop + + } // end of jets loop + + } // end of process function + PROCESS_SWITCH(JetD0AngSubstructure, processDataChargedSubstructure, "charged HF jet substructure", false); +}; +// Workflow definition +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-d0-ang-substructure"})}; } diff --git a/PWGJE/Tasks/jetDsSpectrumAndSubstructure.cxx b/PWGJE/Tasks/jetDsSpectrumAndSubstructure.cxx index a7810742abe..3e2e12d378a 100644 --- a/PWGJE/Tasks/jetDsSpectrumAndSubstructure.cxx +++ b/PWGJE/Tasks/jetDsSpectrumAndSubstructure.cxx @@ -30,7 +30,6 @@ #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Framework/HistogramRegistry.h" -#include #include #include #include @@ -42,7 +41,6 @@ #include "TVector3.h" #include -#include #include #include @@ -67,6 +65,12 @@ DECLARE_SOA_COLUMN(HfY, hfY, float); DECLARE_SOA_COLUMN(HfMlScore0, hfMlScore0, float); DECLARE_SOA_COLUMN(HfMlScore1, hfMlScore1, float); DECLARE_SOA_COLUMN(HfMlScore2, hfMlScore2, float); + +// extra +DECLARE_SOA_COLUMN(JetMass, jetMass, float); +DECLARE_SOA_COLUMN(JetGirth, jetGirth, float); +DECLARE_SOA_COLUMN(JetThrust, jetThrust, float); // lambda_2^1 +DECLARE_SOA_COLUMN(JetLambda11, jetLambda11, float); // lambda_1^1 } // namespace jet_distance DECLARE_SOA_TABLE(JetDistanceTable, "AOD", "JETDISTTABLE", @@ -82,46 +86,117 @@ DECLARE_SOA_TABLE(JetDistanceTable, "AOD", "JETDISTTABLE", jet_distance::HfY, jet_distance::HfMlScore0, jet_distance::HfMlScore1, - jet_distance::HfMlScore2); + jet_distance::HfMlScore2, + jet_distance::JetMass, + jet_distance::JetGirth, + jet_distance::JetThrust, + jet_distance::JetLambda11); } // namespace o2::aod struct JetDsSpecSubs { - HistogramRegistry registry{"registry", - {{"h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}}, - {"h_track_pt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_track_eta", "track #eta;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"h_track_phi", "track #varphi;#varphi_{track};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - {"h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"h_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - {"h_collision_counter", "# of collisions;", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_jet_counter", ";# of D_{S} jets;", {HistType::kTH1F, {{6, 0., 3.0}}}}, - {"h_ds_jet_projection", ";z^{D_{S},jet}_{||};dN/dz^{D_{S},jet}_{||}", {HistType::kTH1F, {{1000, 0., 2.}}}}, - {"h_ds_jet_distance_vs_projection", ";#DeltaR_{D_{S},jet};z^{D_{S},jet}_{||}", {HistType::kTH2F, {{1000, 0., 1.}, {1000, 0., 2.}}}}, - {"h_ds_jet_distance", ";#DeltaR_{D_{S},jet};dN/d(#DeltaR)", {HistType::kTH1F, {{1000, 0., 1.}}}}, - {"h_ds_jet_pt", ";p_{T,D_{S} jet};dN/dp_{T,D_{S} jet}", {HistType::kTH1F, {{1000, 0., 100.}}}}, - {"h_ds_jet_eta", ";#eta_{T,D_{S} jet};dN/d#eta_{D_{S} jet}", {HistType::kTH1F, {{250, -1., 1.}}}}, - {"h_ds_jet_phi", ";#phi_{T,D_{S} jet};dN/d#phi_{D_{S} jet}", {HistType::kTH1F, {{250, -1., 7.}}}}, - {"h_ds_mass", ";m_{D_{S}} (GeV/c^{2});dN/dm_{D_{S}}", {HistType::kTH1F, {{1000, 0., 6.}}}}, - {"h_ds_eta", ";#eta_{D_{S}} (GeV/c^{2});dN/d#eta_{D_{S}}", {HistType::kTH1F, {{250, -1., 1.}}}}, - {"h_ds_phi", ";#phi_{D_{S}} (GeV/c^{2});dN/d#phi_{D_{S}}", {HistType::kTH1F, {{250, -1., 7.}}}}}}; - Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + HistogramRegistry registry{ + "registry", + { + {"h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}}, + {"h_track_pt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"h_track_eta", "track #eta;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, + {"h_track_phi", "track #varphi;#varphi_{track};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, + {"h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, + {"h_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, + {"h_collision_counter", "# of collisions;", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"h_jet_counter", ";# of D_{S} jets;", {HistType::kTH1F, {{6, 0., 3.0}}}}, + {"h_ds_jet_projection", ";z^{D_{S},jet}_{||};dN/dz^{D_{S},jet}_{||}", {HistType::kTH1F, {{1000, 0., 2.}}}}, + {"h_ds_jet_distance_vs_projection", ";#DeltaR_{D_{S},jet};z^{D_{S},jet}_{||}", {HistType::kTH2F, {{1000, 0., 1.}, {1000, 0., 2.}}}}, + {"h_ds_jet_distance", ";#DeltaR_{D_{S},jet};dN/d(#DeltaR)", {HistType::kTH1F, {{1000, 0., 1.}}}}, + {"h_ds_jet_pt", ";p_{T,D_{S} jet};dN/dp_{T,D_{S} jet}", {HistType::kTH1F, {{1000, 0., 100.}}}}, + {"h_ds_jet_eta", ";#eta_{D_{S} jet};entries", {HistType::kTH1F, {{250, -1., 1.}}}}, + {"h_ds_jet_phi", ";#phi_{D_{S} jet};entries", {HistType::kTH1F, {{250, -1., 7.}}}}, + {"h_ds_mass", ";m_{D_{S}} (GeV/c^{2});entries", {HistType::kTH1F, {{1000, 0., 6.}}}}, + {"h_ds_eta", ";#eta_{D_{S}};entries", {HistType::kTH1F, {{250, -1., 1.}}}}, + {"h_ds_phi", ";#phi_{D_{S}};entries", {HistType::kTH1F, {{250, -1., 7.}}}}, + {"h_ds_jet_mass", ";m_{jet}^{ch} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{200, 0., 50.}}}}, + {"h_ds_jet_lambda11", ";#lambda_{1}^{1};entries", {HistType::kTH1F, {{200, 0., 1.0}}}}, + {"h_ds_jet_lambda12", ";#lambda_{2}^{1} (thrust);entries", {HistType::kTH1F, {{200, 0., 1.0}}}}, + {"h_ds_jet_girth", ";g (#equiv #lambda_{1}^{1}R);entries", {HistType::kTH1F, {{200, 0., 0.5}}}}, + {"h2_dsjet_pt_lambda11", ";#it{p}_{T,jet} (GeV/#it{c});#lambda_{1}^{1}", {HistType::kTH2F, {{100, 0., 100.}, {200, 0., 1.0}}}}, + {"h2_dsjet_pt_lambda12", ";#it{p}_{T,jet} (GeV/#it{c});#lambda_{2}^{1}", {HistType::kTH2F, {{100, 0., 100.}, {200, 0., 1.0}}}}, + {"h2_dsjet_pt_mass", ";#it{p}_{T,jet} (GeV/#it{c});m_{jet}^{ch} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, 0., 100.}, {200, 0., 50.0}}}}, + {"h2_dsjet_pt_girth", ";#it{p}_{T,jet} (GeV/#it{c});g", {HistType::kTH2F, {{100, 0., 100.}, {200, 0., 0.5}}}}, + {"h_ds_jet_lambda_extra", ";#lambda_{#alpha}^{#kappa};entries", {HistType::kTH1F, {{200, 0., 1.0}}}}, + {"h2_dsjet_pt_lambda_extra", ";#it{p}_{T,jet} (GeV/#it{c});#lambda_{#alpha}^{#kappa}", {HistType::kTH2F, {{100, 0., 100.}, {200, 0., 1.0}}}}, + }}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + // extra angularity knob + Configurable kappa{"kappa", 1.0f, "angularity kappa"}; + Configurable alpha{"alpha", 1.0f, "angularity alpha"}; + + bool doExtraAngularity = false; + std::vector eventSelectionBits; int trackSelection = -1; Produces distJetTable; + template + float computeLambda(JET const& jet, TRACKS const& tracks, float a, float k) + { + if (jet.pt() <= 0.f) { + return -1.f; + } + float sum = 0.f; + for (auto const& trk : tracks) { + const float dr = jetutilities::deltaR(jet, trk); + sum += std::pow(trk.pt(), k) * std::pow(dr, a); + } + const float R = jet.r() / 100.f; + const float denom = std::pow(jet.pt(), k) * std::pow(R, a); + if (denom <= 0.f) { + return -1.f; + } + return sum / denom; + } + + template + float computeJetMassFromTracksMass(TRACKS const& tracks) + { + double sumPx = 0.0, sumPy = 0.0, sumPz = 0.0, sumE = 0.0; + + for (auto const& trk : tracks) { + const double pt = trk.pt(); + const double phi = trk.phi(); + const double eta = trk.eta(); + + const double px = pt * std::cos(phi); + const double py = pt * std::sin(phi); + const double pz = pt * std::sinh(eta); + const double p = std::sqrt(px * px + py * py + pz * pz); + + sumPx += px; + sumPy += py; + sumPz += pz; + sumE += p; // massless + } + + const double m2 = sumE * sumE - (sumPx * sumPx + sumPy * sumPy + sumPz * sumPz); + return (m2 > 0.0) ? static_cast(std::sqrt(m2)) : 0.f; + } + void init(o2::framework::InitContext&) { eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + const bool is11 = (std::abs(kappa.value - 1.f) < 1e-6f) && (std::abs(alpha.value - 1.f) < 1e-6f); + const bool is12 = (std::abs(kappa.value - 1.f) < 1e-6f) && (std::abs(alpha.value - 2.f) < 1e-6f); + doExtraAngularity = !(is11 || is12); } Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); @@ -129,12 +204,12 @@ struct JetDsSpecSubs { void processCollisions(aod::JetCollision const& collision, aod::JetTracks const& tracks) { - registry.fill(HIST("h_collisions"), 0.5); if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collisions"), 1.5); + for (auto const& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; @@ -146,12 +221,12 @@ struct JetDsSpecSubs { } PROCESS_SWITCH(JetDsSpecSubs, processCollisions, "process JE collisions", false); - void processDataCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + void processDataCharged(soa::Filtered::iterator const& collision, + soa::Filtered const& jets) { if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - // jets -> charged jet for (auto& jet : jets) { registry.fill(HIST("h_jet_pt"), jet.pt()); registry.fill(HIST("h_jet_eta"), jet.eta()); @@ -165,31 +240,24 @@ struct JetDsSpecSubs { aod::CandidatesDsData const&, aod::JetTracks const&) { - // apply event selection and fill histograms for sanity check registry.fill(HIST("h_collision_counter"), 2.0); - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !(std::abs(collision.posZ()) < vertexZCut)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || + !(std::abs(collision.posZ()) < vertexZCut)) { return; } registry.fill(HIST("h_collision_counter"), 3.0); - // jets -> charged jet with Ds + for (const auto& jet : jets) { - // number of charged jets with Ds registry.fill(HIST("h_jet_counter"), 0.5); - // obtaining jet 3-vector + TVector3 jetVector(jet.px(), jet.py(), jet.pz()); for (const auto& dsCandidate : jet.candidates_as()) { - - // obtaining jet 3-vector TVector3 dsVector(dsCandidate.px(), dsCandidate.py(), dsCandidate.pz()); - // calculating fraction of the jet momentum carried by the Ds along the direction of the jet axis - double zParallel = (jetVector * dsVector) / (jetVector * jetVector); - - // calculating angular distance in eta-phi plane - double axisDistance = jetutilities::deltaR(jet, dsCandidate); + const double zParallel = (jetVector * dsVector) / (jetVector * jetVector); + const double axisDistance = jetutilities::deltaR(jet, dsCandidate); - // filling histograms registry.fill(HIST("h_ds_jet_projection"), zParallel); registry.fill(HIST("h_ds_jet_distance_vs_projection"), axisDistance, zParallel); registry.fill(HIST("h_ds_jet_distance"), axisDistance); @@ -200,25 +268,56 @@ struct JetDsSpecSubs { registry.fill(HIST("h_ds_eta"), dsCandidate.eta()); registry.fill(HIST("h_ds_phi"), dsCandidate.phi()); - // Retrieve ML scores safely - auto scores = dsCandidate.mlScores(); + auto jetTracks = jet.tracks_as(); + + const float lambda11 = computeLambda(jet, jetTracks, 1.f, 1.f); + const float lambda12 = computeLambda(jet, jetTracks, 2.f, 1.f); // thrust = λ_2^1 + const float mjet = computeJetMassFromTracksMass(jetTracks); - float s0 = (scores.size() > 0) ? scores[0] : -999.f; - float s1 = (scores.size() > 1) ? scores[1] : -999.f; - float s2 = (scores.size() > 2) ? scores[2] : -999.f; + const float R = jet.r() / 100.f; + const float girth = (lambda11 >= 0.f) ? (lambda11 * R) : -1.f; - distJetTable(axisDistance, + if (lambda11 >= 0.f) { + registry.fill(HIST("h_ds_jet_lambda11"), lambda11); + registry.fill(HIST("h2_dsjet_pt_lambda11"), jet.pt(), lambda11); + } + if (lambda12 >= 0.f) { + registry.fill(HIST("h_ds_jet_lambda12"), lambda12); + registry.fill(HIST("h2_dsjet_pt_lambda12"), jet.pt(), lambda12); + } + registry.fill(HIST("h_ds_jet_mass"), mjet); + registry.fill(HIST("h2_dsjet_pt_mass"), jet.pt(), mjet); + + if (girth >= 0.f) { + registry.fill(HIST("h_ds_jet_girth"), girth); + registry.fill(HIST("h2_dsjet_pt_girth"), jet.pt(), girth); + } + + if (doExtraAngularity) { + const float lambdaExtra = computeLambda(jet, jetTracks, alpha.value, kappa.value); + if (lambdaExtra >= 0.f) { + registry.fill(HIST("h_ds_jet_lambda_extra"), lambdaExtra); + registry.fill(HIST("h2_dsjet_pt_lambda_extra"), jet.pt(), lambdaExtra); + } + } + + auto scores = dsCandidate.mlScores(); + const float s0 = (scores.size() > 0) ? scores[0] : -999.f; + const float s1 = (scores.size() > 1) ? scores[1] : -999.f; + const float s2 = (scores.size() > 2) ? scores[2] : -999.f; + + distJetTable(static_cast(axisDistance), jet.pt(), jet.eta(), jet.phi(), - static_cast(jet.tracks_as().size()), + static_cast(jetTracks.size()), dsCandidate.pt(), dsCandidate.eta(), dsCandidate.phi(), dsCandidate.m(), dsCandidate.y(), - s0, s1, s2); - break; // get out of candidates' loop after first HF particle is found in jet - } // end of DS candidates loop + s0, s1, s2, + mjet, girth, lambda12, lambda11); - } // end of jets loop - - } // end of process function + break; // only first Ds per jet + } + } + } PROCESS_SWITCH(JetDsSpecSubs, processDataChargedSubstructure, "charged HF jet substructure", false); }; diff --git a/PWGJE/Tasks/jetFinderQA.cxx b/PWGJE/Tasks/jetFinderQA.cxx index 878083b557f..40956d71038 100644 --- a/PWGJE/Tasks/jetFinderQA.cxx +++ b/PWGJE/Tasks/jetFinderQA.cxx @@ -83,6 +83,14 @@ struct JetFinderQATask { Configurable intRateMax{"intRateMax", 50000.0, "maximum value of interaction rate axis"}; Configurable kappa{"kappa", 1.0, "angularity kappa"}; Configurable alpha{"alpha", 1.0, "angularity alpha"}; + Configurable checkCentFT0M{"checkCentFT0M", false, "0: centFT0C as default, 1: use centFT0M estimator"}; + + // Configurable qcCutOnJetMultVsPt{"qcCutOnJetMultVsPt", false, "debug configurable for LHC26a7 10% test production with strange high mult jet pupulation"}; + Configurable multCutCheck_proportionalFactor{"multCut_proportionalFactor", 0.5, "debug cut value for LHC26a7 10% test production with strange high mult jet pupulation"}; + Configurable multCutCheck_abscissaAtOrigin{"multCut_abscissaAtOrigin", 5, "debug cut value LHC26a7 10% test production with strange high mult jet pupulation"}; + Configurable multCutCheck_analyseMBGapEvents{"multCutCheck_analyseMBGapEvents", 0, "flag to choose to reject min. bias gap events; -1: MBGap only, 0: skip MBGap events, 1: analyse all events"}; + Configurable doMultCutCheck{"doMultCutCheck", false, "decide to apply multCutCheck or not"}; + Configurable multCutCheck_applyRCTSelections{"multCutCheck_applyRCTSelections", true, "decide to apply RCT selections"}; std::vector filledJetR_Both; std::vector filledJetR_Low; @@ -373,7 +381,7 @@ struct JetFinderQATask { registry.add("h_xsecErrSumWeighted", "Summed Cross section error per collision in pb with weights; Summed Cross section error per collision in pb with weights; entries", {HistType::kTH1F, {{1, 0., 1.}}}); } - AxisSpec occupancyAxis = {142, -1.5, 14000.5, "occupancy"}; + AxisSpec occupancyAxis = {140, -0.5, 13999.5, "occupancy"}; AxisSpec nTracksAxis = {16001, -1., 16000, "n tracks"}; if (doprocessOccupancyQA) { @@ -384,10 +392,61 @@ struct JetFinderQATask { registry.add("h2_occupancy_ntracksselptetacuts_presel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); registry.add("h2_occupancy_ntracksselptetacuts_postsel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); } + + if (doprocessQcMultCutCheck) { + std::vector centralityBinning{0., 10., 50., 70., 100}; + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + bool doSumw2 = true; + + AxisSpec centralityAxis = {1200, -10., 110., "Centrality"}; + AxisSpec trackPtAxis = {200, -0.5, 199.5, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec trackEtaAxis = {nBinsEta, -1.0, 1.0, "#eta"}; + AxisSpec phiAxis = {160, -1.0, 7.0, "#varphi"}; + AxisSpec jetPtAxis = {200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetPtAxisRhoAreaSub = {400, -200., 200., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetEtaAxis = {nBinsEta, -1.0, 1.0, "#eta"}; + + registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_collisions", "centrality vs collisions; centrality; collisions", {HistType::kTH2F, {centAxis, {4, 0.0, 4.0}}}); + // registry.add("h2_mccollision_pthardfromweight_pthardfromhepmcxsection", "ptHard from weight vs ptHard from HepMCXSections; ptHard_weight; ptHard_hepmcxsections", {HistType::kTH2F, {{200, 0.0, 200.0}, {200, 0.0, 200.0}}}); + + registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}, doSumw2); + registry.add("h2_centrality_collisions_weighted", "centrality vs collisions; centrality; collisions", {HistType::kTH2F, {centAxis, {4, 0.0, 4.0}}}, doSumw2); + // registry.add("h2_mccollision_pthardfromweight_pthardfromhepmcxsection_weighted", "ptHard from weight vs ptHard from HepMCXSections; ptHard_weight; ptHard_hepmcxsections", {HistType::kTH2F, {{200, 0.0, 200.0}, {200, 0.0, 200.0}}}, doSumw2); + + registry.add("h_collisions_zvertex", "position of collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.0}}}, doSumw2); + registry.add("h_collisions_ntracks", "N_{tracks};", {HistType::kTH1F, {{10000, 0.0, 10000.0}}}, doSumw2); + registry.add("h_collisions_njets", "N_{jets};", {HistType::kTH1F, {{10000, 0.0, 10000.0}}}, doSumw2); + + registry.add("h2_centrality_ntracks", "; centrality; N_{tracks};", {HistType::kTH2F, {{1100, 0., 110.0}, {10000, 0.0, 10000.0}}}); + registry.add("h2_centrality_njets", "; centrality; N_{jets};", {HistType::kTH2F, {{1100, 0., 110.0}, {10000, 0.0, 10000.0}}}); + registry.add("h2_ntracks_rho", "; N_{tracks}; #it{rho} (GeV/area);", {HistType::kTH2F, {{10000, 0.0, 10000.0}, {400, 0.0, 400.0}}}); + registry.add("h2_centrality_rho", "; centrality; #it{rho} (GeV/area);", {HistType::kTH2F, {{1100, 0., 110.}, {400, 0., 400.0}}}); + + registry.add("h2_centrality_track_pt", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {centAxis, {200, 0., 200.}}}); + registry.add("h2_centrality_track_eta", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {centAxis, {100, -1.0, 1.0}}}); + registry.add("h2_track_pt_track_sigmapt", "#sigma(#it{p}_{T})/#it{p}_{T}; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 10.}, {100000, 0.0, 10.0}}}); + registry.add("h2_track_pt_high_track_sigmapt", "#sigma(#it{p}_{T})/#it{p}_{T}; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {100000, 0.0, 10.0}}}); + registry.add("h2_track_pt_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 10.}, {10000, 0.0, 1.0}}}); + registry.add("h2_track_pt_high_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {10000, 0.0, 1.0}}}); + + registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxis}}, doSumw2); + registry.add("h_jet_eta", "jet eta;#eta; counts", {HistType::kTH1F, {jetEtaAxis}}, doSumw2); + registry.add("h_jet_phi", "jet phi;#phi; counts", {HistType::kTH1F, {phiAxis}}, doSumw2); + registry.add("h2_centrality_jet_pt", "centrality vs. jet pT;centrality; #it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH2F, {centralityAxis, jetPtAxis}}, doSumw2); + registry.add("h2_centrality_jet_eta", "centrality vs. jet eta;centrality; #eta; counts", {HistType::kTH2F, {centralityAxis, jetEtaAxis}}, doSumw2); + registry.add("h2_centrality_jet_phi", "centrality vs. jet phi;centrality; #varphi; counts", {HistType::kTH2F, {centralityAxis, phiAxis}}, doSumw2); + registry.add("h2_jet_pt_jet_area", "jet #it{p}_{T,jet} vs. Area_{jet}; #it{p}_{T,jet} (GeV/#it{c}); Area_{jet}", {HistType::kTH2F, {jetPtAxis, {150, 0., 1.5}}}, doSumw2); + registry.add("h2_jet_pt_jet_ntracks", "jet #it{p}_{T,jet} vs. N_{jet tracks}; #it{p}_{T,jet} (GeV/#it{c}); N_{jet, tracks}", {HistType::kTH2F, {jetPtAxis, {200, -0.5, 199.5}}}, doSumw2); + registry.add("h2_jet_pt_track_pt", "jet #it{p}_{T,jet} vs. #it{p}_{T,track}; #it{p}_{T,jet} (GeV/#it{c}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, trackPtAxis}}, doSumw2); + registry.add("h3_jet_pt_jet_eta_jet_phi", "jet pt vs. eta vs. phi", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, phiAxis}}, doSumw2); + } } Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); - Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && + ((checkCentFT0M ? aod::jcollision::centFT0M : aod::jcollision::centFT0C) >= centralityMin) && + ((checkCentFT0M ? aod::jcollision::centFT0M : aod::jcollision::centFT0C) < centralityMax)); PresliceUnsorted> CollisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; PresliceUnsorted> McCollisionsPerMCPCollision = aod::jmccollision::mcCollisionId; @@ -810,6 +869,64 @@ struct JetFinderQATask { registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), collision.centFT0M(), randomConePtWithoutTwoLeadJet - M_PI * randomConeR * randomConeR * collision.rho()); } + enum mbGapSelectionRequirement { + mbGapOnly = -1, + mbGapSkip = 0, + mbGapAndSignal = 1 + }; + + template + bool applyCollisionCuts_multCutCheck(TColl const& collision, bool fillHistograms = false, bool isWeighted = false, float eventWeight = 1.0) + { + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 0.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, multCutCheck_applyRCTSelections)) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 1.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 1.5, eventWeight); + } + + if (centrality < centralityMin || centralityMax < centrality) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 2.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); + } + + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 3.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 3.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 3.5, eventWeight); + } + + if (multCutCheck_analyseMBGapEvents == mbGapSelectionRequirement::mbGapOnly && collision.getSubGeneratorId() != jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return false; + } else if (multCutCheck_analyseMBGapEvents == mbGapSelectionRequirement::mbGapSkip && collision.getSubGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return false; + } + + return true; + } + void processJetsData(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::JetTracks const&) { if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { @@ -945,14 +1062,11 @@ struct JetFinderQATask { } PROCESS_SWITCH(JetFinderQATask, processJetsMCD, "jet finder QA mcd", false); - void processJetsMCDWeighted(soa::Filtered>::iterator const& collision, aod::JetMcCollisions const&, soa::Join const& jets, aod::JetTracks const&) + void processJetsMCDWeighted(soa::Filtered>::iterator const& collision, aod::JetMcCollisions const&, soa::Join const& jets, aod::JetTracks const&) { if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { return; } - if (collision.isOutlier()) { - return; - } for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; @@ -990,7 +1104,7 @@ struct JetFinderQATask { } PROCESS_SWITCH(JetFinderQATask, processJetsMCP, "jet finder QA mcp", false); - void processJetsMCPWeighted(soa::Join::iterator const& jet, aod::JetParticles const&, soa::Join const& mcCollisions, soa::Filtered> const& collisions) + void processJetsMCPWeighted(soa::Join::iterator const& jet, aod::JetParticles const&, soa::Join const& mcCollisions, soa::Filtered const& collisions) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; @@ -1007,7 +1121,7 @@ struct JetFinderQATask { } if (checkMcCollisionIsMatched) { auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, jet.mcCollisionId()); - if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits) && !collisionspermcpjet.begin().isOutlier()) { + if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits)) { fillMCPHistograms(jet, mcCollision.begin().weight(), mcCollision.begin().ptHard()); } } else { @@ -1047,7 +1161,7 @@ struct JetFinderQATask { } PROCESS_SWITCH(JetFinderQATask, processJetsMCPMCDMatched, "jet finder QA matched mcp and mcd", false); - void processJetsMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, + void processJetsMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, aod::JetMcCollisions const&, soa::Join const& mcdjets, soa::Join const&, @@ -1056,9 +1170,6 @@ struct JetFinderQATask { if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { return; } - if (collision.isOutlier()) { - return; - } for (const auto& mcdjet : mcdjets) { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; @@ -1246,7 +1357,7 @@ struct JetFinderQATask { } PROCESS_SWITCH(JetFinderQATask, processTracks, "QA for charged tracks", false); - void processTracksWeighted(soa::Join::iterator const& collision, + void processTracksWeighted(soa::Join::iterator const& collision, aod::JetMcCollisions const&, soa::Filtered> const& tracks) { @@ -1266,11 +1377,6 @@ struct JetFinderQATask { } registry.fill(HIST("h_collisions"), 2.5); registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); - if (collision.isOutlier()) { - return; - } - registry.fill(HIST("h_collisions"), 3.5); - registry.fill(HIST("h_collisions_weighted"), 3.5, eventWeight); fillTrackHistograms(collision, tracks, eventWeight, collision.mcCollision().ptHard()); } PROCESS_SWITCH(JetFinderQATask, processTracksWeighted, "QA for charged tracks weighted", false); @@ -1357,12 +1463,69 @@ struct JetFinderQATask { registry.fill(HIST("h2_occupancy_ntrackssel_presel"), occupancy, nTracksAllAcceptanceAndSelected); registry.fill(HIST("h2_occupancy_ntracksselptetacuts_presel"), occupancy, nTracksInAcceptanceAndSelected); if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { - registry.fill(HIST("h2_occupancy_ntracksall_postsel"), occupancy, nTracksAll); - registry.fill(HIST("h2_occupancy_ntrackssel_postsel"), occupancy, nTracksAllAcceptanceAndSelected); - registry.fill(HIST("h2_occupancy_ntracksselptetacuts_postsel"), occupancy, nTracksInAcceptanceAndSelected); + return; } + registry.fill(HIST("h2_occupancy_ntracksall_postsel"), occupancy, nTracksAll); + registry.fill(HIST("h2_occupancy_ntrackssel_postsel"), occupancy, nTracksAllAcceptanceAndSelected); + registry.fill(HIST("h2_occupancy_ntracksselptetacuts_postsel"), occupancy, nTracksInAcceptanceAndSelected); } PROCESS_SWITCH(JetFinderQATask, processOccupancyQA, "occupancy QA on jet derived data", false); + + void processQcMultCutCheck(soa::Filtered>::iterator const& collision, + soa::Join const& mcdjets, + soa::Filtered> const& tracks) + { + bool fillHistograms = true; + bool isWeighted = true; + float eventWeight = collision.weight(); + if (!applyCollisionCuts_multCutCheck(collision, fillHistograms, isWeighted, eventWeight)) { + return; + } + registry.fill(HIST("h_collisions_zvertex"), collision.posZ(), eventWeight); + + bool hasJetAboveMultCut = false; + for (auto const& mcdjet : mcdjets) { + if (mcdjet.tracksIds().size() > multCutCheck_proportionalFactor * mcdjet.pt() + multCutCheck_abscissaAtOrigin) { + hasJetAboveMultCut = true; + } + } + if (doMultCutCheck && hasJetAboveMultCut == false) { + return; + } + + registry.fill(HIST("h_collisions_ntracks"), tracks.size(), eventWeight); + registry.fill(HIST("h2_centrality_ntracks"), collision.centFT0M(), tracks.size(), eventWeight); + registry.fill(HIST("h_collisions_njets"), mcdjets.size(), eventWeight); + registry.fill(HIST("h2_centrality_njets"), collision.centFT0M(), mcdjets.size(), eventWeight); + registry.fill(HIST("h2_ntracks_rho"), tracks.size(), collision.rho(), eventWeight); + registry.fill(HIST("h2_centrality_rho"), collision.centFT0M(), collision.rho(), eventWeight); + + for (auto const& track : tracks) { + registry.fill(HIST("h2_centrality_track_pt"), collision.centFT0M(), track.pt(), eventWeight); + registry.fill(HIST("h2_centrality_track_eta"), collision.centFT0M(), track.eta(), eventWeight); + registry.fill(HIST("h2_track_pt_track_sigma1overpt"), track.pt(), track.sigma1Pt(), eventWeight); + registry.fill(HIST("h2_track_pt_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), eventWeight); + registry.fill(HIST("h2_track_pt_high_track_sigma1overpt"), track.pt(), track.sigma1Pt(), eventWeight); + registry.fill(HIST("h2_track_pt_high_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), eventWeight); + } + + for (auto const& mcdjet : mcdjets) { + registry.fill(HIST("h_jet_pt"), mcdjet.pt(), eventWeight); + registry.fill(HIST("h_jet_eta"), mcdjet.eta(), eventWeight); + registry.fill(HIST("h_jet_phi"), mcdjet.phi(), eventWeight); + registry.fill(HIST("h2_centrality_jet_pt"), collision.centFT0M(), mcdjet.pt(), eventWeight); + registry.fill(HIST("h2_centrality_jet_eta"), collision.centFT0M(), mcdjet.eta(), eventWeight); + registry.fill(HIST("h2_centrality_jet_phi"), collision.centFT0M(), mcdjet.phi(), eventWeight); + registry.fill(HIST("h3_jet_pt_jet_eta_jet_phi"), mcdjet.pt(), mcdjet.eta(), mcdjet.phi(), eventWeight); + + registry.fill(HIST("h2_jet_pt_jet_area"), mcdjet.pt(), mcdjet.area(), eventWeight); + registry.fill(HIST("h2_jet_pt_jet_ntracks"), mcdjet.pt(), mcdjet.tracksIds().size(), eventWeight); + for (const auto& constituent : mcdjet.template tracks_as>>()) { + registry.fill(HIST("h2_jet_pt_track_pt"), mcdjet.pt(), constituent.pt(), eventWeight); + } + } + } + PROCESS_SWITCH(JetFinderQATask, processQcMultCutCheck, "processing QC on collision, track and jet quantities after cut on collision based on jet quantities;", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGJE/Tasks/jetHadronRecoil.cxx b/PWGJE/Tasks/jetHadronRecoil.cxx index 94044235003..a16770e19f1 100644 --- a/PWGJE/Tasks/jetHadronRecoil.cxx +++ b/PWGJE/Tasks/jetHadronRecoil.cxx @@ -960,7 +960,7 @@ struct JetHadronRecoil { if (std::abs(mccollision.posZ()) > vertexZCut) { return; } - if (!jetderiveddatautilities::selectMcCollision(mccollision, skipMBGapEvents, applyRCTSelections)) { + if (!jetderiveddatautilities::selectCollision(mccollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } if (mccollision.ptHard() < pTHatMinEvent) { @@ -990,7 +990,7 @@ struct JetHadronRecoil { if (std::abs(mccollision.posZ()) > vertexZCut) { return; } - if (!jetderiveddatautilities::selectMcCollision(mccollision, skipMBGapEvents, applyRCTSelections)) { + if (!jetderiveddatautilities::selectCollision(mccollision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } if (mccollision.ptHard() < pTHatMinEvent) { diff --git a/PWGJE/Tasks/jetSpectraCharged.cxx b/PWGJE/Tasks/jetSpectraCharged.cxx index 8af8e45e7cc..09e02d67d4e 100644 --- a/PWGJE/Tasks/jetSpectraCharged.cxx +++ b/PWGJE/Tasks/jetSpectraCharged.cxx @@ -78,6 +78,7 @@ struct JetSpectraCharged { Configurable acceptSplitCollisions{"acceptSplitCollisions", 0, "0: only look at mcCollisions that are not split; 1: accept split mcCollisions, 2: accept split mcCollisions but only look at the first reco collision associated with it"}; Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection can also be applied at the jet finder level for jets only, here rejection is applied for collision and track process functions for the first time, and on jets in case it was set to false at the jet finder level"}; Configurable checkLeadConstituentPtForMcpJets{"checkLeadConstituentPtForMcpJets", false, "flag to choose whether particle level jets should have their lead track pt above leadingConstituentPtMin to be accepted; off by default, as leadingConstituentPtMin cut is only applied on MCD jets for the Pb-Pb analysis using pp MC anchored to Pb-Pb for the response matrix"}; + Configurable isMCGenOnly{"isMCGenOnly", false, "analysis is run over mcGen only"}; std::vector eventSelectionBits; int trackSelection = -1; @@ -106,11 +107,6 @@ struct JetSpectraCharged { AxisSpec jetPtAxisRhoAreaSub = {400, -200., 200., "#it{p}_{T} (GeV/#it{c})"}; AxisSpec jetEtaAxis = {nBinsEta, -1.0, 1.0, "#eta"}; - if (doprocessTracksQC || doprocessTracksQCWeighted) { - registry.add("h_track_pt", "track #it{p}_{T} ; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH1F, {trackPtAxis}}, doSumw2); - registry.add("h2_track_eta_track_phi", "track eta vs. track phi; #eta; #phi; counts", {HistType::kTH2F, {trackEtaAxis, phiAxis}}, doSumw2); - } - if (doprocessCollisions || doprocessCollisionsWeighted) { registry.add("h_collisions", "number of events;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}, doSumw2); registry.get(HIST("h_collisions"))->GetXaxis()->SetBinLabel(1, "allColl"); @@ -154,7 +150,7 @@ struct JetSpectraCharged { } registry.add("h2_centrality_mccollisions", "mc event status vs. centrality;entries;centrality", {HistType::kTH2F, {centralityAxis, {4, 0.0, 4.0}}}, doSumw2); } - if (doprocessSpectraMCP || doprocessSpectraMCPWeighted || doprocessMCCollisions || doprocessMCCollisionsWeighted) { + if (doprocessMCCollisions || doprocessMCCollisionsWeighted) { registry.add("h_mccollisions_zvertex", "position of mc collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.0}}}, doSumw2); } @@ -318,6 +314,13 @@ struct JetSpectraCharged { template bool applyMCCollisionCuts(TMCColl const& mccollision, TCollisions const& collisions, bool fillHistograms = false, bool isWeighted = false, float eventWeight = 1.0) { + if (isMCGenOnly) { + if (fillHistograms) { + registry.fill(HIST("h_mccollisions"), 0.5); + } + return true; + } // if isMCGenOnly is true, skip MC selection and accept all of them + float centrality = -1.0; // checkCentFT0M ? centrality = mccollision.centFT0M() : centrality = mccollision.centFT0C(); centrality = mccollision.centFT0M(); @@ -460,9 +463,8 @@ struct JetSpectraCharged { } template - void fillJetHistograms(TJets const& jet, float centrality, float weight = 1.0) + void fillJetHistograms(TJets const& jet, float centrality, float weight = 1.0, float pTHat = 999.0) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -484,9 +486,8 @@ struct JetSpectraCharged { } template - void fillJetAreaSubHistograms(TJets const& jet, float centrality, float rho, float weight = 1.0) + void fillJetAreaSubHistograms(TJets const& jet, float centrality, float rho, float weight = 1.0, float pTHat = 999.0) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -513,9 +514,8 @@ struct JetSpectraCharged { } template - void fillMCPHistograms(TJets const& jet, float weight = 1.0) + void fillMCPHistograms(TJets const& jet, float weight = 1.0, float pTHat = 999.0) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -535,9 +535,8 @@ struct JetSpectraCharged { } template - void fillMCPAreaSubHistograms(TJets const& jet, float rho = 0.0, float weight = 1.0) + void fillMCPAreaSubHistograms(TJets const& jet, float rho = 0.0, float weight = 1.0, float pTHat = 999.0) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -556,9 +555,8 @@ struct JetSpectraCharged { } template - void fillEventWiseConstituentSubtractedHistograms(TJets const& jet, float centrality, float weight = 1.0) + void fillEventWiseConstituentSubtractedHistograms(TJets const& jet, float centrality, float weight = 1.0, float pTHat = 999.0) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -568,17 +566,9 @@ struct JetSpectraCharged { } } - template - void fillTrackHistograms(TTracks const& track, float weight = 1.0) - { - registry.fill(HIST("h_track_pt"), track.pt(), weight); - registry.fill(HIST("h2_track_eta_track_phi"), track.eta(), track.phi(), weight); - } - template - void fillMatchedHistograms(TBase const& jetMCD, float weight = 1.0) + void fillMatchedHistograms(TBase const& jetMCD, float weight = 1.0, float pTHat = 999.0) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jetMCD.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -669,15 +659,14 @@ struct JetSpectraCharged { } template - void fillGeoMatchedAreaSubHistograms(TBase const& jetMCD, float rho, float mcrho = 0.0, float weight = 1.0) + void fillGeoMatchedAreaSubHistograms(TBase const& jetMCD, float rho, float mcrho = 0.0, float weight = 1.0, float pTHat = 999.0) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jetMCD.pt() > pTHatMaxMCD * pTHat) { return; } if (jetMCD.has_matchedJetGeo()) { for (const auto& jetMCP : jetMCD.template matchedJetGeo_as>()) { - if (jetMCP.pt() > pTHatMaxMCD * pTHat) { + if (jetMCP.pt() > pTHatMaxMCP * pTHat) { continue; } if (jetMCD.r() == round(selectedJetsRadius * 100.0f)) { @@ -698,42 +687,6 @@ struct JetSpectraCharged { } } - void processTracksQC(soa::Filtered::iterator const& collision, - soa::Filtered> const& tracks) - { - if (!applyCollisionCuts(collision)) { - return; - } - - for (auto const& track : tracks) { - if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { - continue; - } - fillTrackHistograms(track); - } - } - PROCESS_SWITCH(JetSpectraCharged, processTracksQC, "collisions and track QC for Data and MCD", false); - - void processTracksQCWeighted(soa::Filtered>::iterator const& collision, - aod::JetMcCollisions const&, - soa::Filtered> const& tracks) - { - bool fillHistograms = false; - bool isWeighted = true; - float eventWeight = collision.weight(); - if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { - return; - } - - for (auto const& track : tracks) { - if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { - continue; - } - fillTrackHistograms(track, eventWeight); - } - } - PROCESS_SWITCH(JetSpectraCharged, processTracksQCWeighted, "weighted collsions and tracks QC for MC", false); - void processCollisions(soa::Filtered::iterator const& collision) { bool fillHistograms = true; @@ -888,9 +841,10 @@ struct JetSpectraCharged { } PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubMCD, "jet spectra with rho-area subtraction for MCD", false); - void processSpectraMCDWeighted(soa::Filtered::iterator const& collision, + void processSpectraMCDWeighted(soa::Filtered::iterator const& collision, soa::Join const& jets, - aod::JetTracks const&) + aod::JetTracks const&, + aod::JetMcCollisions const&) { bool fillHistograms = false; bool isWeighted = true; @@ -898,7 +852,7 @@ struct JetSpectraCharged { if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { return; } - + float pTHat = collision.has_mcCollision() && collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); float centrality = -1.0; checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); @@ -909,14 +863,15 @@ struct JetSpectraCharged { if (!isAcceptedJet(jet)) { continue; } - fillJetHistograms(jet, centrality, eventWeight); + fillJetHistograms(jet, centrality, eventWeight, pTHat); } } PROCESS_SWITCH(JetSpectraCharged, processSpectraMCDWeighted, "jet finder QA mcd with weighted events", false); - void processSpectraAreaSubMCDWeighted(soa::Filtered>::iterator const& collision, + void processSpectraAreaSubMCDWeighted(soa::Filtered>::iterator const& collision, soa::Join const& jets, - aod::JetTracks const&) + aod::JetTracks const&, + aod::JetMcCollisions const&) { bool fillHistograms = false; bool isWeighted = true; @@ -924,7 +879,7 @@ struct JetSpectraCharged { if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { return; } - + float pTHat = collision.has_mcCollision() && collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); float centrality = -1.0; checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); @@ -935,7 +890,7 @@ struct JetSpectraCharged { if (!isAcceptedJet(jet)) { continue; } - fillJetAreaSubHistograms(jet, centrality, collision.rho(), eventWeight); + fillJetAreaSubHistograms(jet, centrality, collision.rho(), eventWeight, pTHat); } } PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubMCDWeighted, "jet spectra with rho-area subtraction for MCD", false); @@ -950,7 +905,6 @@ struct JetSpectraCharged { if (!applyMCCollisionCuts(mccollision, collisions)) { return; } - registry.fill(HIST("h_mccollisions_zvertex"), mccollision.posZ()); for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { @@ -1168,7 +1122,7 @@ struct JetSpectraCharged { if (!applyMCCollisionCuts(mccollision, collisions, fillHistograms, isWeighted, eventWeight)) { return; } - + float pTHat = mccollision.ptHard() < 999.0f ? mccollision.ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; @@ -1176,14 +1130,13 @@ struct JetSpectraCharged { if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { continue; } - double pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); int Nmax = 21; for (int N = 1; N < Nmax; N++) { if (jet.pt() < N * 0.25 * pTHat && jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h2_jet_ptcut_part"), jet.pt(), N * 0.25, eventWeight); } } - fillMCPHistograms(jet, eventWeight); + fillMCPHistograms(jet, eventWeight, pTHat); } } PROCESS_SWITCH(JetSpectraCharged, processSpectraMCPWeighted, "jet spectra for MC particle level weighted", false); @@ -1201,6 +1154,7 @@ struct JetSpectraCharged { if (!applyMCCollisionCuts(mccollision, collisions, fillHistograms, isWeighted, eventWeight)) { return; } + float pTHat = mccollision.ptHard() < 999.0f ? mccollision.ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); registry.fill(HIST("h_mccollisions_rho"), mccollision.rho(), eventWeight); for (auto const& jet : jets) { @@ -1210,7 +1164,7 @@ struct JetSpectraCharged { if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { continue; } - fillMCPAreaSubHistograms(jet, mccollision.rho(), eventWeight); + fillMCPAreaSubHistograms(jet, mccollision.rho(), eventWeight, pTHat); } } PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubMCPWeighted, "jet spectra with area-based subtraction for MC particle level", false); @@ -1279,10 +1233,11 @@ struct JetSpectraCharged { } PROCESS_SWITCH(JetSpectraCharged, processJetsMatched, "matched mcp and mcd jets", false); - void processJetsMatchedWeighted(soa::Filtered::iterator const& collision, + void processJetsMatchedWeighted(soa::Filtered::iterator const& collision, ChargedMCDMatchedJets const& mcdjets, ChargedMCPMatchedJets const&, - aod::JetTracks const&, aod::JetParticles const&) + aod::JetTracks const&, aod::JetParticles const&, + aod::JetMcCollisions const&) { bool fillHistograms = false; bool isWeighted = true; @@ -1290,12 +1245,12 @@ struct JetSpectraCharged { if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { return; } - + float pTHat = collision.has_mcCollision() && collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); for (const auto& mcdjet : mcdjets) { if (!isAcceptedJet(mcdjet)) { continue; } - fillMatchedHistograms(mcdjet, eventWeight); + fillMatchedHistograms(mcdjet, eventWeight, pTHat); } } PROCESS_SWITCH(JetSpectraCharged, processJetsMatchedWeighted, "matched mcp and mcd jets with weighted events", false); @@ -1333,6 +1288,7 @@ struct JetSpectraCharged { if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { return; } + float pTHat = collision.has_mcCollision() && collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); double mcrho = collision.has_mcCollision() ? collision.mcCollision_as().rho() : -1; @@ -1340,7 +1296,7 @@ struct JetSpectraCharged { if (!isAcceptedJet(mcdjet)) { continue; } - fillGeoMatchedAreaSubHistograms(mcdjet, collision.rho(), mcrho, eventWeight); + fillGeoMatchedAreaSubHistograms(mcdjet, collision.rho(), mcrho, eventWeight, pTHat); } } PROCESS_SWITCH(JetSpectraCharged, processJetsMatchedAreaSubWeighted, "matched mcp and mcd jets after area-based pt subtraction with weighted events", false); diff --git a/PWGJE/Tasks/jetSpectraEseTask.cxx b/PWGJE/Tasks/jetSpectraEseTask.cxx index e9eff0f6cc1..54dbc47901a 100644 --- a/PWGJE/Tasks/jetSpectraEseTask.cxx +++ b/PWGJE/Tasks/jetSpectraEseTask.cxx @@ -53,29 +53,11 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct JetSpectraEseTask { - ConfigurableAxis binJetPt{"binJetPt", {250, -50., 200.}, ""}; - ConfigurableAxis bindPhi{"bindPhi", {180, -o2::constants::math::PI, o2::constants::math::PI}, ""}; - ConfigurableAxis binESE{"binESE", {100, 0, 100}, ""}; - ConfigurableAxis binCos{"binCos", {100, -1.05, 1.05}, ""}; - ConfigurableAxis binOccupancy{"binOccupancy", {5000, 0, 25000}, ""}; - ConfigurableAxis binQVec{"binQVec", {500, -3, 3}, ""}; - ConfigurableAxis binCentrality{"binCentrality", {101, -1, 100}, ""}; - ConfigurableAxis binPhi{"binPhi", {60, -1.0, 7.0}, ""}; - ConfigurableAxis binEta{"binEta", {80, -0.9, 0.9}, ""}; - ConfigurableAxis binFit0{"binFit0", {100, 0, 50}, ""}; - ConfigurableAxis binFit13{"binFit13", {100, 0, 1.4}, ""}; - ConfigurableAxis binFit24{"binFit24", {100, 0, 10}, ""}; - ConfigurableAxis binTrackPt{"binTrackPt", {100, 0, 100}, ""}; - ConfigurableAxis dbinEta{"dbinEta", {100, -1.6, 1.6}, ""}; - ConfigurableAxis dbinPhi{"dbinPhi", {120, -o2::constants::math::PIHalf, 3 * o2::constants::math::PI / 2}, ""}; - Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; Configurable jetR{"jetR", 0.2, "jet resolution parameter"}; Configurable randomConeR{"randomConeR", 0.4, "size of random Cone for estimating background fluctuations"}; Configurable randomConeLeadJetDeltaR{"randomConeLeadJetDeltaR", -99.0, "min distance between leading jet axis and random cone (RC) axis; if negative, min distance is set to automatic value of R_leadJet+R_RC "}; Configurable vertexZCut{"vertexZCut", 10.0, "vertex z cut"}; - Configurable> centRange{"centRange", {0, 90}, "centrality region of interest"}; - Configurable cfgSelCentrality{"cfgSelCentrality", true, "Flag for centrality selection"}; // Configurable leadingTrackPtCut{"leadingTrackPtCut", 5.0, "leading jet pT cut"}; Configurable jetAreaFractionMin{"jetAreaFractionMin", -99, "used to make a cut on the jet areas"}; Configurable cfgCentVariant{"cfgCentVariant", false, "Flag for centrality variant 1"}; @@ -101,13 +83,11 @@ struct JetSpectraEseTask { Configurable jetEtaMin{"jetEtaMin", -0.7, "minimum jet pseudorapidity"}; Configurable jetEtaMax{"jetEtaMax", 0.7, "maximum jet pseudorapidity"}; - Configurable numberEventsMixed{"numberEventsMixed", 5, "number of events mixed in ME process"}; Configurable eventSelections{"eventSelections", "sel8FullPbPb", "choose event selection"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; Configurable cfgEvSelOccupancy{"cfgEvSelOccupancy", true, "Flag for occupancy cut"}; - Configurable> cfgCutOccupancy{"cfgCutOccupancy", {0, 1000}, "Occupancy cut"}; Configurable> cfgOccupancyPtCut{"cfgOccupancyPtCut", {0, 100}, "pT cut"}; @@ -120,25 +100,29 @@ struct JetSpectraEseTask { Configurable cfgEPRefB{"cfgEPRefB", "TPCpos", "EP reference B"}; Configurable cfgEPRefC{"cfgEPRefC", "TPCneg", "EP reference C"}; - AxisSpec jetPtAxis = {binJetPt, "#it{p}_{T,jet}"}; - AxisSpec dPhiAxis = {bindPhi, "#Delta#phi"}; - AxisSpec eseAxis = {binESE, "#it{q}_{2}"}; - AxisSpec cosAxis = {binCos, ""}; - AxisSpec occAxis = {binOccupancy, "Occupancy"}; - AxisSpec qvecAxis = {binQVec, "Q-vector"}; - AxisSpec centAxis = {binCentrality, "Centrality"}; - AxisSpec phiAxis = {binPhi, "#phi"}; - AxisSpec etaAxis = {binEta, "#eta"}; - AxisSpec detaAxis = {dbinEta, "#Delta#eta"}; - AxisSpec dphiAxis = {dbinPhi, "#Delta#phi"}; - AxisSpec fitAxis0 = {binFit0, "Fit0"}; - AxisSpec fitAxis13 = {binFit13, "Fit13"}; - AxisSpec fitAxis24 = {binFit24, "Fit24"}; - - AxisSpec trackPtAxis = {binTrackPt, "#it{p}_{T}"}; ConfigurableAxis assocTrackPt{"assocTrackPt", {VARIABLE_WIDTH, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "pT of associated track"}; + ConfigurableAxis jetPtAxis{"jetPtAxis", {VARIABLE_WIDTH, 0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0, 70.0, 100.0, 150.0, 200.0}, "#it{p}_{T,jet} (GeV/#it{c})"}; + ConfigurableAxis dPhiAxis{"dPhiAxis", {60, -o2::constants::math::PI, o2::constants::math::PI}, "#Delta#phi"}; + ConfigurableAxis eseAxis{"eseAxis", {100, 0, 100}, "#it{q}_{2}"}; + Configurable cfgSelCentrality{"cfgSelCentrality", true, "Flag for centrality selection"}; + Configurable> centRange{"centRange", {0, 90}, "centrality region of interest"}; + ConfigurableAxis centAxis{"centAxis", {91, -1, 90}, "centrality"}; + ConfigurableAxis cosAxis{"cosAxis", {50, -1.0, 1.0}, "cos(2(#Psi_{2}^{A}-#Psi_{2}^{B}))"}; + ConfigurableAxis occAxis{"occAxis", {5000, 0, 25000}, "Occupancy"}; + ConfigurableAxis qvecAxis{"qvecAxis", {60, -3, 3}, "Q-vector"}; + ConfigurableAxis phiAxis{"phiAxis", {30, -1.0, 7.0}, "#phi"}; + ConfigurableAxis etaAxis{"etaAxis", {30, -1.0, 1.0}, "#eta"}; + ConfigurableAxis detaAxis{"detaAxis", {60, -1.6, 1.6}, "#Delta#eta"}; + ConfigurableAxis dphiAxis{"dphiAxis", {120, -o2::constants::math::PIHalf, 3 * o2::constants::math::PI / 2}, "#Delta#phi"}; + ConfigurableAxis trackPtAxis{"trackPtAxis", {100, 0, 100}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis fitAxis0{"fitAxis0", {100, 0, 50}, ""}; + ConfigurableAxis fitAxis13{"fitAxis13", {100, 0, 1.4}, ""}; + ConfigurableAxis fitAxis24{"fitAxis24", {100, 0, 10}, ""}; ConfigurableAxis rhoAxis{"rhoAxis", {50, 0, 200}, "#rho"}; - ConfigurableAxis vertexZAxis{"vertexZAxis", {50, -10.0, 10.0}, "z vertex"}; + ConfigurableAxis vertexZAxis{"vertexZAxis", {20, -10.0, 10.0}, "z vertex"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "number of events mixed in ME process"}; + ConfigurableAxis binsCentrality{"binsCentrality", {VARIABLE_WIDTH, 0.0, 10., 30., 50, 70., 100.}, "Mixing bins - centrality"}; + ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; @@ -157,8 +141,6 @@ struct JetSpectraEseTask { Preslice mcdjetsPerJCollision = o2::aod::jet::collisionId; Preslice tracksPerJCollision = o2::aod::jtrack::collisionId; - ConfigurableAxis binsCentrality{"binsCentrality", {VARIABLE_WIDTH, 0.0, 10., 30., 50, 70., 100.}, "Mixing bins - centrality"}; - ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; SliceCache cache; using BinningType = ColumnBinningPolicy; BinningType corrBinning{{binsZVtx, binsCentrality}, true}; diff --git a/PWGJE/Tasks/recoilJets.cxx b/PWGJE/Tasks/recoilJets.cxx index 378c42875ed..08271300538 100644 --- a/PWGJE/Tasks/recoilJets.cxx +++ b/PWGJE/Tasks/recoilJets.cxx @@ -2663,7 +2663,7 @@ struct RecoilJets { template bool skipMCEvent(const Collision& coll) { - return !jetderiveddatautilities::selectMcCollision(coll, ev.skipMBGapEvents, rct.enable, rct.label, rct.rejectLimitedAcceptance, rct.requireZDC); + return !jetderiveddatautilities::selectCollision(coll, eventSelectionBits, ev.skipMBGapEvents, rct.enable, rct.label, rct.rejectLimitedAcceptance, rct.requireZDC); } template diff --git a/PWGJE/Tasks/statPromptPhoton.cxx b/PWGJE/Tasks/statPromptPhoton.cxx index 98c52aa45e7..4e13332dcfe 100644 --- a/PWGJE/Tasks/statPromptPhoton.cxx +++ b/PWGJE/Tasks/statPromptPhoton.cxx @@ -51,9 +51,9 @@ #include #include +#include #include #include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -96,6 +96,7 @@ struct statPromptPhoton { Configurable cfgTrackFilter{"cfgTrackFilter", "globalTracks", "set track selections"}; Configurable cfgJETracks{"cfgJETracks", false, "Enables running on derived JE data"}; Configurable cfgGenHistograms{"cfgGenHistograms", false, "Enables Generated histograms"}; + Configurable cfgGenReqRec{"cfgGenReqRec", false, "Only consider generated events which are successfully reconstructed"}; Configurable cfgRecHistograms{"cfgRecHistograms", false, "Enables Reconstructed histograms"}; Configurable cfgDataHistograms{"cfgDataHistograms", false, "Enables Data histograms"}; Configurable cfgTriggerMasks{"cfgTriggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; @@ -191,9 +192,52 @@ struct statPromptPhoton { histos.add("REC_TrueTrigger_V_PtHadSum_Photon", "REC_Trigger_V_PtHadSum_Photon", kTH2F, {{100, 0, 100}, pthadAxis}); histos.add("REC_dR_Photon", "REC_dR_Photon", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); histos.add("REC_dR_Stern", "REC_dR_Stern", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); + histos.add("REC_prompt_phiQA", "REC_prompt_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_prompt_etaQA", "REC_prompt_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_prompt_ptQA", "REC_prompt_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_decay_phiQA", "REC_decay_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_decay_etaQA", "REC_decay_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_decay_ptQA", "REC_decay_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_frag_phiQA", "REC_frag_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_frag_etaQA", "REC_frag_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_frag_ptQA", "REC_frag_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_direct_phiQA", "REC_direct_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_direct_etaQA", "REC_direct_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_direct_ptQA", "REC_direct_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_cluster_phiQA", "REC_cluster_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_cluster_etaQA", "REC_cluster_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_cluster_energyQA", "REC_cluster_energyQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_clusteriso_phiQA", "REC_clusteriso_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_clusteriso_etaQA", "REC_clusteriso_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_clusteriso_energyQA", "REC_clusteriso_energyQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_track_phiQA", "REC_track_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_track_etaQA", "REC_track_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_track_ptQA", "REC_track_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_cluster_direct_phiQA", "REC_cluster_direct_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_cluster_direct_etaQA", "REC_cluster_direct_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_cluster_direct_energyQA", "REC_cluster_direct_energyQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_cluster_frag_phiQA", "REC_cluster_frag_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_cluster_frag_etaQA", "REC_cluster_frag_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_cluster_frag_energyQA", "REC_cluster_frag_energyQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_cluster_both_phiQA", "REC_cluster_both_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_cluster_both_etaQA", "REC_cluster_both_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("REC_cluster_both_energyQA", "REC_cluster_both_energyQA", kTH1F, {{82, -1.0, 40.0}}); } if (cfgGenHistograms) { + histos.add("GEN_prompt_phiQA", "GEN_prompt_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("GEN_prompt_etaQA", "GEN_prompt_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("GEN_prompt_ptQA", "GEN_prompt_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("GEN_decay_phiQA", "GEN_decay_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("GEN_decay_etaQA", "GEN_decay_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("GEN_decay_ptQA", "GEN_decay_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("GEN_frag_phiQA", "GEN_frag_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("GEN_frag_etaQA", "GEN_frag_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("GEN_frag_ptQA", "GEN_frag_ptQA", kTH1F, {{82, -1.0, 40.0}}); + histos.add("GEN_direct_phiQA", "GEN_direct_phiQA", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("GEN_direct_etaQA", "GEN_direct_etaQA", kTH1F, {{100, -1, 1}}); + histos.add("GEN_direct_ptQA", "GEN_direct_ptQA", kTH1F, {{82, -1.0, 40.0}}); histos.add("GEN_nEvents", "GEN_nEvents", kTH1F, {{4, 0.0, 4.0}}); + histos.add("GEN_nEvents_simple", "GEN_nEvents", kTH1F, {{4, 0.0, 4.0}}); histos.add("GEN_True_Trigger_Energy", "GEN_True_Trigger_Energy", kTH1F, {{82, -1.0, 40.0}}); histos.add("GEN_Particle_Pt", "GEN_Particle_Pt", kTH1F, {{82, -1.0, 40.0}}); histos.add("GEN_True_Photon_Energy", "GEN_True_Photon_Energy", kTH1F, {{8200, -1.0, 40.0}}); @@ -420,6 +464,71 @@ struct statPromptPhoton { }; // end of track selection ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// + // Below is shamelessly stolen from Florian's gammetreeproducer code. + template + T iTopCopy(const T& particle) const + { + int iUp = particle.globalIndex(); + T currentParticle = particle; + int pdgCode = particle.pdgCode(); + auto mothers = particle.template mothers_as(); + while (iUp > 0 && mothers.size() == 1 && mothers[0].globalIndex() > 0 && mothers[0].pdgCode() == pdgCode) { + iUp = mothers[0].globalIndex(); + currentParticle = mothers[0]; + mothers = currentParticle.template mothers_as(); + } + return currentParticle; + } + + /// \brief Checks if a particle is a prompt photon + /// \param particle The MC particle to check + /// \return true if particle is a prompt photon, false otherwise + bool isPromptPhoton(const auto& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) < 90) { + return true; + } + return false; + } + /// \brief Checks if a particle is a direct prompt photon + /// \param particle The particle to check + /// \return true if particle is a direct prompt photon, false otherwise + bool isDirectPromptPhoton(const auto& particle) + { + // check if particle isa prompt photon + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) < 90) { + // find the top carbon copy + auto topCopy = iTopCopy(particle); + if (topCopy.pdgCode() == PDG_t::kGamma && std::abs(topCopy.getGenStatusCode()) < 40) { // < 40 is particle directly produced in hard scattering + return true; + } + } + return false; + } + /// \brief Checks if a particle is a fragmentation photon + /// \param particle The particle to check + /// \return true if particle is a fragmentation photon, false otherwise + bool isFragmentationPhoton(const auto& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) < 90) { + // find the top carbon copy + auto topCopy = iTopCopy(particle); + if (topCopy.pdgCode() == PDG_t::kGamma && std::abs(topCopy.getGenStatusCode()) >= 40) { // frag photon + return true; + } + } + return false; + } + /// \brief Checks if a particle is a decay photon + /// \param particle The particle to check + /// \return true if particle is a decay photon, false otherwise + bool isDecayPhoton(const auto& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) >= 90) { + return true; + } + return false; + } ///////////////////////////////////////////////////////////////////////////// // PROCESS @@ -1364,6 +1473,362 @@ struct statPromptPhoton { PROCESS_SWITCH(statPromptPhoton, processData, "processJE data", false); + int nEventsGenMC_Simple = 0; + void processMCGen_simple(filteredMCCollisions::iterator const& collision, soa::SmallGroups> const& recocolls, aod::JMcParticles const& mcParticles, jfilteredMCClusters const&) + { + nEventsGenMC_Simple++; + if (cfgDebug) { + if ((nEventsGenMC_Simple + 1) % 10000 == 0) { + std::cout << "Processed Gen MC Events: " << nEventsGenMC_Simple << std::endl; + } + } + histos.fill(HIST("GEN_nEvents_simple"), 0.5); + if (fabs(collision.posZ()) > cfgVtxCut) + return; + + if (cfgGenReqRec) { + if (recocolls.size() <= 0) // not reconstructed + return; + for (auto& recocoll : recocolls) { // poorly reconstructed + if (!recocoll.sel8()) + return; + if (fabs(recocoll.posZ()) > cfgVtxCut) + + return; + histos.fill(HIST("GEN_nEvents_simple"), 1.5); + + if (cfgEmcTrigger) { + if (!recocoll.isEmcalReadout()) + return; + } + histos.fill(HIST("GEN_nEvents_simple"), 2.5); + } + } + + // First pass: find all status -23 particles + for (auto& hardParticle : mcParticles) { + if (hardParticle.getGenStatusCode() != -23) + continue; + + bool isPhoton23 = (hardParticle.pdgCode() == 22); + + // For prompt: find the final-state photon descending from this -23 photon// + // For frag: find any final-state photon descending from this -23 non-photon// + // We search all final-state photons and check if they trace back here// + + for (auto& mcParticle : mcParticles) { + if (mcParticle.pdgCode() != 22) + continue; + if (mcParticle.getGenStatusCode() < 0) + continue; + if (std::fabs(mcParticle.getGenStatusCode()) >= 81 || !mcParticle.isPhysicalPrimary()) + continue; + + // Chase this final-state photon upward + int chaseindex = -1; + for (auto& mom : mcParticle.mothers_as()) { + chaseindex = mom.globalIndex(); + break; + } + if (chaseindex < 0) + continue; + + std::set visited; + bool chase = true; + bool hadronInChain = false; + bool reachedThisHard = false; + bool cleanPhotonChain = true; // all intermediates are photons + + while (chase) { + if (visited.count(chaseindex)) { + chase = false; + break; + } + visited.insert(chaseindex); + + for (auto& particle : mcParticles) { + if (particle.globalIndex() != chaseindex) + continue; + + if (particle.globalIndex() == hardParticle.globalIndex()) { + reachedThisHard = true; + chase = false; + break; + } + + int abspdg = std::abs(particle.pdgCode()); + if (abspdg > 100) + hadronInChain = true; + if (abspdg != 22) + cleanPhotonChain = false; + + int nextindex = -1; + for (auto& mom : particle.mothers_as()) { + nextindex = mom.globalIndex(); + break; + } + if (nextindex < 0) { + chase = false; + } else { + chaseindex = nextindex; + } + break; + } + } + + if (!reachedThisHard) + continue; + + if (isPhoton23 && cleanPhotonChain) { + // Case 1: -23 photon, clean photon chain — direct prompt + histos.fill(HIST("GEN_direct_phiQA"), mcParticle.phi()); + histos.fill(HIST("GEN_direct_etaQA"), mcParticle.eta()); + histos.fill(HIST("GEN_direct_ptQA"), mcParticle.pt()); + } else if (!isPhoton23 && !hadronInChain) { + // Case 2: -23 non-photon, no hadrons — fragmentation + histos.fill(HIST("GEN_frag_phiQA"), mcParticle.phi()); + histos.fill(HIST("GEN_frag_etaQA"), mcParticle.eta()); + histos.fill(HIST("GEN_frag_ptQA"), mcParticle.pt()); + } + } // final-state photon loop + } // hard particle loop + } + PROCESS_SWITCH(statPromptPhoton, processMCGen_simple, "processMC_QA_Gen", false); + int nEventsRecMC_simple = 0; + void processMCRec_simple(jfilteredCollisions::iterator const& collision, jfilteredMCClusters const& mcclusters, jTrackCandidates const&, soa::Join const&, TrackCandidates const&, aod::JMcParticles const& mcparticles, BcCandidates const&, jEMCtracks const& emctracks, aod::JetMcCollisions const&) + { + nEventsRecMC_simple++; + if (cfgDebug) { + if ((nEventsRecMC_simple + 1) % 10000 == 0) { + std::cout << "Processed JE Rec MC Events: " << nEventsRecMC_simple << std::endl; + } + } + histos.fill(HIST("REC_nEvents"), 0.5); + if (fabs(collision.posZ()) > cfgVtxCut) + return; + if (!collision.sel8()) + return; + histos.fill(HIST("REC_nEvents"), 1.5); + if (cfgEmcTrigger) { + if (!collision.isEmcalReadout()) + return; + } + histos.fill(HIST("REC_nEvents"), 2.5); + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) + return; + + for (auto& mccluster : mcclusters) { + histos.fill(HIST("REC_M02_BC"), mccluster.m02()); + if (mccluster.m02() < cfgLowM02) + continue; + if (mccluster.m02() > cfgHighM02) + continue; + if (mccluster.energy() < cfgLowClusterE) + continue; + if (mccluster.energy() > cfgHighClusterE) + continue; + if (fabs(mccluster.eta()) > cfgtrkMaxEta) + continue; + int ClusterHasDirectPhoton = 0; + int ClusterHasFragPhoton = 0; + auto ClusterParticles = mccluster.mcParticles_as(); + for (auto& clusterparticle : ClusterParticles) { + if (clusterparticle.pdgCode() != 22 && std::fabs(clusterparticle.pdgCode()) != 13) + continue; + if (clusterparticle.getGenStatusCode() < 0) + continue; + if (std::fabs(clusterparticle.getGenStatusCode()) >= 81) + continue; + + int chaseindex = -1; + for (auto& mom : clusterparticle.mothers_as()) { + chaseindex = mom.globalIndex(); + break; + } + if (chaseindex < 0) + continue; + + std::set visited; + bool chase = true; + bool hadronInChain = false; + bool cleanPhotonChain = true; + bool adrianprompt = false; + bool adrianfrag = false; + + while (chase) { + if (visited.count(chaseindex)) { + chase = false; + break; + } + visited.insert(chaseindex); + + for (auto& particle : mcparticles) { + if (particle.globalIndex() != chaseindex) + continue; + + if (particle.getGenStatusCode() == -23) { + if (particle.pdgCode() == 22 && cleanPhotonChain) { + adrianprompt = true; + } else if (particle.pdgCode() != 22 && !hadronInChain) { + adrianfrag = true; + } + chase = false; + break; + } + + int abspdg = std::abs(particle.pdgCode()); + if (abspdg > 100) + hadronInChain = true; + if (abspdg != 22) + cleanPhotonChain = false; + + int nextindex = -1; + for (auto& mom : particle.mothers_as()) { + nextindex = mom.globalIndex(); + break; + } + if (nextindex < 0) { + chase = false; + } else { + chaseindex = nextindex; + } + break; + } + } // chase + + if (adrianprompt) { + ClusterHasDirectPhoton++; + histos.fill(HIST("REC_direct_phiQA"), clusterparticle.phi()); + histos.fill(HIST("REC_direct_etaQA"), clusterparticle.eta()); + histos.fill(HIST("REC_direct_ptQA"), clusterparticle.pt()); + } + if (adrianfrag) { + ClusterHasFragPhoton++; + histos.fill(HIST("REC_frag_phiQA"), clusterparticle.phi()); + histos.fill(HIST("REC_frag_etaQA"), clusterparticle.eta()); + histos.fill(HIST("REC_frag_ptQA"), clusterparticle.pt()); + } + } // clusterparticle loop + + if (ClusterHasFragPhoton > 0) { + histos.fill(HIST("REC_cluster_frag_phiQA"), mccluster.phi()); + histos.fill(HIST("REC_cluster_frag_etaQA"), mccluster.eta()); + histos.fill(HIST("REC_cluster_frag_energyQA"), mccluster.energy()); + } + if (ClusterHasDirectPhoton > 0) { + histos.fill(HIST("REC_cluster_direct_phiQA"), mccluster.phi()); + histos.fill(HIST("REC_cluster_direct_etaQA"), mccluster.eta()); + histos.fill(HIST("REC_cluster_direct_energyQA"), mccluster.energy()); + } + if (ClusterHasDirectPhoton > 0 && ClusterHasFragPhoton > 0) { + histos.fill(HIST("REC_cluster_both_phiQA"), mccluster.phi()); + histos.fill(HIST("REC_cluster_both_etaQA"), mccluster.eta()); + histos.fill(HIST("REC_cluster_both_energyQA"), mccluster.energy()); + } + + // now we do cluster tracks + bool photontrigger = false; // is a neutral cluster + bool chargetrigger = false; // is definitely not a neutral cluster + auto tracksofcluster = mccluster.matchedTracks_as>(); + // first, we check if veto is required + double sumptT = 0; + bool clusterqa = false; + for (auto& ctrack : tracksofcluster) { + double etaT, phiT; + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(ctrack, trackFilter)) { + continue; + } + auto emctracksPerTrack = emctracks.sliceBy(EMCTrackPerTrack, ctrack.globalIndex()); + auto emctrack = emctracksPerTrack.iteratorAt(0); + etaT = emctrack.etaEmcal(); + phiT = emctrack.phiEmcal(); + } else { + auto ogtrack = ctrack.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + etaT = ogtrack.trackEtaEmcal(); + phiT = ogtrack.trackPhiEmcal(); + } + + double etaC = mccluster.eta(); + double phiC = mccluster.phi(); + double ptT = ctrack.pt(); + bool etatrigger = false; + bool phitrigger = false; + double phidiff = TVector2::Phi_mpi_pi(mccluster.phi() - ctrack.phi()); + double etadiff = mccluster.eta() - ctrack.eta(); + + if (cfgPtClusterCut) { + if (fabs(etaT - etaC) < (0.010 + pow(ptT + 4.07, -2.5))) { + etatrigger = true; + } + + if (fabs(TVector2::Phi_mpi_pi(phiT - phiC)) < (0.015 + pow(ptT + 3.65, -2.0))) { + phitrigger = true; + } + } else { + if (fabs(etadiff) < 0.05) { + etatrigger = true; + } + + if (fabs(phidiff) < 0.05) { + phitrigger = true; + } + } + + if (etatrigger && phitrigger) { + chargetrigger = true; + sumptT += ptT; + } + if (chargetrigger) { + if (!clusterqa) { + histos.fill(HIST("REC_Cluster_QA"), 1.5); + clusterqa = true; + } + } + histos.fill(HIST("REC_Track_v_Cluster_Phi"), phidiff); + histos.fill(HIST("REC_Track_v_Cluster_Eta"), etadiff); + histos.fill(HIST("REC_Track_v_Cluster_Phi_Eta"), phidiff, etadiff); + histos.fill(HIST("REC_track_phiQA"), ctrack.phi()); + histos.fill(HIST("REC_track_etaQA"), ctrack.eta()); + histos.fill(HIST("REC_track_ptQA"), ctrack.pt()); + } // track of cluster loop + + if (chargetrigger && sumptT > 0) { + double mccluster_over_sumptT = mccluster.energy() / sumptT; + histos.fill(HIST("REC_SumPt_BC"), mccluster_over_sumptT); + if (mccluster_over_sumptT < 1.7) { + histos.fill(HIST("REC_Cluster_QA"), 2.5); // veto fails, cluster is charged + } else { + histos.fill(HIST("REC_Cluster_QA"), 3.5); // veto is good, cluster is converted to neutral cluster + // chargetrigger = false; + histos.fill(HIST("REC_SumPt_AC"), mccluster_over_sumptT); + } + } // sumptT check + + if (!chargetrigger) { + photontrigger = true; + } + + if (photontrigger) { + histos.fill(HIST("REC_clusteriso_phiQA"), mccluster.phi()); + histos.fill(HIST("REC_clusteriso_etaQA"), mccluster.eta()); + histos.fill(HIST("REC_clusteriso_energyQA"), mccluster.energy()); + } + if (chargetrigger) { + histos.fill(HIST("REC_cluster_phiQA"), mccluster.phi()); + histos.fill(HIST("REC_cluster_etaQA"), mccluster.eta()); + histos.fill(HIST("REC_cluster_energyQA"), mccluster.energy()); + } + } // clusters + } // main function + PROCESS_SWITCH(statPromptPhoton, processMCRec_simple, "processMC_QA_Rce", false); + }; // end of main struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGJE/Tasks/trackEfficiency.cxx b/PWGJE/Tasks/trackEfficiency.cxx index 943aeae3dca..1228de53867 100644 --- a/PWGJE/Tasks/trackEfficiency.cxx +++ b/PWGJE/Tasks/trackEfficiency.cxx @@ -52,6 +52,7 @@ struct TrackEfficiency { Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections; other option: uniformTracks"}; Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events"}; + Configurable applyRCTSelections{"applyRCTSelections", true, "decide to apply RCT selections"}; // Tracking efficiency process function configurables: Configurable checkPrimaryPart{"checkPrimaryPart", true, "0: doesn't check mcparticle.isPhysicalPrimary() - 1: checks particle.isPhysicalPrimary()"}; @@ -80,18 +81,19 @@ struct TrackEfficiency { Configurable phiEffNBins{"phiEffNBins", 200, "number of bins for phi axis in efficiency plots"}; Configurable etaEffNBins{"etaEffNBins", 200, "number of bins for eta axis in efficiency plots"}; - Configurable ptHatMin{"ptHatMin", 5, "min pT hat of collisions"}; - Configurable ptHatMax{"ptHatMax", 300, "max pT hat of collisions"}; - Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable ptHatMin{"ptHatMin", -999, "min pT hat of collisions"}; + Configurable ptHatMax{"ptHatMax", 999, "max pT hat of collisions"}; + Configurable pTHatExponent{"pTHatExponent", 4.0, "exponent of the event weight for the calculation of pTHat"}; Configurable pTHatMaxFractionMCD{"pTHatMaxFractionMCD", 999.0, "maximum fraction of hard scattering for reconstructed track acceptance in MC"}; + Configurable pTHatMaxFractionMCP{"pTHatMaxFractionMCP", 999.0, "maximum fraction of hard scattering for particle acceptance in MC"}; - Configurable getPtHatFromHepMCXSection{"getPtHatFromHepMCXSection", true, "test configurable, configurable should be removed once well tested"}; Configurable useTrueTrackWeight{"useTrueTrackWeight", true, "test configurable, should be set to 1 then config removed once well tested"}; // systematics variation - Run 2 guidelines: https://twiki.cern.ch/twiki/bin/view/ALICE/AliDPGtoolsTrackSystematicUncertainty TrackSelection customTrackSelection; Configurable useCustomTrackSelection{"useCustomTrackSelection", false, "whether to use the custom cuts (used for cut variation for tracking efficiency systematics)"}; Configurable effSystMinNCrossedRowsTPC{"effSystMinNCrossedRowsTPC", 70, "min number of crossed rows TPC"}; + Configurable effSystMinNCrossedRowsTPCUseAlternateCut{"effSystMinNCrossedRowsTPCUseAlternateCut", false, "min number of crossed rows TPC - alternate cut of 120 - 5./pt"}; Configurable effSystMinNCrossedRowsOverFindableClustersTPC{"effSystMinNCrossedRowsOverFindableClustersTPC", 0.8, "min ratio of crossed rows over findable clusters TPC"}; Configurable effSystMaxChi2PerClusterTPC{"effSystMaxChi2PerClusterTPC", 4.0, "max chi2 per cluster TPC"}; Configurable effSystMaxChi2PerClusterITS{"effSystMaxChi2PerClusterITS", 36.0, "max chi2 per cluster ITS"}; @@ -118,6 +120,9 @@ struct TrackEfficiency { } } else { const auto& aodTrack = jetTrack.template track_as>(); + if (effSystMinNCrossedRowsTPCUseAlternateCut) { + customTrackSelection.SetMinNCrossedRowsTPC(120 - 5. / jetTrack.pt()); + } if (customTrackSelection.IsSelected(aodTrack)) { return true; } @@ -170,6 +175,10 @@ struct TrackEfficiency { float centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); for (auto const& mcparticle : mcparticles) { + float pTHat = simPtRef / (std::pow(weight, 1.0 / pTHatExponent)); + if (mcparticle.pt() > pTHatMaxFractionMCP * pTHat) { + continue; + } registry.fill(HIST("h2_centrality_particle_pt"), centrality, mcparticle.pt(), weight); registry.fill(HIST("h2_centrality_particle_eta"), centrality, mcparticle.eta(), weight); registry.fill(HIST("h2_centrality_particle_phi"), centrality, mcparticle.phi(), weight); @@ -372,6 +381,18 @@ struct TrackEfficiency { registry.add("h2_trackselplot_pt_dcaxy", "track selection variable: pt vs dca XY", {HistType::kTH2F, {{200, 0., 200.}, {1000, -1.0, 1.0}}}); registry.add("h2_trackselplot_pt_dcaz", "track selection variable: pt vs dca Z", {HistType::kTH2F, {{200, 0., 200.}, {4000, -4.0, 4.0}}}); } + + AxisSpec occupancyAxis = {140, -0.5, 13999.5, "occupancy"}; + AxisSpec nTracksAxis = {16001, -1., 16000, "n tracks"}; + + if (doprocessOccupancyQA) { + registry.add("h2_occupancy_ntracksall_presel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntracksall_postsel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntrackssel_presel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntrackssel_postsel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntracksselptetacuts_presel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntracksselptetacuts_postsel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + } } Preslice tracksPerJCollision = o2::aod::jtrack::collisionId; @@ -382,8 +403,7 @@ struct TrackEfficiency { Filter particleCuts = (aod::jmcparticle::pt >= trackQAPtMin && aod::jmcparticle::pt < trackQAPtMax && aod::jmcparticle::eta > trackQAEtaMin && aod::jmcparticle::eta < trackQAEtaMax); Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut); - void processEFficiencyPurity(soa::Join::iterator const& mcCollision, - soa::Join const&, + void processEFficiencyPurity(aod::JetMcCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, // smallgroups gives only the collisions associated to the current mccollision, thanks to the mccollisionlabel pre-integrated in jetcollisionsmcd soa::Join const& jetTracks, soa::Join const&, @@ -416,7 +436,7 @@ struct TrackEfficiency { bool centralityCheck = false; bool occupancyCheck = false; if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) - if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have their first associated collision not reconstructed hasSel8Coll = true; } if (!checkOccupancy || ((trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax))) { // check occupancy only in GP Pb-Pb MC @@ -428,7 +448,7 @@ struct TrackEfficiency { } } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks for (auto const& collision : collisions) { - if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split hasSel8Coll = true; } if (!checkOccupancy || ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax))) { // check occupancy only in GP Pb-Pb MC @@ -454,7 +474,7 @@ struct TrackEfficiency { } registry.fill(HIST("hMcCollCutsCounts"), 5.5); // at least one of the reconstructed collisions associated with this mcCollision is selected with regard to centrality - float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : 10. / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -500,7 +520,7 @@ struct TrackEfficiency { return; } - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents) || !(std::abs(collision.posZ()) < vertexZCut)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections) || !(std::abs(collision.posZ()) < vertexZCut)) { continue; } @@ -570,8 +590,7 @@ struct TrackEfficiency { } PROCESS_SWITCH(TrackEfficiency, processEFficiencyPurity, "Histograms for efficiency and purity quantities", true); - void processEFficiencyPurityWeighted(soa::Join::iterator const& mcCollision, - soa::Join const&, + void processEFficiencyPurityWeighted(aod::JetMcCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, // smallgroups gives only the collisions associated to the current mccollision, thanks to the mccollisionlabel pre-integrated in jetcollisionsmcd soa::Join const& jetTracks, soa::Join const&, @@ -603,7 +622,7 @@ struct TrackEfficiency { bool hasSel8Coll = false; bool centralityCheck = false; if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) - if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have their first associated collision not reconstructed hasSel8Coll = true; } centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); @@ -612,7 +631,7 @@ struct TrackEfficiency { } } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks for (auto const& collision : collisions) { - if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split hasSel8Coll = true; } centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -643,6 +662,9 @@ struct TrackEfficiency { registry.fill(HIST("hMcCollCutsCounts"), 6.5, mcCollision.weight()); // ptHat condition for (auto const& jMcParticle : jMcParticles) { + if (jMcParticle.pt() > pTHatMaxFractionMCP * pTHat) { + continue; + } registry.fill(HIST("hMcPartCutsCounts"), 0.5, mcCollision.weight()); // allPartsInSelMcColl if (!isChargedParticle(jMcParticle.pdgCode())) { @@ -675,7 +697,7 @@ struct TrackEfficiency { return; } - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents) || !(std::abs(collision.posZ()) < vertexZCut)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections) || !(std::abs(collision.posZ()) < vertexZCut)) { continue; } @@ -702,10 +724,13 @@ struct TrackEfficiency { registry.fill(HIST("hTrackCutsCounts"), 3.5, mcCollision.weight()); auto mcParticle = track.mcParticle_as(); - auto trueTrackMcCollision = mcParticle.mcCollision_as>(); + auto trueTrackMcCollision = mcParticle.mcCollision_as(); float trueTrackCollEventWeight = useTrueTrackWeight ? trueTrackMcCollision.weight() : mcCollEventWeight; auto jMcParticleFromTrack = track.mcParticle_as(); + if (jMcParticleFromTrack.pt() > pTHatMaxFractionMCP * pTHat) { + continue; + } if (!jMcParticleFromTrack.isPhysicalPrimary()) { registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_nonprimary"), track.pt(), track.eta(), track.phi(), trueTrackCollEventWeight); registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); @@ -758,7 +783,7 @@ struct TrackEfficiency { soa::Filtered> const& jetTracks, soa::Join const&) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -774,15 +799,14 @@ struct TrackEfficiency { PROCESS_SWITCH(TrackEfficiency, processTracksFromData, "QA for charged tracks in data", false); void processTracksFromMc(soa::Filtered>::iterator const& collision, - soa::Join const&, - soa::Join const&, + aod::JetMcCollisions const&, soa::Filtered> const& jetTracks, soa::Join const&) { if (!collision.has_mcCollision()) { // the collision is fake and has no associated mc coll; skip as .mccollision() cannot be called return; } - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -793,7 +817,7 @@ struct TrackEfficiency { return; } - float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -803,16 +827,15 @@ struct TrackEfficiency { PROCESS_SWITCH(TrackEfficiency, processTracksFromMc, "QA for charged tracks in MC without weights", false); void processTracksFromMcWeighted(soa::Filtered>::iterator const& collision, - soa::Join const&, - soa::Join const&, + aod::JetMcCollisions const&, soa::Filtered> const& jetTracks, soa::Join const&) { if (!collision.has_mcCollision()) { // the collision is fake and has no associated mc coll; skip as .mccollision() cannot be called return; } - float eventWeight = collision.mcCollision_as>().weight(); - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + float eventWeight = collision.mcCollision().weight(); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -823,7 +846,7 @@ struct TrackEfficiency { return; } - float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -832,8 +855,7 @@ struct TrackEfficiency { } PROCESS_SWITCH(TrackEfficiency, processTracksFromMcWeighted, "QA for charged tracks in weighted MC", false); - void processParticles(soa::Join::iterator const& mcCollision, - soa::Join const&, + void processParticles(aod::JetMcCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, soa::Filtered const& mcparticles, soa::Filtered const& tracks) @@ -849,7 +871,7 @@ struct TrackEfficiency { return; } - float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : 10. / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -858,7 +880,7 @@ struct TrackEfficiency { bool hasSel8Coll = false; bool centralityCheck = false; if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) - if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have their first associated collision not reconstructed hasSel8Coll = true; } centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); @@ -867,7 +889,7 @@ struct TrackEfficiency { } } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks for (auto const& collision : collisions) { - if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split hasSel8Coll = true; } centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -891,8 +913,7 @@ struct TrackEfficiency { } PROCESS_SWITCH(TrackEfficiency, processParticles, "QA for charged particles", false); - void processParticlesWeighted(soa::Join::iterator const& mcCollision, - soa::Join const&, + void processParticlesWeighted(aod::JetMcCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, soa::Filtered const& mcparticles, soa::Filtered const& tracks) @@ -913,7 +934,7 @@ struct TrackEfficiency { return; } - float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -922,7 +943,7 @@ struct TrackEfficiency { bool hasSel8Coll = false; bool centralityCheck = false; if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) - if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have their first associated collision not reconstructed hasSel8Coll = true; } centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); @@ -931,7 +952,7 @@ struct TrackEfficiency { } } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks for (auto const& collision : collisions) { - if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split hasSel8Coll = true; } centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -962,7 +983,7 @@ struct TrackEfficiency { registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h2_centrality_collisions"), centrality, 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } registry.fill(HIST("h_collisions"), 1.5); @@ -981,8 +1002,7 @@ struct TrackEfficiency { PROCESS_SWITCH(TrackEfficiency, processCollisionsFromData, "QA for reconstructed collisions in data", false); void processCollisionsFromMc(soa::Filtered>::iterator const& collision, - soa::Join const&, - soa::Join const&) + aod::JetMcCollisions const&) { float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -992,7 +1012,7 @@ struct TrackEfficiency { } registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h2_centrality_collisions"), centrality, 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } registry.fill(HIST("h_collisions"), 1.5); @@ -1008,7 +1028,7 @@ struct TrackEfficiency { registry.fill(HIST("h_collisions"), 3.5); registry.fill(HIST("h2_centrality_collisions"), centrality, 3.5); - float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -1018,8 +1038,7 @@ struct TrackEfficiency { PROCESS_SWITCH(TrackEfficiency, processCollisionsFromMc, "QA for reconstructed collisions in MC without weights", false); void processCollisionsFromMcWeighted(soa::Filtered>::iterator const& collision, - soa::Join const&, - soa::Join const&) + aod::JetMcCollisions const&) { float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -1027,10 +1046,10 @@ struct TrackEfficiency { registry.fill(HIST("h_fakecollisions"), 0.5); return; } - float eventWeight = collision.mcCollision_as>().weight(); + float eventWeight = collision.mcCollision().weight(); registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } registry.fill(HIST("h_collisions"), 1.5); @@ -1046,7 +1065,7 @@ struct TrackEfficiency { registry.fill(HIST("h_collisions"), 3.5); registry.fill(HIST("h_collisions_weighted"), 3.5, eventWeight); - float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -1055,22 +1074,21 @@ struct TrackEfficiency { } PROCESS_SWITCH(TrackEfficiency, processCollisionsFromMcWeighted, "QA for reconstructed collisions in weighted MC", false); - void processMcCollisions(soa::Join::iterator const& mcCollision, - soa::Join const&, + void processMcCollisions(aod::JetMcCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions) { // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is float eventWeight = mcCollision.weight(); - float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); - registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.mcCollision_as>().ptHard()); + float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.ptHard()); float centrality = -1; bool hasSel8Coll = false; bool centralityCheck = false; if (collisions.size() > 1) { // remove and move the if block below under if (collisions.size() < 1) { when mccoll.centFt0C has been fixed if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) - if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have their first associated collision not reconstructed hasSel8Coll = true; } centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); @@ -1079,7 +1097,7 @@ struct TrackEfficiency { } } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks for (auto const& collision : collisions) { - if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split hasSel8Coll = true; } centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -1124,8 +1142,7 @@ struct TrackEfficiency { } PROCESS_SWITCH(TrackEfficiency, processMcCollisions, "QA for McCollisions in MC without weights", false); - void processMcCollisionsWeighted(soa::Join::iterator const& mcCollision, - soa::Join const&, + void processMcCollisionsWeighted(aod::JetMcCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions) { if (skipMBGapEvents && mcCollision.getSubGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { @@ -1135,16 +1152,16 @@ struct TrackEfficiency { // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is float eventWeight = mcCollision.weight(); - float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); - registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.mcCollision_as>().ptHard()); - registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection_weighted"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.mcCollision_as>().ptHard(), eventWeight); + float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.ptHard()); + registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection_weighted"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.ptHard(), eventWeight); float centrality = -1; bool hasSel8Coll = false; bool centralityCheck = false; if (collisions.size() > 1) { // remove and move the if block below under if (collisions.size() < 1) { when mccoll.centFt0C has been fixed if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) - if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have their first associated collision not reconstructed hasSel8Coll = true; } centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); @@ -1153,7 +1170,7 @@ struct TrackEfficiency { } } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks for (auto const& collision : collisions) { - if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split hasSel8Coll = true; } centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -1205,7 +1222,7 @@ struct TrackEfficiency { void processTrackSelectionHistograms(soa::Filtered::iterator const& collision, soa::Join const& jetTracks, soa::Join const&) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); @@ -1235,6 +1252,38 @@ struct TrackEfficiency { } } PROCESS_SWITCH(TrackEfficiency, processTrackSelectionHistograms, "plots distributions of variables that are cut on during track selection", false); + + void processOccupancyQA(soa::Filtered::iterator const& collision, aod::JetTracks const& tracks) + { + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + + int occupancy = collision.trackOccupancyInTimeRange(); + int nTracksAll = tracks.size(); + int nTracksAllAcceptanceAndSelected = 0; + int nTracksInAcceptanceAndSelected = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + nTracksAllAcceptanceAndSelected += 1; + if (track.pt() >= trackQAPtMin && track.pt() < trackQAPtMax && track.eta() > trackQAEtaMin && track.eta() < trackQAEtaMax) { + nTracksInAcceptanceAndSelected += 1; + } + } + } + + registry.fill(HIST("h2_occupancy_ntracksall_presel"), occupancy, nTracksAll); + registry.fill(HIST("h2_occupancy_ntrackssel_presel"), occupancy, nTracksAllAcceptanceAndSelected); + registry.fill(HIST("h2_occupancy_ntracksselptetacuts_presel"), occupancy, nTracksInAcceptanceAndSelected); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { + return; + } + registry.fill(HIST("h2_occupancy_ntracksall_postsel"), occupancy, nTracksAll); + registry.fill(HIST("h2_occupancy_ntrackssel_postsel"), occupancy, nTracksAllAcceptanceAndSelected); + registry.fill(HIST("h2_occupancy_ntracksselptetacuts_postsel"), occupancy, nTracksInAcceptanceAndSelected); + } + PROCESS_SWITCH(TrackEfficiency, processOccupancyQA, "occupancy QA on jet derived data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/DataModel/LFAntinCexTables.h b/PWGLF/DataModel/LFAntinCexTables.h index 9e8f4ce1ca8..0e762f03e17 100644 --- a/PWGLF/DataModel/LFAntinCexTables.h +++ b/PWGLF/DataModel/LFAntinCexTables.h @@ -26,11 +26,12 @@ namespace o2::aod namespace antin_cex { // Metadata -DECLARE_SOA_COLUMN(IsCex, isCex, bool); // 1=CEX (from antin), 0=BG -DECLARE_SOA_COLUMN(MotherPdg, motherPdg, int32_t); // mother PDG -DECLARE_SOA_COLUMN(ColId, colId, int32_t); // mcCollisionId -DECLARE_SOA_COLUMN(PId, pId, int32_t); // proton MC id -DECLARE_SOA_COLUMN(AntipId, antipId, int32_t); // antiproton MC id +DECLARE_SOA_COLUMN(IsCex, isCex, bool); // 1=CEX (from antin), 0=BG +DECLARE_SOA_COLUMN(MotherPdg, motherPdg, int32_t); // mother PDG +DECLARE_SOA_COLUMN(MotherNHitIB, motherNHitIB, int); // mother IB Hits +DECLARE_SOA_COLUMN(ColId, colId, int32_t); // mcCollisionId +DECLARE_SOA_COLUMN(PId, pId, int32_t); // proton MC id +DECLARE_SOA_COLUMN(AntipId, antipId, int32_t); // antiproton MC id // MC (pair) DECLARE_SOA_COLUMN(McPairP, mcPairP, float); @@ -41,6 +42,12 @@ DECLARE_SOA_COLUMN(McAngleDeg, mcAngleDeg, float); DECLARE_SOA_COLUMN(McVtxX, mcVtxX, float); DECLARE_SOA_COLUMN(McVtxY, mcVtxY, float); DECLARE_SOA_COLUMN(McVtxZ, mcVtxZ, float); +DECLARE_SOA_COLUMN(VtxNAll, vtxNAll, int16_t); +DECLARE_SOA_COLUMN(VtxNCh, vtxNCh, int16_t); +DECLARE_SOA_COLUMN(VtxNNeut, vtxNNeut, int16_t); +DECLARE_SOA_COLUMN(VtxNPi0, vtxNPi0, int16_t); +DECLARE_SOA_COLUMN(VtxNGamma, vtxNGamma, int16_t); +DECLARE_SOA_COLUMN(VtxNN, vtxNN, int16_t); // Tracks (pair, fitter) DECLARE_SOA_COLUMN(TrkPairP, trkPairP, float); @@ -85,6 +92,8 @@ DECLARE_SOA_COLUMN(AntipTrkNClsIts, antipTrkNClsIts, int16_t); DECLARE_SOA_COLUMN(SelMask, selMask, uint32_t); DECLARE_SOA_COLUMN(PairPointingAngleDeg, pairPointingAngleDeg, float); +DECLARE_SOA_COLUMN(PvsvThetaDeg, pvsvThetaDeg, float); +DECLARE_SOA_COLUMN(PvsvPhiDeg, pvsvPhiDeg, float); DECLARE_SOA_COLUMN(PairPBalance, pairPBalance, float); DECLARE_SOA_COLUMN(PairPtBalance, pairPtBalance, float); DECLARE_SOA_COLUMN(PairQ, pairQ, float); @@ -118,9 +127,10 @@ DECLARE_SOA_COLUMN(AntipTrkTgl, antipTrkTgl, float); // Table DECLARE_SOA_TABLE(AntinCexPairs, "AOD", "ANTINCEX", antin_cex::IsCex, - antin_cex::MotherPdg, antin_cex::ColId, antin_cex::PId, antin_cex::AntipId, + antin_cex::MotherPdg, antin_cex::MotherNHitIB, antin_cex::ColId, antin_cex::PId, antin_cex::AntipId, antin_cex::McPairP, antin_cex::McPairPt, antin_cex::McPairPz, antin_cex::McDplane, antin_cex::McAngleDeg, antin_cex::McVtxX, antin_cex::McVtxY, antin_cex::McVtxZ, + antin_cex::VtxNAll, antin_cex::VtxNCh, antin_cex::VtxNNeut, antin_cex::VtxNPi0, antin_cex::VtxNGamma, antin_cex::VtxNN, antin_cex::TrkPairP, antin_cex::TrkPairPt, antin_cex::TrkPairPz, antin_cex::TrkAngleDeg, antin_cex::TrkVtxfitDcaPair, antin_cex::TrkVtxfitR, antin_cex::TrkVtxfitDistToPv, antin_cex::TrkVtxfitSecVtxX, antin_cex::TrkVtxfitSecVtxY, antin_cex::TrkVtxfitSecVtxZ, @@ -129,7 +139,7 @@ DECLARE_SOA_TABLE(AntinCexPairs, "AOD", "ANTINCEX", antin_cex::PTrkP, antin_cex::PTrkPx, antin_cex::PTrkPy, antin_cex::PTrkPz, antin_cex::PTrkEta, antin_cex::PTrkTpcSignal, antin_cex::PTrkNClsIts, antin_cex::AntipTrkP, antin_cex::AntipTrkPx, antin_cex::AntipTrkPy, antin_cex::AntipTrkPz, antin_cex::AntipTrkEta, antin_cex::AntipTrkTpcSignal, antin_cex::AntipTrkNClsIts, antin_cex::SelMask, - antin_cex::PairPointingAngleDeg, antin_cex::PairPBalance, antin_cex::PairPtBalance, antin_cex::PairQ, + antin_cex::PairPointingAngleDeg, antin_cex::PvsvThetaDeg, antin_cex::PvsvPhiDeg, antin_cex::PairPBalance, antin_cex::PairPtBalance, antin_cex::PairQ, antin_cex::DPairP, antin_cex::DPairPt, antin_cex::DPairPz, antin_cex::DOpenAngle, antin_cex::SVNearestLayerId, antin_cex::SVDeltaRToLayer, antin_cex::PTrkItsHitMap, antin_cex::APTrkItsHitMap, antin_cex::PLayersOk, antin_cex::APLayersOk, diff --git a/PWGLF/DataModel/LFHypernucleiTables.h b/PWGLF/DataModel/LFHypernucleiTables.h index ca389cf928b..9ff524dd347 100644 --- a/PWGLF/DataModel/LFHypernucleiTables.h +++ b/PWGLF/DataModel/LFHypernucleiTables.h @@ -59,6 +59,8 @@ DECLARE_SOA_COLUMN(NTPCclusHe, nTPCclusHe, uint8_t); // Number DECLARE_SOA_COLUMN(NTPCclusPi, nTPCclusPi, uint8_t); // Number of TPC clusters of the Pi daughter DECLARE_SOA_COLUMN(NTPCpidClusHe, nTPCpidClusHe, uint8_t); // Number of TPC clusters with PID information of the He daughter DECLARE_SOA_COLUMN(NTPCpidClusPi, nTPCpidClusPi, uint8_t); // Number of TPC clusters with PID information of the Pi daughter +DECLARE_SOA_COLUMN(NTPCCrossedRowsHe, nTPCCrossedRowsHe, uint8_t); // Number of TPC crossed rows of the He daughter +DECLARE_SOA_COLUMN(NTPCCrossedRowsPi, nTPCCrossedRowsPi, uint8_t); // Number of TPC crossed rows of the Pi daughter DECLARE_SOA_COLUMN(TPCsignalHe, tpcSignalHe, uint16_t); // TPC signal of the He daughter DECLARE_SOA_COLUMN(TPCsignalPi, tpcSignalPi, uint16_t); // TPC signal of the Pi daughter DECLARE_SOA_COLUMN(TPCChi2He, tpcChi2He, float); // TPC chi2 of the He daughter @@ -99,7 +101,7 @@ DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, - hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, @@ -118,7 +120,7 @@ DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, - hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, @@ -134,7 +136,7 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, - hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, @@ -163,7 +165,7 @@ DECLARE_SOA_TABLE(DataHypCandsWColl, "AOD", "HYPCANDSWCOLL", hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, - hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, diff --git a/PWGLF/DataModel/LFNonPromptCascadeTables.h b/PWGLF/DataModel/LFNonPromptCascadeTables.h index 16c86667ad1..7d0a9c156a8 100644 --- a/PWGLF/DataModel/LFNonPromptCascadeTables.h +++ b/PWGLF/DataModel/LFNonPromptCascadeTables.h @@ -124,6 +124,9 @@ DECLARE_SOA_COLUMN(ToiMask, toiMask, uint32_t); DECLARE_SOA_COLUMN(RunNumber, runNumber, int); DECLARE_SOA_COLUMN(NoSameBunchPileup, noSameBunchPileup, bool); DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); +DECLARE_SOA_COLUMN(PtGen, ptGen, float); +DECLARE_SOA_COLUMN(PtRec, ptRec, float); +DECLARE_SOA_COLUMN(MultGen, multGen, int); } // namespace NPCascadeTable DECLARE_SOA_TABLE(NPCascTable, "AOD", "NPCASCTABLE", @@ -454,7 +457,12 @@ DECLARE_SOA_TABLE(NPPileUpTable, "AOD", "NPPileUpTABLE", aod::collision::NumContrib, NPCascadeTable::MultNTracksGlobal, NPCascadeTable::CentFT0M, - NPCascadeTable::MultFT0M); + NPCascadeTable::MultFT0M) +DECLARE_SOA_TABLE(NPMCNegativesTable, "AOD", "NPMCNegativesTABLE", + NPCascadeTable::PtGen, + NPCascadeTable::PtRec, + NPCascadeTable::MultNTracksGlobal, + NPCascadeTable::MultGen); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFNONPROMPTCASCADETABLES_H_ diff --git a/PWGLF/DataModel/LFResonanceTables.h b/PWGLF/DataModel/LFResonanceTables.h index 8a04eb4ffdd..e5d9662b89e 100644 --- a/PWGLF/DataModel/LFResonanceTables.h +++ b/PWGLF/DataModel/LFResonanceTables.h @@ -210,6 +210,8 @@ DECLARE_SOA_COLUMN(CascTransRadius, cascTransRadius, float); DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! X position of the decay vertex DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! Y position of the decay vertex DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay vertex +DECLARE_SOA_COLUMN(Alpha, alpha, float); //! Alpha of the decay vertex +DECLARE_SOA_COLUMN(QtArm, qtarm, float); //! Armenteros Qt of the decay vertex DECLARE_SOA_COLUMN(TpcSignal10, tpcSignal10, int8_t); //! TPC signal of the track x10 DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosPi10, daughterTPCNSigmaPosPi10, int8_t); //! TPC PID x10 of the positive daughter as Pion DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosKa10, daughterTPCNSigmaPosKa10, int8_t); //! TPC PID x10 of the positive daughter as Kaon @@ -648,6 +650,8 @@ DECLARE_SOA_TABLE(ResoV0s, "AOD", "RESOV0", resodaughter::DecayVtxX, resodaughter::DecayVtxY, resodaughter::DecayVtxZ, + resodaughter::Alpha, + resodaughter::QtArm, // resodaughter::Pt, resodaughter::Eta, resodaughter::Phi, diff --git a/PWGLF/DataModel/LFSigmaProtonTables.h b/PWGLF/DataModel/LFSigmaHadTables.h similarity index 52% rename from PWGLF/DataModel/LFSigmaProtonTables.h rename to PWGLF/DataModel/LFSigmaHadTables.h index d9eafbedda5..a70af6317fd 100644 --- a/PWGLF/DataModel/LFSigmaProtonTables.h +++ b/PWGLF/DataModel/LFSigmaHadTables.h @@ -10,8 +10,8 @@ // or submit itself to any jurisdiction. /// -/// \file LFKinkDecayTables.h -/// \brief Slim tables for kinks +/// \file LFSigmaHadTables.h +/// \brief Slim tables for Sigma-hadron pairs /// \author Francesco Mazzaschi /// @@ -22,31 +22,31 @@ #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" -#ifndef PWGLF_DATAMODEL_LFSIGMAPROTONTABLES_H_ -#define PWGLF_DATAMODEL_LFSIGMAPROTONTABLES_H_ +#ifndef PWGLF_DATAMODEL_LFSIGMAHADTABLES_H_ +#define PWGLF_DATAMODEL_LFSIGMAHADTABLES_H_ namespace o2::aod { namespace sigmaproton { -DECLARE_SOA_COLUMN(ChargeSigma, chargeSigma, int); //! Charge of the sigma candidate -DECLARE_SOA_COLUMN(SigmaDecRad, sigmaDecRad, float); //! Decay radius of the Sigma candidate -DECLARE_SOA_COLUMN(SigmaCosPA, sigmaCosPA, float); //! Cosine of pointing angle of the Sigma candidate -DECLARE_SOA_COLUMN(ChargePr, chargePr, int); //! Charge of the proton candidate -DECLARE_SOA_COLUMN(PxPr, pxPr, float); //! Px of the proton candidate -DECLARE_SOA_COLUMN(PyPr, pyPr, float); //! Py of the proton candidate -DECLARE_SOA_COLUMN(PzPr, pzPr, float); //! Pz of the proton candidate -DECLARE_SOA_COLUMN(NSigmaTPCPr, nSigmaTPCPr, float); //! Number of sigmas for the proton candidate from Sigma kink in TPC -DECLARE_SOA_COLUMN(NSigmaTOFPr, nSigmaTOFPr, float); //! Number of sigmas for the proton candidate from Sigma kink in TOF +DECLARE_SOA_COLUMN(ChargeSigma, chargeSigma, int); //! Charge of the sigma candidate +DECLARE_SOA_COLUMN(SigmaDecRad, sigmaDecRad, float); //! Decay radius of the Sigma candidate +DECLARE_SOA_COLUMN(SigmaCosPA, sigmaCosPA, float); //! Cosine of pointing angle of the Sigma candidate +DECLARE_SOA_COLUMN(ChargeHad, chargeHad, int); //! Charge of the hadron candidate +DECLARE_SOA_COLUMN(PxHad, pxHad, float); //! Px of the hadron candidate +DECLARE_SOA_COLUMN(PyHad, pyHad, float); //! Py of the hadron candidate +DECLARE_SOA_COLUMN(PzHad, pzHad, float); //! Pz of the hadron candidate +DECLARE_SOA_COLUMN(NSigmaTPCHad, nSigmaTPCHad, float); //! Number of sigmas for the hadron candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTOFHad, nSigmaTOFHad, float); //! Number of sigmas for the hadron candidate from Sigma kink in TOF // MC Columns DECLARE_SOA_COLUMN(SigmaPDG, sigmaPDG, int); //! PDG code of the Sigma daughter DECLARE_SOA_COLUMN(DaughterPDG, daughterPDG, int); //! PDG code of the kink daughter -DECLARE_SOA_COLUMN(PrPDG, prPDG, int); //! PDG code of the proton candidate +DECLARE_SOA_COLUMN(HadPDG, hadPDG, int); //! PDG code of the hadron candidate DECLARE_SOA_COLUMN(SigmaGenPt, sigmaGenPt, float); //! Generated pT of the Sigma candidate -DECLARE_SOA_COLUMN(PrGenPt, prGenPt, float); //! Generated pT of the proton candidate -DECLARE_SOA_COLUMN(GenKStar, genKStar, float); //! Generated k* of the Sigma-Proton pair +DECLARE_SOA_COLUMN(HadGenPt, hadGenPt, float); //! Generated pT of the hadron candidate +DECLARE_SOA_COLUMN(GenKStar, genKStar, float); //! Generated k* of the Sigma-hadron pair } // namespace sigmaproton @@ -54,18 +54,18 @@ DECLARE_SOA_TABLE(SigmaProtonCands, "AOD", "SIGMAPROTONCANDS", o2::soa::Index<>, sigmaproton::ChargeSigma, kinkcand::PxMoth, kinkcand::PyMoth, kinkcand::PzMoth, kinkcand::PxDaug, kinkcand::PyDaug, kinkcand::PzDaug, sigmaproton::SigmaDecRad, sigmaproton::SigmaCosPA, - sigmaproton::ChargePr, sigmaproton::PxPr, sigmaproton::PyPr, sigmaproton::PzPr, - sigmaproton::NSigmaTPCPr, sigmaproton::NSigmaTOFPr); + sigmaproton::ChargeHad, sigmaproton::PxHad, sigmaproton::PyHad, sigmaproton::PzHad, + sigmaproton::NSigmaTPCHad, sigmaproton::NSigmaTOFHad); DECLARE_SOA_TABLE(SigmaProtonMCCands, "AOD", "SIGMAPROTONMCCANDS", o2::soa::Index<>, sigmaproton::ChargeSigma, kinkcand::PxMoth, kinkcand::PyMoth, kinkcand::PzMoth, kinkcand::PxDaug, kinkcand::PyDaug, kinkcand::PzDaug, sigmaproton::SigmaDecRad, sigmaproton::SigmaCosPA, - sigmaproton::ChargePr, sigmaproton::PxPr, sigmaproton::PyPr, sigmaproton::PzPr, - sigmaproton::NSigmaTPCPr, sigmaproton::NSigmaTOFPr, - sigmaproton::SigmaPDG, sigmaproton::DaughterPDG, sigmaproton::PrPDG, - sigmaproton::SigmaGenPt, sigmaproton::PrGenPt, sigmaproton::GenKStar); + sigmaproton::ChargeHad, sigmaproton::PxHad, sigmaproton::PyHad, sigmaproton::PzHad, + sigmaproton::NSigmaTPCHad, sigmaproton::NSigmaTOFHad, + sigmaproton::SigmaPDG, sigmaproton::DaughterPDG, sigmaproton::HadPDG, + sigmaproton::SigmaGenPt, sigmaproton::HadGenPt, sigmaproton::GenKStar); } // namespace o2::aod -#endif // PWGLF_DATAMODEL_LFSIGMAPROTONTABLES_H_ +#endif // PWGLF_DATAMODEL_LFSIGMAHADTABLES_H_ diff --git a/PWGLF/DataModel/LFSlimNucleiTables.h b/PWGLF/DataModel/LFSlimNucleiTables.h index b35355873f7..84a2da9966f 100644 --- a/PWGLF/DataModel/LFSlimNucleiTables.h +++ b/PWGLF/DataModel/LFSlimNucleiTables.h @@ -55,6 +55,7 @@ DECLARE_SOA_COLUMN(MotherPDGcode, MotherpdgCode, int); DECLARE_SOA_COLUMN(MotherDecRad, motherDecRad, float); DECLARE_SOA_COLUMN(AbsoDecL, absoDecL, float); DECLARE_SOA_COLUMN(McProcess, mcProcess, uint64_t); +DECLARE_SOA_COLUMN(gEventMask, genEventMask, uint8_t); DECLARE_SOA_COLUMN(NsigmaTpc, nsigmaTpc, uint8_t); DECLARE_SOA_COLUMN(NsigmaTof, nsigmaTof, uint8_t); @@ -206,6 +207,40 @@ DECLARE_SOA_TABLE(NucleiTableRed, "AOD", "NUCLEITABLERED", NucleiTableNS::PDGcode, NucleiTableNS::MotherPDGcode); +// Table for keeping track of selection of generated events +DECLARE_SOA_TABLE(GenEventMCSel, "AOD", "GENEVENTMCSEL", + NucleiTableNS::gEventMask); + +DECLARE_SOA_TABLE(NucleiTableMCExtension, "AOD", "NUCTABLEMCSEL", + NucleiTableNS::Pt, + NucleiTableNS::Eta, + NucleiTableNS::Phi, + NucleiTableNS::TPCInnerParam, + NucleiTableNS::Beta, + NucleiTableNS::Zvertex, + NucleiTableNS::NContrib, + NucleiTableNS::DCAxy, + NucleiTableNS::DCAz, + NucleiTableNS::TPCsignal, + NucleiTableNS::ITSchi2, + NucleiTableNS::TPCchi2, + NucleiTableNS::TOFchi2, + NucleiTableNS::Flags, + NucleiTableNS::TPCfindableCls, + NucleiTableNS::TPCcrossedRows, + NucleiTableNS::ITSclsMap, + NucleiTableNS::TPCnCls, + NucleiTableNS::TPCnClsShared, + NucleiTableNS::ITSclusterSizes, + NucleiTableNS::SurvivedEventSelection, + NucleiTableNS::gPt, + NucleiTableNS::gEta, + NucleiTableNS::gPhi, + NucleiTableNS::PDGcode, + NucleiTableNS::MotherPDGcode, + NucleiTableNS::MotherDecRad, + NucleiTableNS::AbsoDecL, + NucleiTableNS::gEventMask); // Extended table with central PID information DECLARE_SOA_TABLE(NucleiTableExt, "AOD", "NUCLEITABLEEXT", NucleiTableNS::NsigmaTpc, diff --git a/PWGLF/DataModel/ZDCCalTables.h b/PWGLF/DataModel/ZDCCalTables.h index 0e3a61d1e4d..fee4e89e309 100644 --- a/PWGLF/DataModel/ZDCCalTables.h +++ b/PWGLF/DataModel/ZDCCalTables.h @@ -34,16 +34,10 @@ DECLARE_SOA_COLUMN(Cent, cent, float); DECLARE_SOA_COLUMN(Vx, vx, float); DECLARE_SOA_COLUMN(Vy, vy, float); DECLARE_SOA_COLUMN(Vz, vz, float); -DECLARE_SOA_COLUMN(ZnaC, znaC, float); -DECLARE_SOA_COLUMN(ZncC, zncC, float); -DECLARE_SOA_COLUMN(ZnaE0, znaE0, float); -DECLARE_SOA_COLUMN(ZnaE1, znaE1, float); -DECLARE_SOA_COLUMN(ZnaE2, znaE2, float); -DECLARE_SOA_COLUMN(ZnaE3, znaE3, float); -DECLARE_SOA_COLUMN(ZncE0, zncE0, float); -DECLARE_SOA_COLUMN(ZncE1, zncE1, float); -DECLARE_SOA_COLUMN(ZncE2, zncE2, float); -DECLARE_SOA_COLUMN(ZncE3, zncE3, float); +DECLARE_SOA_COLUMN(QxA, qxA, float); +DECLARE_SOA_COLUMN(QxC, qxC, float); +DECLARE_SOA_COLUMN(QyA, qyA, float); +DECLARE_SOA_COLUMN(QyC, qyC, float); } // namespace zdccaltable DECLARE_SOA_TABLE(ZDCCalTables, "AOD", "ZDCCALTABLE", zdccaltable::TriggerEventZDC, @@ -52,16 +46,10 @@ DECLARE_SOA_TABLE(ZDCCalTables, "AOD", "ZDCCALTABLE", zdccaltable::Vx, zdccaltable::Vy, zdccaltable::Vz, - zdccaltable::ZnaC, - zdccaltable::ZncC, - zdccaltable::ZnaE0, - zdccaltable::ZnaE1, - zdccaltable::ZnaE2, - zdccaltable::ZnaE3, - zdccaltable::ZncE0, - zdccaltable::ZncE1, - zdccaltable::ZncE2, - zdccaltable::ZncE3); + zdccaltable::QxA, + zdccaltable::QxC, + zdccaltable::QyA, + zdccaltable::QyC); using ZDCCalTable = ZDCCalTables::iterator; } // namespace o2::aod #endif // PWGLF_DATAMODEL_ZDCCALTABLES_H_ diff --git a/PWGLF/DataModel/lambdaJetPolarizationIons.h b/PWGLF/DataModel/lambdaJetPolarizationIons.h new file mode 100644 index 00000000000..faa06e78b22 --- /dev/null +++ b/PWGLF/DataModel/lambdaJetPolarizationIons.h @@ -0,0 +1,151 @@ +// 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 lambdaJetPolarizationIons.h +/// \brief Derived Data table for Jet-induced polarization analysis (HI) +/// \author Cicero Domenico Muncinelli (cicero.domenico.muncinelli@cern.ch) +// Comments, questions, complaints, suggestions? +// Please write to: +// cicero.domenico.muncinelli@cern.ch +// + +#ifndef PWGLF_DATAMODEL_LAMBDAJETPOLARIZATIONIONS_H_ +#define PWGLF_DATAMODEL_LAMBDAJETPOLARIZATIONIONS_H_ + +#include + +#include + +namespace o2::aod +{ + +namespace lambdajetpol +{ +// Collision information: +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); +DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); + +// Jet (and jet proxies) information: +DECLARE_SOA_COLUMN(JetPt, jetPt, float); +DECLARE_SOA_COLUMN(JetEta, jetEta, float); +DECLARE_SOA_COLUMN(JetPhi, jetPhi, float); +DECLARE_SOA_COLUMN(JetNConstituents, jetNConstituents, int); + +DECLARE_SOA_COLUMN(LeadParticlePt, leadParticlePt, float); +DECLARE_SOA_COLUMN(LeadParticleEta, leadParticleEta, float); +DECLARE_SOA_COLUMN(LeadParticlePhi, leadParticlePhi, float); + +// V0 information: +DECLARE_SOA_COLUMN(V0Pt, v0Pt, float); +DECLARE_SOA_COLUMN(V0Eta, v0Eta, float); +DECLARE_SOA_COLUMN(V0Phi, v0Phi, float); + +DECLARE_SOA_COLUMN(IsLambda, isLambda, bool); +DECLARE_SOA_COLUMN(IsAntiLambda, isAntiLambda, bool); +DECLARE_SOA_COLUMN(MassLambda, massLambda, float); +DECLARE_SOA_COLUMN(MassAntiLambda, massAntiLambda, float); + +DECLARE_SOA_COLUMN(PosPt, posPt, float); +DECLARE_SOA_COLUMN(PosEta, posEta, float); +DECLARE_SOA_COLUMN(PosPhi, posPhi, float); +DECLARE_SOA_COLUMN(NegPt, negPt, float); +DECLARE_SOA_COLUMN(NegEta, negEta, float); +DECLARE_SOA_COLUMN(NegPhi, negPhi, float); + +DECLARE_SOA_COLUMN(PosTPCNSigmaPr, posTPCNSigmaPr, float); +DECLARE_SOA_COLUMN(PosTPCNSigmaPi, posTPCNSigmaPi, float); +DECLARE_SOA_COLUMN(NegTPCNSigmaPr, negTPCNSigmaPr, float); +DECLARE_SOA_COLUMN(NegTPCNSigmaPi, negTPCNSigmaPi, float); + +DECLARE_SOA_COLUMN(V0CosPA, v0CosPA, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(DcaV0Daughters, dcaV0Daughters, float); +DECLARE_SOA_COLUMN(DcaPosToPV, dcaPosToPV, float); +DECLARE_SOA_COLUMN(DcaNegToPV, dcaNegToPV, float); + +// Dynamic columns for jets (Px,Py,Pz): +DECLARE_SOA_DYNAMIC_COLUMN(JetPx, jetPx, //! Jet px + [](float jetPt, float jetPhi) -> float { return jetPt * std::cos(jetPhi); }); +DECLARE_SOA_DYNAMIC_COLUMN(JetPy, jetPy, //! Jet py + [](float jetPt, float jetPhi) -> float { return jetPt * std::sin(jetPhi); }); +DECLARE_SOA_DYNAMIC_COLUMN(JetPz, jetPz, //! Jet pz + [](float jetPt, float jetEta) -> float { return jetPt * std::sinh(jetEta); }); +// Same for leading particles: +DECLARE_SOA_DYNAMIC_COLUMN(LeadParticlePx, leadParticlePx, //! Leading particle px + [](float leadParticlePt, float leadParticlePhi) -> float { return leadParticlePt * std::cos(leadParticlePhi); }); +DECLARE_SOA_DYNAMIC_COLUMN(LeadParticlePy, leadParticlePy, //! Leading particle py + [](float leadParticlePt, float leadParticlePhi) -> float { return leadParticlePt * std::sin(leadParticlePhi); }); +DECLARE_SOA_DYNAMIC_COLUMN(LeadParticlePz, leadParticlePz, //! Leading particle pz + [](float leadParticlePt, float leadParticleEta) -> float { return leadParticlePt * std::sinh(leadParticleEta); }); +} // namespace lambdajetpol + +DECLARE_SOA_TABLE(RingCollisions, "AOD", "RINGCOLLISION", + o2::soa::Index<>, // self-index: auto-assigned row number + lambdajetpol::CentFT0M, + lambdajetpol::CentFT0C, + lambdajetpol::CentFV0A); + +namespace lambdajetpol +{ +DECLARE_SOA_INDEX_COLUMN(RingCollision, ringCollision); // Declare index after table is available +} // namespace lambdajetpol + +DECLARE_SOA_TABLE(RingJets, "AOD", "RINGJET", + lambdajetpol::RingCollisionId, // relational index -> RingCollisions + lambdajetpol::JetPt, + lambdajetpol::JetEta, + lambdajetpol::JetPhi, + lambdajetpol::JetNConstituents, + // Dynamic columns (explicitly bound to their static inputs): + lambdajetpol::JetPx, + lambdajetpol::JetPy, + lambdajetpol::JetPz); + +DECLARE_SOA_TABLE(RingLeadPs, "AOD", "RINGLEADP", + lambdajetpol::RingCollisionId, + lambdajetpol::LeadParticlePt, + lambdajetpol::LeadParticleEta, + lambdajetpol::LeadParticlePhi, + // Dynamic columns: + lambdajetpol::LeadParticlePx, + lambdajetpol::LeadParticlePy, + lambdajetpol::LeadParticlePz); + +DECLARE_SOA_TABLE(RingLaV0s, "AOD", "RINGLAV0", + lambdajetpol::RingCollisionId, + lambdajetpol::V0Pt, + lambdajetpol::V0Eta, + lambdajetpol::V0Phi, + lambdajetpol::IsLambda, + lambdajetpol::IsAntiLambda, + lambdajetpol::MassLambda, + lambdajetpol::MassAntiLambda, + lambdajetpol::PosPt, + lambdajetpol::PosEta, + lambdajetpol::PosPhi, + lambdajetpol::NegPt, + lambdajetpol::NegEta, + lambdajetpol::NegPhi, + lambdajetpol::PosTPCNSigmaPr, + lambdajetpol::PosTPCNSigmaPi, + lambdajetpol::NegTPCNSigmaPr, + lambdajetpol::NegTPCNSigmaPi, + lambdajetpol::V0CosPA, + lambdajetpol::V0Radius, + lambdajetpol::DcaV0Daughters, + lambdajetpol::DcaPosToPV, + lambdajetpol::DcaNegToPV); + +using RingCollision = RingCollisions::iterator; // Useful shorthand +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LAMBDAJETPOLARIZATIONIONS_H_ diff --git a/PWGLF/TableProducer/Common/zdcvector.cxx b/PWGLF/TableProducer/Common/zdcvector.cxx index 995b0cc8448..19fc5e65393 100644 --- a/PWGLF/TableProducer/Common/zdcvector.cxx +++ b/PWGLF/TableProducer/Common/zdcvector.cxx @@ -176,7 +176,7 @@ struct zdcvector { if (!bc.has_zdc()) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); return; } @@ -190,7 +190,8 @@ struct zdcvector { if (znaEnergycommon <= 0.0 || zncEnergycommon <= 0.0) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); + // zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); return; } @@ -198,14 +199,16 @@ struct zdcvector { if (znaEnergy[0] <= 0.0 || znaEnergy[1] <= 0.0 || znaEnergy[2] <= 0.0 || znaEnergy[3] <= 0.0) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); + // zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); return; } histos.fill(HIST("hEvtSelInfo"), 3.5); if (zncEnergy[0] <= 0.0 || zncEnergy[1] <= 0.0 || zncEnergy[2] <= 0.0 || zncEnergy[3] <= 0.0) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); + // zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); return; } @@ -213,7 +216,8 @@ struct zdcvector { if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); + // zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); return; } @@ -221,7 +225,8 @@ struct zdcvector { if (additionalEvSel && (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); + // zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); return; } @@ -255,7 +260,7 @@ struct zdcvector { if (znaEnergy[iChA] <= 0.0) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); return; } else { double ampl = gainequal * znaEnergy[iChA]; @@ -270,7 +275,8 @@ struct zdcvector { } else { if (zncEnergy[iChA - 4] <= 0.0) { triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); + // zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); return; } else { double ampl = gainequal * zncEnergy[iChA - 4]; @@ -300,7 +306,8 @@ struct zdcvector { qyZDCA = 0.0; qyZDCC = 0.0; triggerevent = false; - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0); + // zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); return; } @@ -322,7 +329,7 @@ struct zdcvector { lastRunNumber = currentRunNumber; } - zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3]); + zdccaltable(triggerevent, currentRunNumber, centrality, vx, vy, vz, qxZDCA, qxZDCC, qyZDCA, qyZDCC); } }; diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index cae41a2bd67..8e1e0431010 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -123,6 +123,9 @@ struct decay3bodyBuilder { Configurable doVertexQA{"doVertexQA", false, "Flag to fill QA histograms for PV of (selected) events."}; Configurable disableITSROFCut{"disableITSROFCut", false, "Disable ITS ROF border cut"}; + // MC processing options + Configurable doStoreMcBkg{"doStoreMcBkg", false, "Flag to store candidates which were not matched to true H3L/Anti-H3L decaying via three-body decay in MC (i.e. MC background) in the output table"}; + // 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"}; @@ -794,47 +797,56 @@ struct decay3bodyBuilder { // check if daughters have MC particle if (!trackProton.has_mcParticle() || !trackPion.has_mcParticle() || !trackDeuteron.has_mcParticle()) { - continue; - } + if (!doStoreMcBkg) { + continue; // if not storing MC background, skip candidates where at least one daughter is not matched to MC particle + } else { + this3BodyMCInfo.label = -5; // at least one non-matched daughter + // fill analysis table (only McVtx3BodyDatas is filled here) + fillAnalysisTables(); + } + } else { // all daughters are matched to MC particles, get their MC info + // 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 mothers) + 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(); + + // daughters are matched to MC, now we check if reco mother is true H3L/Anti-H3l and decayed via three-body decay + this3BodyMCInfo.label = checkH3LTruth(mcTrackProton, mcTrackPion, mcTrackDeuteron); // returns global index of mother if true H3L/Anti-H3L mother decaying via three-body decay, otherwise negative value + + // if not storing MC background, skip candidates where mother is not true H3L/Anti-H3L decaying via three-body decay + if (!doStoreMcBkg && this3BodyMCInfo.label <= 0) { + continue; + } - // 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); - this3BodyMCInfo.motherPdgCode = mcTrackH3L.pdgCode(); - 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 = this3BodyMCInfo.motherPdgCode > 0 ? true : false; - this3BodyMCInfo.isTrueAntiH3L = this3BodyMCInfo.motherPdgCode < 0 ? true : false; - } + // get generated mother MC info for matched candidates + if (this3BodyMCInfo.label > -1) { + auto mcTrackH3L = mcParticles.rawIteratorAt(this3BodyMCInfo.label); + this3BodyMCInfo.motherPdgCode = mcTrackH3L.pdgCode(); + 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 = this3BodyMCInfo.motherPdgCode > 0 ? true : false; + this3BodyMCInfo.isTrueAntiH3L = this3BodyMCInfo.motherPdgCode < 0 ? true : false; + } - // fill analysis tables (only McVtx3BodyDatas is filled here) - fillAnalysisTables(); + // fill analysis tables (only McVtx3BodyDatas is filled here) + fillAnalysisTables(); + } // end of check if daughters have MC particle // mark mcParticle as reconstructed if (this3BodyMCInfo.label > -1) { @@ -1179,30 +1191,23 @@ struct decay3bodyBuilder { // ______________________________________________________________ // 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) + int checkH3LTruth(MCTrack3B const& mcParticlePr, MCTrack3B const& mcParticlePi, MCTrack3B const& mcParticleDe) { - if (std::abs(mcParticlePr.pdgCode()) != PDG_t::kProton || std::abs(mcParticleDe.pdgCode()) != o2::constants::physics::Pdg::kDeuteron) { - 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()) == o2::constants::physics::Pdg::kHyperTriton) { - prDeMomID = motherPr.globalIndex(); - break; - } - } - } - if (prDeMomID == -1) { - return -1; - } - if (std::abs(mcParticlePi.pdgCode()) != PDG_t::kPiPlus && std::abs(mcParticlePi.pdgCode()) != PDG_t::kMuonMinus) { - return -1; + // return legend + // -4: proton, pion, or deuteron have wrong identity + // -3: proton and pion have a common mother which is a Lambda (i.e., not a direct daughter of hypertriton) + // -2: proton, pion, and deuteron don't have a common mother + // -1: proton, pion, and deuteron have common mother but it's NOT a hypertriton + // global mother ID: proton, pion, and deuteron have common mother and it's a hypertriton + + // first, check identity of MC daughters + if (std::abs(mcParticlePr.pdgCode()) != PDG_t::kProton || std::abs(mcParticleDe.pdgCode()) != o2::constants::physics::Pdg::kDeuteron || (std::abs(mcParticlePi.pdgCode()) != PDG_t::kPiPlus && std::abs(mcParticlePi.pdgCode()) != PDG_t::kMuonMinus)) { + return -4; } // 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()) == PDG_t::kMuonMinus) { + bool isMuonReco = false; for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { if (std::abs(motherPi.pdgCode()) == PDG_t::kPiPlus) { mcParticlePiTmp = motherPi; @@ -1210,14 +1215,45 @@ struct decay3bodyBuilder { break; } } + // If the track is a muon but none of its mothers is a pi+, treat as wrong identity + if (!isMuonReco) { + return -4; + } + } + + // now first check if the proton and pion have the same mother and it is a Lambda + for (const auto& motherPr : mcParticlePr.template mothers_as()) { + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (motherPr.globalIndex() == motherPi.globalIndex() && std::abs(motherPr.pdgCode()) == PDG_t::kLambda0) { + return -3; + } + } } - // now loop over the pion mother - for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { - if (motherPi.globalIndex() == prDeMomID) { - return motherPi.globalIndex(); + + // now check if all three daughters have the same mother + int momID = -1; + int momPdgCode = 0; + for (const auto& motherPr : mcParticlePr.template mothers_as()) { + for (const auto& motherDe : mcParticleDe.template mothers_as()) { + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (motherPr.globalIndex() == motherDe.globalIndex() && motherPr.globalIndex() == motherPi.globalIndex()) { + momID = motherPr.globalIndex(); + momPdgCode = motherPr.pdgCode(); + break; + } + } } } - return -1; + if (momID == -1) { + return -2; + } + + // check if the common mother is a hypertriton + if (std::abs(momPdgCode) == o2::constants::physics::Pdg::kHyperTriton) { + return momID; + } else { + return -1; // common mother found but not a hypertriton + } } // ______________________________________________________________ diff --git a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx index 029b8e95b89..41e5a177282 100644 --- a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx +++ b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx @@ -514,9 +514,9 @@ struct he3HadronFemto { float correctPtHe3TrackedAsTriton(const float pt, const uint32_t pidForTracking) { if (pt < 2.5 && pidForTracking == o2::track::PID::Triton) - return pt * 2. * (1. - kHePidTrkParams[0] - kHePidTrkParams[1] * pt * 2.); + return pt * (1. - kHePidTrkParams[0] - kHePidTrkParams[1] * pt); - return pt * 2.; + return pt; } float computeNsigmaDCA(const float pt, const float dca, const int iSpecies, const char* dcaType = "xy") diff --git a/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx index 2018c6a53d4..fc5f9882729 100644 --- a/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx @@ -16,6 +16,10 @@ #include "MetadataHelper.h" #include "PWGLF/DataModel/LFHypernucleiKfTables.h" +#include "PWGLF/DataModel/LFNucleiTables.h" +#include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/Utils/pidTOFGeneric.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" @@ -65,7 +69,7 @@ using namespace o2::framework::expressions; using CollisionsFull = soa::Join; using CollisionsFullMC = soa::Join; -using TracksFull = soa::Join; +using TracksFull = soa::Join; o2::common::core::MetadataHelper metadataInfo; // Metadata helper //---------------------------------------------------------------------------------------------------------------- @@ -146,17 +150,17 @@ enum HYPNUCDEFS { kEnabled, kDsigns, kUseV0for }; static const std::vector hypNucDefsLb{"Enabled", "PDGCode", "d1", "d2", "d3", "d4", "daughterSigns", "useV0for"}; -static const std::string hypNucDefs[nHyperNuclei][nHypNucDefs]{ - {"0", "3122", "proton", "pion", "none", "none", "+-", ""}, - {"0", "1010010030", "helion", "pion", "none", "none", "+-", ""}, - {"0", "1010010030", "deuteron", "proton", "pion", "none", "++-", ""}, - {"0", "1010010040", "alpha", "pion", "none", "none", "+-", ""}, - {"0", "1010010040", "triton", "proton", "pion", "none", "++-", ""}, - {"0", "1010020040", "helion", "proton", "pion", "none", "++-", ""}, - {"0", "1010020050", "alpha", "proton", "pion", "none", "++-", ""}, - {"0", "1010020050", "helion", "deuteron", "pion", "none", "++-", ""}, - {"0", "0", "none", "none", "none", "none", "", ""}, - {"0", "0", "none", "none", "none", "none", "", ""}}; // NOLINT: runtime/string +const std::string hypNucDefs[nHyperNuclei][nHypNucDefs]{// NOLINT: runtime/string + {"0", "3122", "proton", "pion", "none", "none", "+-", ""}, + {"0", "1010010030", "helion", "pion", "none", "none", "+-", ""}, + {"0", "1010010030", "deuteron", "proton", "pion", "none", "++-", ""}, + {"0", "1010010040", "alpha", "pion", "none", "none", "+-", ""}, + {"0", "1010010040", "triton", "proton", "pion", "none", "++-", ""}, + {"0", "1010020040", "helion", "proton", "pion", "none", "++-", ""}, + {"0", "1010020050", "alpha", "proton", "pion", "none", "++-", ""}, + {"0", "1010020050", "helion", "deuteron", "pion", "none", "++-", ""}, + {"0", "0", "none", "none", "none", "none", "", ""}, + {"0", "0", "none", "none", "none", "none", "", ""}}; const int nSelPrim = 8; enum PRESELECTIONSPRIMARIES { kMinMass, @@ -263,7 +267,6 @@ struct DaughterKf { dcaToPv = daughterKfp.GetDistanceFromVertex(&vtx[0]); dcaToPvZ = std::sqrt(dcaToPv * dcaToPv - dcaToPvXY * dcaToPvXY); } - bool isTrack() { return daughterTrackId >= 0; } }; int DaughterKf::uniqueId = 0; @@ -429,6 +432,30 @@ struct IndexPairs { } }; // struct IndexPairs +struct IndexPairsVec { + std::vector>> pairs; + IndexPairsVec() + { + pairs.resize(nDaughterParticles); + } + void add(int i, int64_t a, int b) { pairs.at(i).push_back({a, b}); } + void clear() + { + for (size_t i = 0; i < nDaughterParticles; i++) + pairs.at(i).clear(); + } + bool getIndex(int i, int64_t a, int& b) + { + for (const auto& pair : pairs.at(i)) { + if (pair.first == a) { + b = pair.second; + return true; + } + } + return false; + } +}; // struct IndexPairsVec + struct McCollInfo { bool hasRecoColl; bool passedEvSel; @@ -526,7 +553,8 @@ struct HypKfRecoTask { std::vector singleHyperNuclei, cascadeHyperNuclei; std::vector primVtx, cents; std::vector mcCollInfos; - IndexPairs trackIndices, mcPartIndices; + IndexPairsVec trackIndices; + IndexPairs mcPartIndices; KFPVertex kfPrimVtx; bool collHasCandidate, collHasMcTrueCandidate, collPassedEvSel, activeCascade, isMC; int64_t mcCollTableIndex; @@ -610,8 +638,12 @@ struct HypKfRecoTask { const float itsNsigma = getITSnSigma(track, daughterParticles.at(i)); if (daughterParticles.at(i).trkSettings[kMaxITSnSigma] >= 0 && std::abs(itsNsigma) > daughterParticles.at(i).trkSettings[kMaxITSnSigma]) continue; + float tpcNsigmaNlp = NoVal; + if (daughterParticles.at(i).name == "alpha") { + tpcNsigmaNlp = getTPCnSigma(track, daughterParticles.at(i - 1)); + } filldedx(track, i); - foundDaughterKfs.at(i).push_back(DaughterKf(i, track.globalIndex(), track.sign(), primVtx, 0, 0, 0)); + foundDaughterKfs.at(i).push_back(DaughterKf(i, track.globalIndex(), track.sign(), primVtx, tpcNsigma, tpcNsigmaNlp, itsNsigma)); } } // track loop } @@ -865,14 +897,14 @@ struct HypKfRecoTask { continue; const auto& daughterTrackId = daughter->daughterTrackId; int trackTableId; - if (!trackIndices.getIndex(daughterTrackId, trackTableId)) { + if (!trackIndices.getIndex(daughter->species, daughterTrackId, trackTableId)) { const auto& track = tracks.rawIteratorAt(daughterTrackId); outputTrackTable( daughter->species * track.sign(), track.pt(), track.eta(), track.phi(), daughter->dcaToPvXY, daughter->dcaToPvZ, track.tpcNClsFound(), track.tpcChi2NCl(), track.itsClusterSizes(), track.itsChi2NCl(), getRigidity(track), track.tpcSignal(), daughter->tpcNsigma, daughter->tpcNsigmaNHP, daughter->tpcNsigmaNLP, - track.mass(), track.isPVContributor()); + getMass2(track), track.isPVContributor()); trackTableId = outputTrackTable.lastIndex(); - trackIndices.add(daughterTrackId, trackTableId); + trackIndices.add(daughter->species, daughterTrackId, trackTableId); } vecDaugtherTracks.push_back(trackTableId); } @@ -1162,7 +1194,7 @@ struct HypKfRecoTask { return false; if (getMeanItsClsSize(track) > particle.trkSettings[kMaxITSmeanClsSize]) return false; - if (particle.trkSettings[kTOFrequiredabove] >= 0 && getRigidity(track) > particle.trkSettings[kTOFrequiredabove] && (track.mass() < particle.trkSettings[kMinTOFmass] || track.mass() > particle.trkSettings[kMaxTOFmass])) + if (particle.trkSettings[kTOFrequiredabove] >= 0 && getRigidity(track) > particle.trkSettings[kTOFrequiredabove] && (getMass2(track) < particle.trkSettings[kMinTOFmass] || getMass2(track) > particle.trkSettings[kMaxTOFmass])) return false; return true; } @@ -1331,6 +1363,23 @@ struct HypKfRecoTask { return -1; } //---------------------------------------------------------------------------------------------------------------- + template + float getMass2(const T& track) + { + const float p = track.p(); + const float& tofStartTime = track.evTimeForTrack(); + const float& tofTime = track.tofSignal(); + constexpr float CInCmPs = 2.99792458e-2f; + const float& length = track.length(); + const float time = tofTime - tofStartTime; + if (time > 0.f && length > 0.f) { + const float beta = length / (CInCmPs * time); + const float gamma = 1.f / std::sqrt(1.f - beta * beta); + const float mass = p / std::sqrt(gamma * gamma - 1.f); + return mass * mass; + } + return -1.f; + } //---------------------------------------------------------------------------------------------------------------- }; //---------------------------------------------------------------------------------------------------------------- diff --git a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx index 096b427617e..2d922f613a5 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -40,6 +40,8 @@ #include "MathUtils/BetheBlochAleph.h" #include "ReconstructionDataFormats/Track.h" +#include "Math/Vector4D.h" + #include #include #include @@ -49,6 +51,8 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using std::array; + using CollBracket = o2::math_utils::Bracket; using TracksFull = soa::Join; using CollisionsFull = soa::Join; @@ -56,6 +60,9 @@ using CollisionsFullMC = soa::Join; +using McCollisionMults = soa::Join; +using EventCandidatesMC = soa::Join; + namespace { constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; @@ -77,6 +84,20 @@ std::shared_ptr hH4LMassTracked; std::shared_ptr hDecayChannel; std::shared_ptr hIsMatterGen; std::shared_ptr hIsMatterGenTwoBody; +std::shared_ptr hEvtMC; +std::shared_ptr hImpactParamGen; +std::shared_ptr hImpactParamReco; +std::shared_ptr hGen3HLBeforeEvtSel; +std::shared_ptr hGen3HLAfterSel; +std::shared_ptr hRecoCentralityColvsMultiplicityRecoEta05; +std::shared_ptr hRecoCentralityColvsImpactParamReco; +std::shared_ptr hGen3HLvsImpactParameterBeforeEvtSel; +std::shared_ptr hGen3HLvsImpactParameterAfterSel; +std::shared_ptr hGen3HLvsMultiplicityGenEta05BeforeEvtSel; +std::shared_ptr hGen3HLvsMultiplicityGenEta05AfterSel; +std::shared_ptr hGen3HLvsMultiplicityFT0CBeforeEvtSel; +std::shared_ptr hGen3HLvsMultiplicityFT0CAfterSel; + } // namespace struct hyperCandidate { @@ -117,6 +138,8 @@ struct hyperCandidate { uint8_t nTPCClustersPi = 0u; uint8_t nTPCpidClusHe3 = 0u; uint8_t nTPCpidClusPi = 0u; + uint8_t nTPCCrossedRowsHe3 = 0u; + uint8_t nTPCCrossedRowsPi = 0u; uint32_t clusterSizeITSHe3 = 0u; uint32_t clusterSizeITSPi = 0u; @@ -147,6 +170,7 @@ struct hyperRecoTask { // PDG codes Configurable hyperPdg{"hyperPDG", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; Configurable heDauPdg{"heDauPDG", 1000020030, "PDG code of the helium (could be 3He or 4He)"}; + Configurable piDauPdg{"piDauPdg", 211, "PDG code of pion"}; // Selection criteria Configurable v0cospacut{"hypcospa", 0.95, "V0 CosPA"}; @@ -160,6 +184,8 @@ struct hyperRecoTask { Configurable nSigmaMaxHe{"nSigmaMaxHe", 5, "helium dEdx cut (n sigma)"}; Configurable nTPCClusMinHe{"nTPCClusMinHe", 70, "helium NTPC clusters cut"}; Configurable nTPCClusMinPi{"nTPCClusMinPi", -1., "pion NTPC clusters cut"}; + Configurable nTPCCrossedRowsMinHe{"nTPCCrossedRowsMinHe", 70, "helium minimum crossed rows"}; + Configurable nTPCCrossedRowsMinPi{"nTPCCrossedRowsMinPi", -1., "pion minimum crossed rows"}; Configurable mcSignalOnly{"mcSignalOnly", true, "If true, save only signal in MC"}; Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; Configurable isEventUsedForEPCalibration{"isEventUsedForEPCalibration", 1, "Event is used for EP calibration"}; @@ -199,6 +225,13 @@ struct hyperRecoTask { ConfigurableAxis zVtxBins{"zVtxBins", {100, -20.f, 20.f}, "Binning for n sigma"}; ConfigurableAxis centBins{"centBins", {100, 0.f, 100.f}, "Binning for centrality"}; + // histogram axes for EvtLossMC + ConfigurableAxis binsImpactPar{"binsImpactPar", {80, 0, 16}, "Binning of the impact parameter axis"}; + ConfigurableAxis binsCent{"binsCent", {10, 0.0, 100.0}, "Binning of the centrality axis"}; + ConfigurableAxis binsPt{"binsPt", {20, 0, 10}, "Binning of the pt"}; + ConfigurableAxis binsFT0CMult{"binsFT0CMult", {500, 0.0f, +500.0f}, "Binning of the FT0C multiplicity"}; + ConfigurableAxis binsMult{"binsMult", {500, 0.0f, +500.0f}, ""}; + // std vector of candidates std::vector hyperCandidates; // vector to keep track of MC mothers already filled @@ -219,7 +252,6 @@ struct hyperRecoTask { void init(InitContext const&) { - zorroSummary.setObject(zorro.getZorroSummary()); mRunNumber = 0; @@ -250,6 +282,11 @@ struct hyperRecoTask { const AxisSpec nSigma3HeAxis{nSigmaBins, "n_{#sigma}({}^{3}He)"}; const AxisSpec zVtxAxis{zVtxBins, "z_{vtx} (cm)"}; const AxisSpec centAxis{centBins, "Centrality"}; + const AxisSpec impactParamAxis{binsImpactPar, "Impact Parameter (b)"}; + const AxisSpec centFT0CAxis{binsCent, "Centrality (FT0C %)"}; + const AxisSpec binsFT0CMultAxis{binsFT0CMult, "FT0C multiplicity"}; + const AxisSpec ptAxis{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec multAxis = {binsMult, "Multiplicity #eta <0.5"}; hNsigma3HeSel = qaRegistry.add("hNsigma3HeSel", "; p_{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}He)", HistType::kTH2F, {rigidityAxis, nSigma3HeAxis}); hDeDx3HeSel = qaRegistry.add("hDeDx3HeSel", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); @@ -259,11 +296,12 @@ struct hyperRecoTask { hH4LMassBefSel = qaRegistry.add("hH4LMassBefSel", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); hH4LMassTracked = qaRegistry.add("hH4LMassTracked", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); - hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{4, -0.5, 3.5}}); + hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{5, -0.5, 4.5}}); hEvents->GetXaxis()->SetBinLabel(1, "All"); hEvents->GetXaxis()->SetBinLabel(2, "sel8"); - hEvents->GetXaxis()->SetBinLabel(3, "kNoSameBunchPileup"); - hEvents->GetXaxis()->SetBinLabel(4, "kIsGoodZvtxFT0vsPV"); + hEvents->GetXaxis()->SetBinLabel(3, "z_{vtx}"); + hEvents->GetXaxis()->SetBinLabel(4, "kNoSameBunchPileup"); + hEvents->GetXaxis()->SetBinLabel(5, "kIsGoodZvtxFT0vsPV"); hEventsZorro = qaRegistry.add("hEventsZorro", ";Events; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hEventsZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); @@ -284,6 +322,29 @@ struct hyperRecoTask { hCentFT0A = qaRegistry.add("hCentFT0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); hCentFT0C = qaRegistry.add("hCentFT0C", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); hCentFT0M = qaRegistry.add("hCentFT0M", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + + if (doprocessEventLossMC) { + hEvtMC = qaRegistry.add("QAEvent/hEvtMC", ";; ", HistType::kTH1D, {{3, -0.5, 2.5}}); + hEvtMC->GetXaxis()->SetBinLabel(1, "All gen evts"); + hEvtMC->GetXaxis()->SetBinLabel(2, "Gen evts with al least one reconstructed"); + hEvtMC->GetXaxis()->SetBinLabel(3, "Gen evts with no reconstructed collisions"); + // Infomation for all generated collisions collisions + hImpactParamGen = qaRegistry.add("QAEvent/McColAll/hImpactParamGen", "Impact parameter of generated MC events; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + // Infomation for generated collisions collisions with at least one rec. event + hImpactParamReco = qaRegistry.add("QAEvent/McColAll/hImpactParamReco", "Impact parameter of generated MC events with at least one rec. evt; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + hRecoCentralityColvsMultiplicityRecoEta05 = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta05", "Correlation between FT0C centrality and charged particle multiplicity in generated MC events with at least one rec. evt; Multiplicity #eta <0.5; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); + hRecoCentralityColvsImpactParamReco = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsImpactParamReco", "Correlation between FT0C centrality and impact parameter in generated MC events with at least one rec. evt; Impact Parameter (b); Counts", HistType::kTH2D, {centFT0CAxis, impactParamAxis}); + // Information of generated 3HL in generated events + hGen3HLBeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLBeforeEvtSel", "3HL generated #it{p}_{T} distribution in all gen evt;#it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); + hGen3HLvsImpactParameterBeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsImpactParameterBeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and impact parameter in all gen evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); + hGen3HLvsMultiplicityGenEta05BeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05BeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.5", HistType::kTH2D, {ptAxis, multAxis}); + hGen3HLvsMultiplicityFT0CBeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CBeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and FT0C multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); + // Information of generated 3HL in generated events with at least one rec. event + hGen3HLAfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLAfterSel", "3HL generated #it{p}_{T} distribution in gen. evts with at least one rec. evt; #it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); + hGen3HLvsImpactParameterAfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsImpactParameterAfterSel", "Correlation 3HL generated #it{p}_{T} and impact parameter in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); + hGen3HLvsMultiplicityGenEta05AfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05AfterSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.5", HistType::kTH2D, {ptAxis, multAxis}); + hGen3HLvsMultiplicityFT0CAfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CAfterSel", "Correlation 3HL generated #it{p}_{T} and FT0C multiplicity in gen. evts with at least one rec;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); + } } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -366,12 +427,17 @@ struct hyperRecoTask { } } - if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > 10) { + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { continue; } hEvents->Fill(1.); + if (std::abs(collision.posZ()) > 10) { + hEvents->Fill(2.); + continue; + } + if (zorroSelected) { hEventsZorro->Fill(1.); } @@ -380,14 +446,13 @@ struct hyperRecoTask { if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { continue; } - hEvents->Fill(2.); + hEvents->Fill(3.); } - if (cfgEvSelkIsGoodZvtxFT0vsPV) { if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { continue; } - hEvents->Fill(3.); + hEvents->Fill(4.); } goodCollision[collision.globalIndex()] = true; @@ -408,23 +473,27 @@ struct hyperRecoTask { if (collision.has_mcCollision()) { recoCollisionIds[collision.mcCollisionId()] = collision.globalIndex(); } - if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > 10) + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) continue; hEvents->Fill(1.); + if (std::abs(collision.posZ()) > 10) { + hEvents->Fill(2.); + continue; + } + if (cfgEvSelkNoSameBunchPileup) { if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { continue; } - hEvents->Fill(2.); + hEvents->Fill(3.); } - if (cfgEvSelkIsGoodZvtxFT0vsPV) { if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { continue; } - hEvents->Fill(3.); + hEvents->Fill(4.); } if (collision.has_mcCollision()) { @@ -437,7 +506,6 @@ struct hyperRecoTask { hCentFT0M->Fill(collision.centFT0M()); } } - template void fillHyperCand(Ttrack& heTrack, Ttrack& piTrack, CollBracket collBracket, const Tcolls& collisions, hyperCandidate& hypCand) { @@ -445,10 +513,12 @@ struct hyperRecoTask { hypCand.isMatter = heTrack.sign() > 0; hypCand.nSigmaHe3 = computeNSigmaHe3(heTrack); hypCand.nTPCClustersHe3 = heTrack.tpcNClsFound(); + hypCand.nTPCCrossedRowsHe3 = heTrack.tpcNClsCrossedRows(); hypCand.tpcSignalHe3 = heTrack.tpcSignal(); hypCand.nTPCpidClusHe3 = static_cast(heTrack.tpcNClsFindable()) - heTrack.tpcNClsFindableMinusPID(); hypCand.clusterSizeITSHe3 = heTrack.itsClusterSizes(); hypCand.nTPCClustersPi = piTrack.tpcNClsFound(); + hypCand.nTPCCrossedRowsPi = piTrack.tpcNClsCrossedRows(); hypCand.nTPCpidClusPi = static_cast(piTrack.tpcNClsFindable()) - piTrack.tpcNClsFindableMinusPID(); hypCand.tpcSignalPi = piTrack.tpcSignal(); hypCand.tpcChi2He3 = heTrack.tpcChi2NCl(); @@ -609,6 +679,9 @@ struct hyperRecoTask { if (heTrack.tpcNClsFound() < nTPCClusMinHe || piTrack.tpcNClsFound() < nTPCClusMinPi) { continue; } + if (heTrack.tpcNClsCrossedRows() < nTPCCrossedRowsMinHe || piTrack.tpcNClsCrossedRows() < nTPCCrossedRowsMinPi) { + continue; + } hyperCandidate hypCand; hypCand.v0ID = v0.globalIndex(); @@ -643,6 +716,10 @@ struct hyperRecoTask { continue; if (!isHe && track.tpcNClsFound() < nTPCClusMinPi) continue; + if (isHe && track.tpcNClsCrossedRows() < nTPCCrossedRowsMinHe) + continue; + if (!isHe && track.tpcNClsCrossedRows() < nTPCCrossedRowsMinPi) + continue; svCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); } @@ -729,6 +806,7 @@ struct hyperRecoTask { hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.nTPCCrossedRowsHe3, hypCand.nTPCCrossedRowsPi, hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, hypCand.massTOFHe3, hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); @@ -764,6 +842,7 @@ struct hyperRecoTask { hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.nTPCCrossedRowsHe3, hypCand.nTPCCrossedRowsPi, hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, hypCand.massTOFHe3, hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); @@ -792,6 +871,7 @@ struct hyperRecoTask { hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.nTPCCrossedRowsHe3, hypCand.nTPCCrossedRowsPi, hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, hypCand.massTOFHe3, hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); @@ -826,7 +906,7 @@ struct hyperRecoTask { hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, - hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, hypCand.nTPCCrossedRowsHe3, hypCand.nTPCCrossedRowsPi, hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, hypCand.massTOFHe3, hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize, @@ -896,14 +976,14 @@ struct hyperRecoTask { } outputMCTable(centFT0A, centFT0C, centFT0M, - mRunNumber, -1, -1, -1, - 0, -1, -1, -1, + mRunNumber, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, false, chargeFactor * hypCand.genPt(), hypCand.genPhi(), hypCand.genEta(), hypCand.genPtHe3(), hypCand.gDecVtx[0], hypCand.gDecVtx[1], hypCand.gDecVtx[2], @@ -922,6 +1002,111 @@ struct hyperRecoTask { processMC(collisions, mcCollisions, V0s, tracks, ambiTracks, bcs, trackLabelsMC, particlesMC); } PROCESS_SWITCH(hyperRecoTask, processMCTracked, "MC analysis with tracked V0s", false); + + template + bool passEvtSel(const CollType& collision) + { + if (!collision.sel8()) + return false; + + if ((std::abs(collision.posZ())) > 10) + return false; + + if (cfgEvSelkNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + + if (cfgEvSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + + return true; + } + + void processEventLossMC(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, aod::McParticles const& GenParticles) + { + if (std::abs(mcCollision.posZ()) > 10) { + return; + } + + //////////// Event loss estimation via impact parameter and multiplicity by MCFT0C + + // Fill all generated events + hEvtMC->Fill(0); + hImpactParamGen->Fill(mcCollision.impactParameter()); + + // Fill generated events with no reconstructed collisions + if (collisions.size() == 0) { + hEvtMC->Fill(1); + } + + // Define the generated events with at least one reconstructed event + bool atLeastOneRecoEvt = false; + auto centralityFT0C = -999.; + + for (auto const& col : collisions) { + if (!passEvtSel(col)) { + continue; + } + centralityFT0C = col.centFT0C(); + atLeastOneRecoEvt = true; + } + + if (atLeastOneRecoEvt) { + hEvtMC->Fill(2); + hImpactParamReco->Fill(mcCollision.impactParameter()); + hRecoCentralityColvsMultiplicityRecoEta05->Fill(centralityFT0C, mcCollision.multMCNParticlesEta05()); + hRecoCentralityColvsImpactParamReco->Fill(centralityFT0C, mcCollision.impactParameter()); + } + // Construct the H3L 4-vector based on the generated daugthers identification by PDG + ROOT::Math::PxPyPzMVector daugh1, daugh2, mother; + + for (const auto& genParticle : GenParticles) { + if (std::abs(genParticle.y()) > 1) + continue; + if (std::abs(genParticle.pdgCode()) != hyperPdg) + continue; + + auto daughters = genParticle.daughters_as(); + + bool dauHe3 = false, dauPiMinus = false, dauAntiHe3 = false, dauPiPos = true; + + for (const auto& daughter : daughters) { + if (daughter.pdgCode() == heDauPdg) { + dauHe3 = true; + daugh1 = ROOT::Math::PxPyPzMVector(daughter.px(), daughter.py(), daughter.pz(), he3Mass); + } else if (daughter.pdgCode() == -piDauPdg) { + dauPiMinus = true; + daugh2 = ROOT::Math::PxPyPzMVector(daughter.px(), daughter.py(), daughter.pz(), piMass); + } + if (daughter.pdgCode() == -heDauPdg) { + dauAntiHe3 = true; + daugh1 = ROOT::Math::PxPyPzMVector(daughter.px(), daughter.py(), daughter.pz(), he3Mass); + } else if (daughter.pdgCode() == piDauPdg) { + dauPiPos = true; + daugh2 = ROOT::Math::PxPyPzMVector(daughter.px(), daughter.py(), daughter.pz(), piMass); + } + } + // Check pairs to avoid wrong charge associations + if (!((dauHe3 && dauPiMinus) || !(dauAntiHe3 && dauPiPos))) + continue; + + mother = daugh1 + daugh2; + + // Fill informations for generated 3HL in all generated events + hGen3HLBeforeEvtSel->Fill(mother.pt()); + hGen3HLvsImpactParameterBeforeEvtSel->Fill(mother.pt(), mcCollision.impactParameter()); + hGen3HLvsMultiplicityGenEta05BeforeEvtSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta05()); + hGen3HLvsMultiplicityFT0CBeforeEvtSel->Fill(mother.pt(), mcCollision.multMCFT0C()); + + // Fill informations for generated 3HL in generated events with at least one reconstructed event + if (atLeastOneRecoEvt) { + hGen3HLAfterSel->Fill(mother.pt()); + hGen3HLvsImpactParameterAfterSel->Fill(mother.pt(), mcCollision.impactParameter()); + hGen3HLvsMultiplicityGenEta05AfterSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta05()); + hGen3HLvsMultiplicityFT0CAfterSel->Fill(mother.pt(), mcCollision.multMCFT0C()); + } + } + } + PROCESS_SWITCH(hyperRecoTask, processEventLossMC, "Event loss analysis", false); }; WorkflowSpec diff --git a/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx b/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx index 5f7de80eff7..4e8d5fb205e 100644 --- a/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx @@ -87,6 +87,8 @@ std::shared_ptr h2FT0CnClusTPCtoTrBfSel; std::shared_ptr h2FT0CnClusTPCtoPiBfSel; std::shared_ptr h2FT0Cchi2NClTPCtoTrBfSel; std::shared_ptr h2FT0Cchi2NClITStoTrBfSel; +std::shared_ptr h2FT0CnTPCNClsCrossedRows3HBfSel; +std::shared_ptr h2FT0CnTPCNClsCrossedRowsPiBfSel; // QA ITS-TPC and ITS-TPC-TOF track signals std::shared_ptr h2FT0CptTrBfSelItsTpc; std::shared_ptr h2FT0CptTrBfSelItsTpcTof; @@ -101,14 +103,9 @@ std::shared_ptr hPtTrkItsTpcTofTrStr; std::shared_ptr hPtItsTpcPiStr; std::shared_ptr hPtTrkItsTpcPiStr; // QA reco generated candidate and daugher particles from secondary vertex -std::shared_ptr h2FT0CPtGenColRecoGenCandMC; -std::shared_ptr h2FT0CPtGenColRecoGenTrStrMC; -std::shared_ptr h2FT0CPtGenColRecoGenPiStrMC; -std::shared_ptr h2FT0CPtRecColRecoGenCandMC; -std::shared_ptr h2FT0CPtRecColRecoGenTrStrMC; -std::shared_ptr h2FT0CPtRecColRecoGenPiStrMC; -std::shared_ptr h2FT0CPtRecColRecoTrStrMC; -std::shared_ptr h2FT0CPtRecColRecoPiStrMC; +std::shared_ptr h2FT0CPtGenColRecCandMC; +std::shared_ptr h2FT0CPtGenColRecTrStrMC; +std::shared_ptr h2FT0CPtGenColRecPiStrMC; // QA signal generated candidate and daugher particles from secondary vertex std::shared_ptr h2FT0CPtGenColGenCandMC; std::shared_ptr h2FT0CPtGenColGenTrStrMC; @@ -200,13 +197,16 @@ struct lnnRecoTask { Configurable tpcRigidityMin3H{"tpcRigidityMin3H", 0.2, "Minimum rigidity of the triton candidate"}; Configurable nSigmaCutMinTPC{"nSigmaCutMinTPC", -5, "triton dEdx cut (n sigma)"}; Configurable nSigmaCutMaxTPC{"nSigmaCutMaxTPC", 5, "triton dEdx cut (n sigma)"}; + Configurable nTPCNClsCrossedRows3H{"nTPCNClsCrossedRows3H", 80, "Number of crossed TPC Rows for triton"}; + Configurable nTPCNClsCrossedRowsPi{"nTPCNClsCrossedRowsPi", 80, "Number of crossed TPC Rows for pions"}; Configurable nTPCClusMin3H{"nTPCClusMin3H", 80, "triton NTPC clusters cut"}; Configurable nTPCClusMinPi{"nTPCClusMinPi", 60, "pion NTPC clusters cut"}; Configurable ptMinTOF{"ptMinTOF", 0.8, "minimum pt for TOF cut"}; Configurable trTOFMass2Cut{"trTOFMass2Cut", 5.5, "minimum Triton mass square to TOF"}; Configurable betaTrTOF{"betaTrTOF", 0.4, "minimum beta TOF cut"}; Configurable mcSignalOnly{"mcSignalOnly", true, "If true, save only signal in MC"}; - Configurable doTrackQA{"doTrackQA", true, "If true, compute the QA studies beased on detectors (ITS-TPC-TOF) signals"}; + Configurable doTrackQA{"doTrackQA", true, "if true, compute the QA studies beased on detectors (ITS-TPC-TOF) signals"}; + Configurable useNoSameBunchPileup{"useNoSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; // Define o2 fitter, 2-prong, active memory (no need to redefine per event) o2::vertexing::DCAFitterN<2> fitter; @@ -247,6 +247,7 @@ struct lnnRecoTask { ConfigurableAxis betaBins{"betaBins", {550, 0.f, 1.1f}, "Binning for Beta"}; ConfigurableAxis dcaXYBins{"dcaXYBins", {550, -5.f, 5.f}, "Binning for dcaXY triton"}; ConfigurableAxis tpcNClusBins{"tpcNClusBins", {260, 30, 165}, "Binning for nClusTPC"}; + ConfigurableAxis tpcNClsCrossedRowsBins{"TPCNClsCrossedRowsBins", {260, 30, 165}, "Binning for TPCNClsCrossedRows"}; ConfigurableAxis tpcChi2NClusBins{"tpcChi2NClusBins", {20, 0.5, 10}, "Binning for chi2NClusTPC"}; ConfigurableAxis itsChi2NClusBins{"itsChi2NClusBins", {72, 0, 36}, "Binning for chi2NClusTPC"}; ConfigurableAxis candPtBins{"candPtBins", {160, 0, 8}, "Binning for lnn cand pt"}; @@ -302,6 +303,7 @@ struct lnnRecoTask { const AxisSpec betaAxis{betaBins, "#beta_{TOF}"}; const AxisSpec dcaXYAxis(dcaXYBins, "DCA_{xy} ({}^{3}H (cm)"); const AxisSpec tpcNClusAxis(tpcNClusBins, "N_{clus}^{TPC}"); + const AxisSpec tpcNClsCrossedRowsAxis(tpcNClsCrossedRowsBins, "N_{TPC} crossed rows"); const AxisSpec tpcChi2NClusAxis(tpcChi2NClusBins, "{#Chi}^{2}/N_{clus}^{TPC}"); const AxisSpec itsChi2NClusAxis(itsChi2NClusBins, "{#Chi}^{2}/N_{clus}^{ITS}"); const AxisSpec candPtAxis(candPtBins, "#it{p}_{T} (Gev/#it{c})"); @@ -315,16 +317,18 @@ struct lnnRecoTask { hdEdxTot = qaRegistry.add("hdEdxTot", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dEdxAxis}); h3HMassPtTOF = qaRegistry.add("PID/hTrMassPtTOF", "; #it{p}_{T} ({}^{3}H) (GeV/#it{c}); #frac{m^{2}}{z^{2}} (GeV^{2}/#it{c}^{4})", HistType::kTH2F, {tPtAxis, mTOFAxis}); h3HSignalPtTOF = qaRegistry.add("PID/h3HSignalPtTOF", "; #it{p}_{T}({}^{3}H) (GeV/#it{c}); #beta_{TOF}", HistType::kTH2F, {tPtAxis, betaAxis}); - hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{3, -0.5, 2.5}}); + hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{4, -0.5, 3.5}}); hLnnCandLoss = qaRegistry.add("CandCounts/hLnnCandLoss", ";CandLoss; ", HistType::kTH1D, {{7, -0.5, 6.5}}); // QA its-tpc and its-tpc-tof tracks before selection h2FT0CnClusTPCtoTrBfSel = qaRegistry.add("QATracks/h2FT0CnClusTPCtoTrBfSel", ";FT0C (%);N_{clus}^{TPC}", HistType::kTH2F, {centAxis, tpcNClusAxis}); h2FT0CnClusTPCtoPiBfSel = qaRegistry.add("QATracks/h2FT0CnClusTPCtoPiBfSel", ";FT0C (%);N_{clus}^{TPC}", HistType::kTH2F, {centAxis, tpcNClusAxis}); h2FT0Cchi2NClTPCtoTrBfSel = qaRegistry.add("QATracks/h2FT0Cchi2NClTPCtoTrBfSel", ";FT0C (%);{#Chi}^{2}/N_{clus}^{TPC} ", HistType::kTH2F, {centAxis, tpcChi2NClusAxis}); h2FT0Cchi2NClITStoTrBfSel = qaRegistry.add("QATracks/h2FT0Cchi2NClITStoTrBfSel", ";FT0C (%);{#Chi}^{2}/N_{clus}^{ITS}", HistType::kTH2F, {centAxis, itsChi2NClusAxis}); - h2FT0CptTrBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpc", "; #it{p}_{T}({}^{3}H) (GeV/#it{c}); #beta_{TOF}", HistType::kTH2F, {centAxis, candPtBins}); - h2FT0CptTrBfSelItsTpcTof = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpcTof", "; #it{p}_{T}({}^{3}H) (GeV/#it{c}); #beta_{TOF}", HistType::kTH2F, {centAxis, candPtBins}); - h2FT0CptPiBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptPiBfSelItsTpc", "; #it{p}_{T}({}^{3}H) (GeV/#it{c}); #beta_{TOF}", HistType::kTH2F, {centAxis, candPtBins}); + h2FT0CnTPCNClsCrossedRows3HBfSel = qaRegistry.add("QATracks/h2FT0CnTPCNClsCrossedRows3H", ";FT0C (%);N_{TPC} crossed rows", HistType::kTH2F, {centAxis, tpcNClsCrossedRowsAxis}); + h2FT0CnTPCNClsCrossedRowsPiBfSel = qaRegistry.add("QATracks/h2FT0CnTPCNClsCrossedRowsPi", ";FT0C (%);N_{TPC} crossed rows", HistType::kTH2F, {centAxis, tpcNClsCrossedRowsAxis}); + h2FT0CptTrBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpc", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtBins}); + h2FT0CptTrBfSelItsTpcTof = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpcTof", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtBins}); + h2FT0CptPiBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptPiBfSelItsTpc", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtBins}); // QA its-tpc, its-tpc-tof, and generated MC hPtItsTpcTrStr = qaRegistry.add("MC/McTracks/hPtItsTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); hPtTrkItsTpcTrStr = qaRegistry.add("MC/McTracks/hPtTrkItsTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); @@ -338,6 +342,7 @@ struct lnnRecoTask { hEvents->GetXaxis()->SetBinLabel(1, "All"); hEvents->GetXaxis()->SetBinLabel(2, "sel8"); hEvents->GetXaxis()->SetBinLabel(3, "z_{vtx}"); + hEvents->GetXaxis()->SetBinLabel(4, "NoSameBunchPileUp"); hLnnCandLoss->GetYaxis()->SetTitle("#it{N}_{cand}"); hLnnCandLoss->GetXaxis()->SetTitle("Cuts"); hLnnCandLoss->GetXaxis()->SetBinLabel(1, "Initial"); @@ -349,19 +354,15 @@ struct lnnRecoTask { hLnnCandLoss->GetXaxis()->SetBinLabel(7, "cosPA"); if (doprocessMC) { hDecayChannel = qaRegistry.add("MC/hDecayChannel", ";Decay channel; ", HistType::kTH1D, {{2, -0.5, 1.5}}); - hDecayChannel->GetXaxis()->SetBinLabel(1, "2-body"); + hDecayChannel->GetXaxis()->SetBinLabel(1, "All"); + hDecayChannel->GetXaxis()->SetBinLabel(2, "2-body"); hIsMatterGen = qaRegistry.add("MC/hIsMatterGen", ";; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hIsMatterGen->GetXaxis()->SetBinLabel(1, "Matter"); hIsMatterGen->GetXaxis()->SetBinLabel(2, "Antimatter"); // QA for generated mother candidate and daughter particles - h2FT0CPtGenColRecoGenCandMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtGenColRecoGenCandMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtGenColRecoGenTrStrMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtGenColRecoGenTrStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtGenColRecoGenPiStrMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtGenColRecoGenPiStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtRecColRecoGenCandMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtRecColRecoGenCandMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtRecColRecoGenTrStrMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtRecColRecoGenTrStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtRecColRecoGenPiStrMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtRecColRecoGenPiStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtRecColRecoTrStrMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtRecColRecoTrStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtRecColRecoPiStrMC = qaRegistry.add("MC/QARecoGenSV/h2FT0CPtRecColRecoPiStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); + h2FT0CPtGenColRecCandMC = qaRegistry.add("MC/RecMcCol/h2FT0CPtGenColRecCandMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); + h2FT0CPtGenColRecTrStrMC = qaRegistry.add("MC/RecMcCol/h2FT0CPtGenColRecTrStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); + h2FT0CPtGenColRecPiStrMC = qaRegistry.add("MC/RecMcCol/h2FT0CPtGenColRecPiStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); // QA signal generated candidate and daugher particles from secondary vertex h2FT0CPtGenColGenCandMC = qaRegistry.add("MC/QASignalGenSV/h2FT0CPtGenColGenCandMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); h2FT0CPtGenColGenTrStrMC = qaRegistry.add("MC/QASignalGenSV/h2FT0CPtGenColGenTrStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); @@ -484,6 +485,8 @@ struct lnnRecoTask { // fill QA track histogram studies to check track signal before selections h2FT0CnClusTPCtoTrBfSel->Fill(collision.centFT0C(), h3track.tpcNClsFound()); h2FT0CnClusTPCtoPiBfSel->Fill(collision.centFT0C(), pitrack.tpcNClsFound()); + h2FT0CnTPCNClsCrossedRows3HBfSel->Fill(collision.centFT0C(), h3track.tpcNClsCrossedRows()); + h2FT0CnTPCNClsCrossedRowsPiBfSel->Fill(collision.centFT0C(), pitrack.tpcNClsCrossedRows()); h2FT0Cchi2NClTPCtoTrBfSel->Fill(collision.centFT0C(), h3track.tpcChi2NCl()); h2FT0Cchi2NClITStoTrBfSel->Fill(collision.centFT0C(), h3track.itsChi2NCl()); @@ -503,11 +506,11 @@ struct lnnRecoTask { } if (h3Rigidity < tpcRigidityMin3H || - h3track.tpcNClsFound() < nTPCClusMin3H || + h3track.tpcNClsCrossedRows() < nTPCNClsCrossedRows3H || h3track.tpcChi2NCl() < chi2nClusTPCMin || h3track.tpcChi2NCl() > chi2nClusTPCMax || h3track.itsChi2NCl() > chi2nClusITS || - pitrack.tpcNClsFound() < nTPCClusMinPi) { + pitrack.tpcNClsCrossedRows() < nTPCNClsCrossedRowsPi) { continue; } @@ -697,32 +700,31 @@ struct lnnRecoTask { if (!mcPart.has_mothers()) return false; - bool motherIsAccepted = true; + if (mcPart.getProcess() != 4) + return false; + + bool motherIsAccepted = false; auto mothers = mcPart.mothers_as(); for (const auto& mother : mothers) { - if (mcPart.getProcess() == 4) { - motherIsAccepted = false; - // só aceita se a mãe for um Lnn - if (std::abs(mother.pdgCode()) == lnnPdg) { - motherIsAccepted = true; - } + if (std::abs(mother.pdgCode()) == lnnPdg) { + motherIsAccepted = true; + break; } } return motherIsAccepted; } template - void fillMcHistograms(TracksFullMC::iterator const& mcTrack, aod::McParticles::iterator const& mc, bool motherIsAccepted, Tcoll const& collision) + void fillMcHistograms(TracksFullMC::iterator const& mcTrack, aod::McParticles::iterator const& mc, Tcoll const& collision) { bool passedTrackITS = mcTrack.hasITS(); bool passedTrackTPC = mcTrack.hasTPC(); bool passedTrackTOF = mcTrack.hasTOF(); - if (!motherIsAccepted) - return; + int pdg = std::abs(mc.pdgCode()); - if (std::abs(mc.pdgCode()) == h3DauPdg) { + if (pdg == h3DauPdg) { hPtGeneratedTrStr->Fill(collision.centFT0C(), mc.pt()); if (passedTrackITS && passedTrackTPC) { @@ -735,7 +737,7 @@ struct lnnRecoTask { } } - if (std::abs(mc.pdgCode()) == piDauPdg) { + if (pdg == piDauPdg) { hPtGeneratedPiStr->Fill(collision.centFT0C(), mc.pt()); if (passedTrackITS && passedTrackTPC) { hPtItsTpcPiStr->Fill(collision.centFT0C(), mc.pt()); @@ -761,6 +763,10 @@ struct lnnRecoTask { continue; } hEvents->Fill(2.); + if (useNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + continue; + } + hEvents->Fill(3.); hZvtx->Fill(collision.posZ()); hCentFT0A->Fill(collision.centFT0A()); @@ -809,9 +815,11 @@ struct lnnRecoTask { continue; auto mc = trackMC.mcParticle(); - bool motherIsAccepted = isLnnDecay(mc); - fillMcHistograms(trackMC, mc, motherIsAccepted, collision); + if (!isLnnDecay(mc)) + continue; + + fillMcHistograms(trackMC, mc, collision); } lnnCandidates.clear(); @@ -822,6 +830,7 @@ struct lnnRecoTask { if (collision.has_mcCollision()) { recoCollisionIds[collision.mcCollisionId()] = collision.globalIndex(); } + if ((!collision.sel8())) { continue; } @@ -830,6 +839,10 @@ struct lnnRecoTask { continue; } hEvents->Fill(2.); + if (useNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + continue; + } + hEvents->Fill(3.); hZvtx->Fill(collision.posZ()); hCentFT0A->Fill(collision.centFT0A()); @@ -854,19 +867,10 @@ struct lnnRecoTask { continue; } int chargeFactor = -1 + 2 * (lnnCand.pdgCode > 0); - - // Fill 2D map for generated daughter particles which the mother candidate is reconstructed - h2FT0CPtGenColRecoGenCandMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt()); - h2FT0CPtGenColRecoGenTrStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt3H()); - h2FT0CPtGenColRecoGenPiStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPtPi()); - if (lnnCand.recoMcColl) { - h2FT0CPtRecColRecoGenCandMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt()); - h2FT0CPtRecColRecoGenTrStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt3H()); - h2FT0CPtRecColRecoGenPiStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPtPi()); - if (lnnCand.isReco && lnnCand.survEvSelection) { - h2FT0CPtRecColRecoTrStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.recoPt3H()); - h2FT0CPtRecColRecoPiStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.recoPtPi()); - } + if (lnnCand.recoMcColl && lnnCand.survEvSelection) { + h2FT0CPtGenColRecCandMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt()); + h2FT0CPtGenColRecTrStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt3H()); + h2FT0CPtGenColRecPiStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPtPi()); } outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.posX(), collision.posY(), collision.posZ(), @@ -890,6 +894,9 @@ struct lnnRecoTask { continue; } float cent = collisionFT0Ccent[mcPart.mcCollisionId()]; + + h2FT0CPtGenColGenCandMC->Fill(cent, mcPart.pt()); + constexpr std::size_t kVtxDim = 3; std::array secVtx; std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; @@ -902,14 +909,17 @@ struct lnnRecoTask { bool is3HFound = false; for (const auto& mcDaught : mcPart.daughters_as()) { - if (std::abs(mcDaught.pdgCode()) == h3DauPdg) { + int pdg = std::abs(mcDaught.pdgCode()); + + if (pdg == h3DauPdg) { secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; mom3H = mcDaught.pVector(); + h2FT0CPtGenColGenTrStrMC->Fill(cent, mcDaught.pt()); is3HFound = true; - break; } - if (std::abs(mcDaught.pdgCode()) == piDauPdg) { + if (pdg == piDauPdg) { momPi = mcDaught.pVector(); + h2FT0CPtGenColGenPiStrMC->Fill(cent, mcDaught.pt()); } } @@ -918,9 +928,9 @@ struct lnnRecoTask { } else { hIsMatterGen->Fill(1.); } + if (!is3HFound) { hDecayChannel->Fill(1.); - continue; } hDecayChannel->Fill(0.); if (std::find(filledMothers.begin(), filledMothers.end(), mcPart.globalIndex()) != std::end(filledMothers)) { @@ -941,18 +951,15 @@ struct lnnRecoTask { lnnCand.posTrackID = -1; lnnCand.negTrackID = -1; lnnCand.isSignal = true; - if (lnnCand.isSignal) { - h2FT0CPtGenColGenCandMC->Fill(cent, chargeFactor * lnnCand.genPt()); - h2FT0CPtGenColGenTrStrMC->Fill(cent, chargeFactor * lnnCand.genPt3H()); - h2FT0CPtGenColGenPiStrMC->Fill(cent, chargeFactor * lnnCand.genPtPi()); - } - float centFT0C = -1.; + float centFT0A = -1, centFT0C = -1, centFT0M = -1; if (lnnCand.recoMcColl) { auto recoCollision = collisions.rawIteratorAt(recoCollisionIds[mcPart.mcCollisionId()]); + centFT0A = recoCollision.centFT0A(); centFT0C = recoCollision.centFT0C(); + centFT0M = recoCollision.centFT0M(); } - outputMCTable(-1, centFT0C, -1, + outputMCTable(centFT0A, centFT0C, centFT0M, -1, -1, -1, 0, -1, -1, -1, diff --git a/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx b/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx index 4ba3316a0b7..71cbd488d71 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,7 @@ struct NucleiAntineutronCex { static constexpr double kIts2MaxR = 48.0; // ITS2 max radius [cm] static constexpr double kIts2MaxVz = 39.0; // ITS2 max |vz| [cm] static constexpr double kAccMaxEta = 1.2; // acceptance |eta| - static constexpr double kAccMaxVz = 5.3; // acceptance |vz| [cm] + static constexpr double kAccMaxVz = 10.0; // acceptance |vz| [cm] static constexpr double kStrictEta = 0.9; // tighter eta cut static constexpr double kInitDplane = 10.0; // init dplane static constexpr double kHuge = 1e9; // fallback for bad denom @@ -102,8 +103,24 @@ struct NucleiAntineutronCex { histos.add("pEta", "Pseudorapidity;#eta;Entries", kTH1F, {{100, -10., 10.}}); histos.add("pP_ITScuts", "Momentum with ITS cuts;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); - // test (MC) - histos.add("antip_test", "Secondary antiprotons;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + // Process enum breakdown (secondary antiproton that anchors the SV) + histos.add("hProcEnumAP_CEX", "procEnum of secondary #bar{p} (CEX);procEnum;Entries", kTH1I, {{100, -0.5, 99.5}}); + histos.add("hProcEnumAP_BG", "procEnum of secondary #bar{p} (BG);procEnum;Entries", kTH1I, {{100, -0.5, 99.5}}); + + // Multiplicity/composition at the SV (MC truth, for FINAL selected candidates) + histos.add("hVtxNAll_CEX", "N(all) secondaries at SV (CEX);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + histos.add("hVtxNAll_BG", "N(all) secondaries at SV (BG);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + histos.add("hVtxNCh_CEX", "N(charged) secondaries at SV (CEX);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + histos.add("hVtxNCh_BG", "N(charged) secondaries at SV (BG);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + histos.add("hVtxNNeut_CEX", "N(neutral) secondaries at SV (CEX);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + histos.add("hVtxNNeut_BG", "N(neutral) secondaries at SV (BG);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + + histos.add("hVtxNPi0_CEX", "N(#pi^{0}) at SV (CEX);N;Entries", kTH1I, {{40, -0.5, 39.5}}); + histos.add("hVtxNPi0_BG", "N(#pi^{0}) at SV (BG);N;Entries", kTH1I, {{40, -0.5, 39.5}}); + histos.add("hVtxNGamma_CEX", "N(#gamma) at SV (CEX);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + histos.add("hVtxNGamma_BG", "N(#gamma) at SV (BG);N;Entries", kTH1I, {{60, -0.5, 59.5}}); + histos.add("hVtxNN_CEX", "N(n) at SV (CEX);N;Entries", kTH1I, {{40, -0.5, 39.5}}); + histos.add("hVtxNN_BG", "N(n) at SV (BG);N;Entries", kTH1I, {{40, -0.5, 39.5}}); // CEX pair from antineutron (MC) histos.add("cexPairMcP", "CEX pair total momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); @@ -130,6 +147,13 @@ struct NucleiAntineutronCex { histos.add("cexbg_pairmc_vtxz", "Background secondary vertex Z;Z (cm);Entries", kTH1F, {{200, -60., 60.}}); histos.add("cexbg_pairmc_pITScuts", "Background momentum (ITS cuts);|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("hDeltaP_CEX", "|p_{mother}-Σp_{SV}| (CEX);Δp (GeV/c);Entries", kTH1F, {{200, 0., 10.}}); + histos.add("hDeltaP_BG", "|p_{mother}-Σp_{SV}| (BG);Δp (GeV/c);Entries", kTH1F, {{200, 0., 10.}}); + + // Mother IB hits + histos.add("hMotherNHitIB_CEX", "Mother IB hit layers (L0-L2) (CEX);N_{IB layers};Entries", kTH1I, {{5, -1.5, 4.5}}); + histos.add("hMotherNHitIB_BG", "Mother IB hit layers (L0-L2) (BG);N_{IB layers};Entries", kTH1I, {{5, -1.5, 4.5}}); + // CEX pair from antineutron (TRK) histos.add("cex_pairtrk_angle", "Pair opening angle (tracks);Angle (°);Entries", kTH1F, {{180, 0., 180.}}); histos.add("cexPairTrkP", "Pair momentum (tracks);|p| (GeV/c);Entries", kTH1F, {{120, 0., 12.}}); @@ -260,26 +284,31 @@ struct NucleiAntineutronCex { const bool isSecondaryFromMaterial = (!particle.producedByGenerator()) && (procEnum == kPHadronic || procEnum == kPHInhelastic); if (particle.pdgCode() != -kProton || !isSecondaryFromMaterial || particle.mothersIds().empty()) continue; - histos.fill(HIST("antip_test"), particle.p()); // Primary mother bool hasPrimaryMotherAntip = false; double motherPt = 0.0; + double motherPx = 0.0; + double motherPy = 0.0; double motherPz = 0.0; double motherVz = 0.0; double motherP = 0.0; double motherEta = 0.0; int motherPdg = 0; + int motherId = -1; for (const auto& mother : particle.mothers_as()) { if (mother.isPhysicalPrimary()) { hasPrimaryMotherAntip = true; motherPt = mother.pt(); + motherPx = mother.px(); + motherPy = mother.py(); motherPz = mother.pz(); motherVz = mother.vz(); motherP = mother.p(); motherEta = mother.eta(); motherPdg = mother.pdgCode(); + motherId = mother.globalIndex(); break; } } @@ -530,6 +559,9 @@ struct NucleiAntineutronCex { int8_t antipTrkItsPidValid = 0; float antipTrkTgl = 0.f; + bool motherHasTrack = false; + int motherNHitIB = -1; // number of hits in IB (L0-L2) + o2::aod::ITSResponse itsResponse; for (const auto& track : tracks) { @@ -557,6 +589,11 @@ struct NucleiAntineutronCex { int nITS = track.itsNCls(); bool layerCondition = (!hitIB) && hitOuter && (nITS >= kMinItsHits); + if (mc.globalIndex() == motherId) { + motherHasTrack = true; + motherNHitIB = static_cast(hitL0) + static_cast(hitL1) + static_cast(hitL2); + } + if (mc.globalIndex() == antipId) { antipTrkP = track.p(); antipTrkPx = track.px(); @@ -695,6 +732,13 @@ struct NucleiAntineutronCex { const TVector3 pv2sv(secX - pvtxX, secY - pvtxY, secZ - pvtxZ); const double pairPointingAngleDeg = pv2sv.Angle(total_trk_pVec) * Rad2Deg; + const double pvsvThetaDeg = pv2sv.Theta() * Rad2Deg; + + double pvsvPhiDeg = pv2sv.Phi() * Rad2Deg; + if (pvsvPhiDeg < 0.) { + pvsvPhiDeg += 360.; + } + const double pP = pVecProton_trk.Mag(); const double pAP = AntipVecProton_trk.Mag(); const double ptP = pVecProton_trk.Pt(); @@ -757,16 +801,112 @@ struct NucleiAntineutronCex { const bool isCex = (motherPdg == -kNeutron); + // Nature of the process + if (isCex) { + histos.fill(HIST("hProcEnumAP_CEX"), static_cast(procEnum)); + } else { + histos.fill(HIST("hProcEnumAP_BG"), static_cast(procEnum)); + } + + // Count material secondaries produced at the same SV as the selected secondary antiproton. + int vtxNAll = 0; + int vtxNCh = 0; + int vtxNNeut = 0; + int vtxNPi0 = 0; + int vtxNGamma = 0; + int vtxNN = 0; + double sumPx_vtx = 0.0; + double sumPy_vtx = 0.0; + double sumPz_vtx = 0.0; + auto* pdgDB = TDatabasePDG::Instance(); + + for (const auto& particle5 : mcPartsThis) { + if (particle5.mcCollisionId() != colId) { + continue; + } + // Same SV (use the SV of the selected secondary antiproton) + if (std::abs(particle5.vx() - antipVx) >= kVtxTol || std::abs(particle5.vy() - antipVy) >= kVtxTol || std::abs(particle5.vz() - antipVz) >= kVtxTol) { + continue; + } + const auto proc5Enum = particle5.getProcess(); + const bool isSecondaryFromMaterial5 = + (!particle5.producedByGenerator()) && (proc5Enum == kPHadronic || proc5Enum == kPHInhelastic); + if (!isSecondaryFromMaterial5) { + continue; + } + ++vtxNAll; + sumPx_vtx += particle5.px(); + sumPy_vtx += particle5.py(); + sumPz_vtx += particle5.pz(); + const int pdg = particle5.pdgCode(); + if (pdg == kPi0) { + ++vtxNPi0; + } + if (pdg == kGamma) { + ++vtxNGamma; + } + if (pdg == kNeutron) { + ++vtxNN; + } + // Charged vs neutral via PDG database (Charge() is in units of e/3) + double q = 0.0; + if (auto* part = pdgDB->GetParticle(pdg)) { + q = part->Charge() / 3.0; + } + if (std::abs(q) > 0.0) { + ++vtxNCh; + } else { + ++vtxNNeut; + } + } + + // Fill histos (final selected candidates only) + if (isCex) { + histos.fill(HIST("hVtxNAll_CEX"), vtxNAll); + histos.fill(HIST("hVtxNCh_CEX"), vtxNCh); + histos.fill(HIST("hVtxNNeut_CEX"), vtxNNeut); + histos.fill(HIST("hVtxNPi0_CEX"), vtxNPi0); + histos.fill(HIST("hVtxNGamma_CEX"), vtxNGamma); + histos.fill(HIST("hVtxNN_CEX"), vtxNN); + } else { + histos.fill(HIST("hVtxNAll_BG"), vtxNAll); + histos.fill(HIST("hVtxNCh_BG"), vtxNCh); + histos.fill(HIST("hVtxNNeut_BG"), vtxNNeut); + histos.fill(HIST("hVtxNPi0_BG"), vtxNPi0); + histos.fill(HIST("hVtxNGamma_BG"), vtxNGamma); + histos.fill(HIST("hVtxNN_BG"), vtxNN); + } + const float vtxfitDX = secX - antipVx; const float vtxfitDY = secY - antipVy; const float vtxfitDZ = secZ - antipVz; const float vtxfitD3D = std::sqrt(vtxfitDX * vtxfitDX + vtxfitDY * vtxfitDY + vtxfitDZ * vtxfitDZ); + const double dPx = motherPx - sumPx_vtx; + const double dPy = motherPy - sumPy_vtx; + const double dPz = motherPz - sumPz_vtx; + const double deltaP = std::sqrt(dPx * dPx + dPy * dPy + dPz * dPz); + + if (isCex) { + histos.fill(HIST("hDeltaP_CEX"), deltaP); + } else { + histos.fill(HIST("hDeltaP_BG"), deltaP); + } + + if (motherHasTrack) { + if (isCex) { + histos.fill(HIST("hMotherNHitIB_CEX"), motherNHitIB); + } else { + histos.fill(HIST("hMotherNHitIB_BG"), motherNHitIB); + } + } + const uint32_t selMask = 0u; outPairs( isCex, motherPdg, + motherNHitIB, colId, pId, antipId, @@ -780,6 +920,13 @@ struct NucleiAntineutronCex { antipVy, antipVz, + static_cast(vtxNAll), + static_cast(vtxNCh), + static_cast(vtxNNeut), + static_cast(vtxNPi0), + static_cast(vtxNGamma), + static_cast(vtxNN), + cexPairTrkP, cexPairTrkPt, cexPairTrkPz, @@ -818,6 +965,8 @@ struct NucleiAntineutronCex { selMask, pairPointingAngleDeg, + pvsvThetaDeg, + pvsvPhiDeg, pairPBalance, pairPtBalance, pairQ, diff --git a/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx b/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx index 6ba0b483c46..a412b6a93c4 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx @@ -21,6 +21,7 @@ #include "PWGLF/DataModel/EPCalibrationTables.h" #include "PWGLF/DataModel/LFSlimNucleiTables.h" +#include "PWGLF/Utils/inelGt.h" #include "Common/Core/EventPlaneHelper.h" #include "Common/Core/PID/PIDTOF.h" @@ -52,8 +53,10 @@ #include "ReconstructionDataFormats/Track.h" #include +#include #include #include // for PDG codes +#include #include #include @@ -248,6 +251,14 @@ constexpr int EvSelDefault[9][1]{ {0}, {0}, {0}}; + +enum EvGenSel : uint8_t { + kGenTVX = 1 << 0, + kGenZvtx = 1 << 1, + kGenINELgt0 = 1 << 2, + kHasRecoEv = 1 << 3 +}; + } // namespace nuclei struct nucleiSpectra { @@ -269,7 +280,9 @@ struct nucleiSpectra { Produces nucleiTable; Produces nucleiPairTable; Produces nucleiTableMC; + Produces nucleiTableMCExtension; Produces nucleiTableFlow; + Produces GenEventMCSel; Service ccdb; Zorro zorro; OutputObj zorroSummary{"zorroSummary"}; @@ -334,6 +347,8 @@ struct nucleiSpectra { ConfigurableAxis cfgNTPCClusBins{"cfgNTPCClusBins", {3, 89.5, 159.5}, "N TPC clusters binning"}; Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable cfgTriggerList{"cfgTriggerList", "fHe", "Trigger List"}; + Configurable cfgSelectTrgEv{"cfgSelectTrgEv", false, "If true, select events with active trigger list"}; // running variables for track tuner o2::dataformats::DCA mDcaInfoCov; @@ -349,7 +364,7 @@ struct nucleiSpectra { using TrackCandidates = soa::Join; - // Collisions with chentrality + // Collisions with centrality using CollWithCent = soa::Join::iterator; // Flow analysis @@ -453,7 +468,7 @@ struct nucleiSpectra { return; } if (cfgSkimmedProcessing) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfgTriggerList); zorro.populateHistRegistry(spectra, bc.runNumber()); } auto timestamp = bc.timestamp(); @@ -600,8 +615,15 @@ struct nucleiSpectra { { auto bc = collision.template bc_as(); initCCDB(bc); + + bool isTriggered = true; + + // Using zorro for selecting only events with active trigger if (cfgSkimmedProcessing) { - zorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting + isTriggered = zorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting + if (cfgSelectTrgEv && !isTriggered) { + return; + } } gRandom->SetSeed(bc.timestamp()); @@ -911,21 +933,74 @@ struct nucleiSpectra { PROCESS_SWITCH(nucleiSpectra, processDataFlowAlternative, "Data analysis with flow - alternative framework", false); Preslice tracksPerCollisions = aod::track::collisionId; + Preslice particlesPerMcCollision = aod::mcparticle::mcCollisionId; void processMC(soa::Join const& collisions, aod::McCollisions const& mcCollisions, soa::Join const& tracks, aod::McParticles const& particlesMC, aod::BCsWithTimestamps const&) { nuclei::candidates.clear(); + + std::vector goodCollisions(mcCollisions.size(), false); + std::vector eventMask(mcCollisions.size(), 0); + + auto* pdgDB = TDatabasePDG::Instance(); // Useful for evaluating the particle charge + for (const auto& c : mcCollisions) { + + uint8_t mask = 0; + + const auto& slicedParticles = particlesMC.sliceBy(particlesPerMcCollision, c.globalIndex()); + + bool hasHitFT0A(false); + bool hasHitFT0C(false); + + // TVX trigger + for (const auto& p : slicedParticles) { + if (!p.isPhysicalPrimary()) + continue; + + auto* pdg = pdgDB->GetParticle(p.pdgCode()); + if (!pdg || pdg->Charge() == 0) + continue; + + // Apply the TVX trigger condition + if (p.eta() > 3.5f && p.eta() < 4.9f) + hasHitFT0A = true; + else if (p.eta() > -3.3f && p.eta() < -2.1f) + hasHitFT0C = true; + + if (hasHitFT0A && hasHitFT0C) + break; + } + + if (hasHitFT0A && hasHitFT0C) + mask |= nuclei::kGenTVX; + + // |z| condition + if (std::abs(c.posZ()) < cfgCutVertex) + mask |= nuclei::kGenZvtx; + + // INEL > 0 selection + if (o2::pwglf::isINELgt0mc(slicedParticles, pdgDB)) { + mask |= nuclei::kGenINELgt0; + } + + eventMask[c.globalIndex()] = mask; + GenEventMCSel(mask); spectra.fill(HIST("hGenVtxZ"), c.posZ()); } - std::vector goodCollisions(mcCollisions.size(), false); + for (const auto& collision : collisions) { if (!eventSelectionWithHisto(collision)) { continue; } goodCollisions[collision.mcCollisionId()] = true; + auto& mask = eventMask[collision.mcCollisionId()]; + mask |= nuclei::kHasRecoEv; + + GenEventMCSel(mask); const auto& slicedTracks = tracks.sliceBy(tracksPerCollisions, collision.globalIndex()); fillDataInfo(collision, slicedTracks); } + std::vector isReconstructed(particlesMC.size(), false); for (auto& c : nuclei::candidates) { auto label = tracks.iteratorAt(c.globalIndex); @@ -987,7 +1062,7 @@ struct nucleiSpectra { isReconstructed[particle.globalIndex()] = true; float absoDecL = computeAbsoDecL(particle); - nucleiTableMC(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.nContrib, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS, goodCollisions[particle.mcCollisionId()], particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), motherPdgCode, motherDecRadius, absoDecL); + nucleiTableMCExtension(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.nContrib, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS, goodCollisions[particle.mcCollisionId()], particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), motherPdgCode, motherDecRadius, absoDecL, eventMask[particle.mcCollisionId()]); } int index{0}; @@ -1039,7 +1114,7 @@ struct nucleiSpectra { continue; // skip secondaries from material if not requested } float absDecL = computeAbsoDecL(particle); - nucleiTableMC(999., 999., 999., 0., 0., 999., -1, 999., 999., -1, -1, -1, -1, flags, 0, 0, 0, 0, 0, 0, goodCollisions[particle.mcCollisionId()], particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), motherPdgCode, motherDecRadius, absDecL); + nucleiTableMCExtension(999., 999., 999., 0., 0., 999., -1, 999., 999., -1, -1, -1, -1, flags, 0, 0, 0, 0, 0, 0, goodCollisions[particle.mcCollisionId()], particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), motherPdgCode, motherDecRadius, absDecL, eventMask[particle.mcCollisionId()]); } break; } diff --git a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx index 4cbdecef436..90cfd3f4d5f 100644 --- a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx +++ b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx @@ -84,6 +84,7 @@ struct f1protonreducedtable { Configurable trackSphMin{"trackSphMin", 10, "Number of tracks for Spherocity Calculation"}; // Configs for track PID + Configurable Confglobaltrackcheck{"Confglobaltrackcheck", true, "Global track check"}; Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", true, "Analysed skimmed events"}; Configurable ConfUseManualPIDproton{"ConfUseManualPIDproton", true, "True: use home-made PID solution for proton "}; Configurable ConfUseManualPIDkaon{"ConfUseManualPIDkaon", true, "True: use home-made PID solution for kaon "}; @@ -161,8 +162,8 @@ struct f1protonreducedtable { {"hInvMassf1Like", "hInvMassf1Like", {HistType::kTH2F, {{400, 1.1f, 1.9f}, {100, 0.0f, 10.0f}}}}, {"hInvMassf1kstar", "hInvMassf1kstar", {HistType::kTH3F, {{400, 1.1f, 1.9f}, {100, 0.0f, 10.0f}, {8, 0.0f, 0.8f}}}}, {"hkstarDist", "hkstarDist", {HistType::kTH1F, {{300, 0.0f, 3.0f}}}}, - {"hDCAxy", "hDCAxy", {HistType::kTH1F, {{100, -5.0f, 5.0f}}}}, - {"hDCAz", "hDCAz", {HistType::kTH1F, {{100, -5.0f, 5.0f}}}}, + {"hDCAxy", "hDCAxy", {HistType::kTH3F, {{100, -0.05f, 0.05f}, {5, -2.5, 2.5}, {40, 0.0, 4.0}}}}, + {"hDCAz", "hDCAz", {HistType::kTH3F, {{100, -0.05f, 0.05f}, {2, 0, 2}, {40, 0.0, 4.0}}}}, {"hPhi", "hPhi", {HistType::kTH1F, {{1400, -7.0f, 7.0f}}}}, {"hPhiSphero", "hPhiSphero", {HistType::kTH1F, {{1400, -7.0f, 7.0f}}}}, {"hEta", "hEta", {HistType::kTH1F, {{20, -1.0f, 1.0f}}}}, @@ -170,7 +171,7 @@ struct f1protonreducedtable { {"hNsigmaPtpionTOF", "hNsigmaPtpionTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, {"hNsigmaPtkaonTPC", "hNsigmaPtkaonTPC", {HistType::kTH3F, {{200, -10.0f, 10.0f}, {200, -20.0f, 20.0f}, {100, 0.0f, 10.0f}}}}, {"hNsigmaPtkaonTOF", "hNsigmaPtkaonTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, - {"hNsigmaPtprotonTPC", "hNsigmaPtprotonTPC", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, + {"hNsigmaPtprotonTPC", "hNsigmaPtprotonTPC", {HistType::kTH3F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}, {100, 0.0f, 10.0f}}}}, {"hNsigmaPtprotonTOF", "hNsigmaPtprotonTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, {"hInvMassk0", "hInvMassk0", {HistType::kTH2F, {{200, 0.4f, 0.6f}, {100, 0.0f, 10.0f}}}}, }, @@ -265,7 +266,7 @@ struct f1protonreducedtable { template bool selectionGlobalTrack(const T& candidate) { - if (!(candidate.isGlobalTrack() && candidate.isPVContributor())) { + if (Confglobaltrackcheck && !(candidate.isGlobalTrack() && candidate.isPVContributor())) { return false; } return true; @@ -348,6 +349,32 @@ struct f1protonreducedtable { return false; } + inline bool passProtonPID(float nsigmaTPC, float nsigmaTOF, float TOFHit, ROOT::Math::PtEtaPhiMVector proton) + { + // pidMode: + // 0 = default: p < thr -> |TPC| < 2.5 ; p >= thr -> TOF mandatory AND circular(TPC,TOF) < 2.0 + // 1 = syst-1: p < thr -> |TPC| < 2.0 ; p >= thr -> TOF mandatory AND circular(TPC,TOF) < 2.0 + // 2 = syst-2: p < thr -> |TPC| < 2.5 ; p >= thr -> TOF mandatory AND circular(TPC,TOF) < 2.5 + + if (proton.Pt() > 4.0 || proton.Pt() < 0.15) { + return false; + } + + if (proton.P() < 0.7) { + return (std::abs(nsigmaTPC) < 2.5); + } + + // above threshold: TOF must exist + if (TOFHit != 1) { + return false; + } + + const float nsTPC = nsigmaTPC; + const float nsTOF = nsigmaTOF; + const float comb = std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF); + return (comb < 2.5); + } + template bool SelectionV0(Collision const& collision, V0 const& candidate) { @@ -682,8 +709,6 @@ struct f1protonreducedtable { if (!selectionGlobalTrack(track)) { continue; } - qaRegistry.fill(HIST("hDCAxy"), track.dcaXY()); - qaRegistry.fill(HIST("hDCAz"), track.dcaZ()); qaRegistry.fill(HIST("hEta"), track.eta()); qaRegistry.fill(HIST("hPhi"), track.phi()); double nTPCSigmaP[3]{track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; @@ -778,17 +803,15 @@ struct f1protonreducedtable { ProtonIndex.push_back(track.globalIndex()); ProtonCharge.push_back(track.sign()); - ProtonDcaxy.push_back(std::abs(track.dcaXY())); - ProtonDcaz.push_back(std::abs(track.dcaZ())); + ProtonDcaxy.push_back(track.dcaXY()); + ProtonDcaz.push_back(track.dcaZ()); ProtonTPCNcls.push_back(std::abs(track.tpcNClsFound())); ProtonTPCNcrs.push_back(std::abs(track.tpcNClsCrossedRows())); if (track.sign() > 0) { - qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), nTPCSigmaP[2], track.pt()); ProtonTPCNsigma.push_back(nTPCSigmaP[2]); } if (track.sign() < 0) { - qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), nTPCSigmaN[2], track.pt()); ProtonTPCNsigma.push_back(nTPCSigmaN[2]); } if (track.hasTOF()) { @@ -961,6 +984,25 @@ struct f1protonreducedtable { } } qaRegistry.fill(HIST("hEventstat"), 0.5); + if (keepEventF1Proton) { + for (auto iproton = protons.begin(); iproton != protons.end(); ++iproton) { + auto i6 = std::distance(protons.begin(), iproton); + ProtonVectorDummy2 = protons.at(i6); + if (std::abs(ProtonDcaxy.at(i6)) < 0.05 && std::abs(ProtonDcaz.at(i6)) < 0.05) { + if (ProtonTOFHit.at(i6) && ProtonVectorDummy2.P() > 0.7) { + qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), ProtonTPCNsigma.at(i6), ProtonTOFNsigma.at(i6), ProtonVectorDummy2.Pt()); + } + if (ProtonVectorDummy2.P() < 0.7) { + qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), ProtonTPCNsigma.at(i6), 4.999, ProtonVectorDummy2.Pt()); + } + } + if (passProtonPID(ProtonTPCNsigma.at(i6), ProtonTOFNsigma.at(i6), ProtonTOFHit.at(i6), ProtonVectorDummy2)) { + qaRegistry.fill(HIST("hDCAxy"), ProtonDcaxy.at(i6), ProtonCharge.at(i6), ProtonVectorDummy2.Pt()); + qaRegistry.fill(HIST("hDCAz"), ProtonDcaz.at(i6), ProtonCharge.at(i6), ProtonVectorDummy2.Pt()); + } + } + } + if (numberF1 > 0 && (f1resonance.size() == f1signal.size()) && (f1resonance.size() == f1kaonkshortmass.size()) && (f1resonance.size() == f1resonanced1.size()) && (f1resonance.size() == f1resonanced2.size()) && (f1resonance.size() == f1resonanced3.size())) { qaRegistry.fill(HIST("hEventstat"), 1.5); if (keepEventF1Proton) { diff --git a/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx index e1c4b3cc5d8..d401153f9b6 100644 --- a/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx @@ -793,7 +793,8 @@ struct ResonanceInitializer { v0.mLambda(), v0.mAntiLambda(), v0.mK0Short(), - v0.v0radius(), v0.x(), v0.y(), v0.z()); + v0.v0radius(), v0.x(), v0.y(), v0.z(), + v0.alpha(), v0.qtarm()); if (!cfgBypassTrackIndexFill) { resoV0V0s(v0.globalIndex()); } @@ -1016,7 +1017,7 @@ struct ResonanceInitializer { daughterPDGs = getDaughtersPDGCodes(v0mc); } while (daughters.size() > 2) { - LOGF(info, "daughters.size() is larger than 2"); + // LOGF(info, "daughters.size() is larger than 2"); daughters.pop_back(); daughterPDGs.pop_back(); } @@ -1127,7 +1128,7 @@ struct ResonanceInitializer { daughterPDGs = getDaughtersPDGCodes(cascmc); } while (daughters.size() > 2) { - LOGF(info, "daughters.size() is larger than 2"); + // LOGF(info, "daughters.size() is larger than 2"); daughters.pop_back(); daughterPDGs.pop_back(); } diff --git a/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx index 5a4bc9f2be1..358703eaf13 100644 --- a/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx @@ -1037,7 +1037,8 @@ struct ResonanceDaughterInitializer { v0.mLambda(), v0.mAntiLambda(), v0.mK0Short(), - v0.v0radius(), v0.x(), v0.y(), v0.z()); + v0.v0radius(), v0.x(), v0.y(), v0.z(), + v0.alpha(), v0.qtarm()); if (!cfgBypassTrackIndexFill) { resoV0V0s(v0.globalIndex()); } diff --git a/PWGLF/TableProducer/Strangeness/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/CMakeLists.txt index 43c6331ae07..3f1d8565951 100644 --- a/PWGLF/TableProducer/Strangeness/CMakeLists.txt +++ b/PWGLF/TableProducer/Strangeness/CMakeLists.txt @@ -147,6 +147,11 @@ o2physics_add_dpl_workflow(lambdajetpolarizationbuilder PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lambdajetpolarizationions + SOURCES lambdaJetPolarizationIons.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(stracents SOURCES stracents.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -157,8 +162,8 @@ o2physics_add_dpl_workflow(lambdaspincorrelation PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(sigmaprotoncorr - SOURCES sigmaProtonCorr.cxx +o2physics_add_dpl_workflow(sigmahadcorr + SOURCES sigmaHadCorr.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx index cd825f1ffa4..f944b37749a 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -74,6 +74,7 @@ struct HStrangeCorrelationFilter { Configurable cfgCutOccupancyLow{"cfgCutOccupancyLow", 0, "Low cut on TPC occupancy"}; struct : ConfigurableGroup { + std::string prefix = "eventSelections"; // event filtering Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; Configurable selectINELgtZERO{"selectINELgtZERO", true, "select INEL>0 events"}; @@ -83,12 +84,23 @@ struct HStrangeCorrelationFilter { } eventSelections; struct : ConfigurableGroup { + std::string prefix = "generalSelections"; + + // Associated particle selections in phase space + Configurable assocEtaMin{"assocEtaMin", -0.8, "triggeretamin"}; + Configurable assocEtaMax{"assocEtaMax", 0.8, "triggeretamax"}; + Configurable assocPtCutMin{"assocPtCutMin", 0.2, "assocptmin"}; + Configurable assocPtCutMax{"assocPtCutMax", 10, "assocptmax"}; + // Trigger particle selections in phase space Configurable triggerEtaMin{"triggerEtaMin", -0.8, "triggeretamin"}; Configurable triggerEtaMax{"triggerEtaMax", 0.8, "triggeretamax"}; Configurable triggerPtCutMin{"triggerPtCutMin", 3, "triggerptmin"}; Configurable triggerPtCutMax{"triggerPtCutMax", 20, "triggerptmax"}; + } generalSelections; + struct : ConfigurableGroup { + std::string prefix = "trackSelections"; // Track quality Configurable minTPCNCrossedRows{"minTPCNCrossedRows", 70, "Minimum TPC crossed rows"}; Configurable triggerRequireITS{"triggerRequireITS", true, "require ITS signal in trigger tracks"}; @@ -96,77 +108,62 @@ struct HStrangeCorrelationFilter { Configurable triggerMaxTPCSharedClusters{"triggerMaxTPCSharedClusters", 200, "maximum number of shared TPC clusters (inclusive)"}; Configurable triggerRequireL0{"triggerRequireL0", false, "require ITS L0 cluster for trigger"}; - // Associated particle selections in phase space - Configurable assocEtaMin{"assocEtaMin", -0.8, "triggeretamin"}; - Configurable assocEtaMax{"assocEtaMax", 0.8, "triggeretamax"}; - Configurable assocPtCutMin{"assocPtCutMin", 0.2, "assocptmin"}; - Configurable assocPtCutMax{"assocPtCutMax", 10, "assocptmax"}; - // Associated pion identification Configurable pionMinBayesProb{"pionMinBayesProb", 0.95, "minimal Bayesian probability for pion ID"}; Configurable assocPionNSigmaTPCFOF{"assocPionNSigmaTPCFOF", 3, "minimal n sigma in TOF and TPC for Pion ID"}; Configurable rejectSigma{"rejectSigma", 1, "n sigma for rejecting pion candidates"}; + // primary particle DCAxy selections + // formula: |DCAxy| < 0.004f + (0.013f / pt) + Configurable dcaXYconstant{"dcaXYconstant", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; + Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; + } trackSelections; + struct : ConfigurableGroup { // V0 selections + std::string prefix = "v0Selection"; Configurable v0Cospa{"v0Cospa", 0.97, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) Configurable dcaV0dau{"dcaV0dau", 1.0, "DCA V0 Daughters"}; Configurable dcaNegtopv{"dcaNegtopv", 0.06, "DCA Neg To PV"}; Configurable dcaPostopv{"dcaPostopv", 0.06, "DCA Pos To PV"}; + Configurable dcaBaryonToPV{"dcaBaryonToPV", 0.2, "DCA of baryon daughter track To PV"}; + Configurable dcaMesonToPV{"dcaMesonToPV", 0.05, "DCA of meson daughter track To PV"}; Configurable v0RadiusMin{"v0RadiusMin", 0.5, "v0radius"}; Configurable v0RadiusMax{"v0RadiusMax", 200, "v0radius"}; - // more V0 selections in PbPb + Configurable lifetimecutK0S{"lifetimecutK0S", 20, "lifetimecutK0S"}; Configurable lifetimecutLambda{"lifetimecutLambda", 30, "lifetimecutLambda"}; - Configurable dcanegtopvK0S{"dcanegtopvK0S", 0.1, "DCA Neg To PV"}; - Configurable dcapostopvK0S{"dcapostopvK0S", 0.1, "DCA Pos To PV"}; - Configurable dcanegtopvLambda{"dcanegtopvLambda", 0.05, "DCA Neg To PV"}; - Configurable dcapostopvLambda{"dcapostopvLambda", 0.2, "DCA Pos To PV"}; - Configurable dcanegtopvAntiLambda{"dcanegtopvAntiLambda", 0.2, "DCA Neg To PV"}; - Configurable dcapostopvAntiLambda{"dcapostopvAntiLambda", 0.05, "DCA Pos To PV"}; - // original equation: lArmPt*2>TMath::Abs(lArmAlpha) only for K0S Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; - // specific selections - Configurable lambdaCospa{"lambdaCospa", 0.995, "CosPA for lambda"}; // allows for tighter selection for Lambda - - // primary particle DCAxy selections - // formula: |DCAxy| < 0.004f + (0.013f / pt) - Configurable dcaXYconstant{"dcaXYconstant", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; - Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; - - // cascade selections - Configurable cascCospa{"cascCospa", 0.95, "cascCospa"}; - Configurable cascRadius{"cascRadius", 0.5, "cascRadius"}; - Configurable dcaCascdau{"dcaCascdau", 1.0, "dcaCascdau"}; - Configurable dcaBachtopv{"dcaBachtopv", 0.1, "dcaBachtopv"}; - Configurable cascV0masswindow{"cascV0masswindow", 0.01, "cascV0masswindow"}; - Configurable cascMindcav0topv{"cascMindcav0topv", 0.01, "cascMindcav0topv"}; - - // pt Range for pt dep cuts - Configurable highPtForCascDaugPtDep{"highPtForCascDaugPtDep", 4.0, "high pt range for pt dep cuts"}; - Configurable lowPtForCascDaugPtDep{"lowPtForCascDaugPtDep", 1.0, "low pt range for pt dep cuts"}; - } systCuts; + Configurable lambdaCospa{"lambdaCospa", 0.995, "Lambda CosPA, if needed to be stricter"}; // allows for tighter selection for Lambda + } v0Selection; struct : ConfigurableGroup { - // cascade selections in PbPb - Configurable cascDcacascdau{"cascDcacascdau", 1.0, "cascDcacascdau"}; - Configurable cascDcabachtopv{"cascDcabachtopv", 0.1, "cascDcabachtopv"}; + // cascade selections + std::string prefix = "cascSelection"; Configurable bachBaryonCosPA{"bachBaryonCosPA", 0.9999, "Bachelor baryon CosPA"}; Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; - Configurable dcaBaryonToPV{"dcaBaryonToPV", 0.05, "DCA of baryon doughter track To PV"}; - Configurable dcaMesonToPV{"dcaMesonToPV", 0.1, "DCA of meson doughter track To PV"}; Configurable dcaBachToPV{"dcaBachToPV", 0.07, "DCA Bach To PV"}; + Configurable cascDcaBaryonToPV{"cascDcaBaryonToPV", 0.2, "DCA of baryon daughter track To PV"}; + Configurable cascDcaMesonToPV{"cascDcaMesonToPV", 0.05, "DCA of meson daughter track To PV"}; Configurable cascdcaV0dau{"cascdcaV0dau", 0.5, "DCA V0 Daughters"}; Configurable dcaCacsDauPar0{"dcaCacsDauPar0", 0.8, " par for pt dep DCA cascade daughter cut, p_T < 1 GeV/c"}; Configurable dcaCacsDauPar1{"dcaCacsDauPar1", 0.5, " par for pt dep DCA cascade daughter cut, 1< p_T < 4 GeV/c"}; Configurable dcaCacsDauPar2{"dcaCacsDauPar2", 0.2, " par for pt dep DCA cascade daughter cut, p_T > 4 GeV/c"}; - Configurable cascdcaV0ToPV{"cascdcaV0ToPV", 0.06, "DCA V0 To PV"}; Configurable cascv0cospa{"cascv0cospa", 0.98, "V0 CosPA"}; Configurable cascv0RadiusMin{"cascv0RadiusMin", 2.5, "v0radius"}; Configurable proplifetime{"proplifetime", 3, "ctau/"}; Configurable lambdaMassWin{"lambdaMassWin", 0.005, "V0 Mass window limit"}; Configurable rejcomp{"rejcomp", 0.008, "Competing Cascade rejection"}; Configurable rapCut{"rapCut", 0.8, "Rapidity acceptance"}; - } MorePbPbsystCuts; + Configurable cascCospa{"cascCospa", 0.95, "cascCospa"}; + Configurable cascRadius{"cascRadius", 0.5, "cascRadius"}; + Configurable dcaCascdau{"dcaCascdau", 1.0, "DCA between V0 and bachelor track"}; + Configurable dcaBachtopv{"dcaBachtopv", 0.1, "DCA bachelor track to PV"}; + Configurable cascV0masswindow{"cascV0masswindow", 0.01, "V0 Mass window"}; + Configurable cascMindcav0topv{"cascMindcav0topv", 0.01, "Minimum DCA V0 to PV"}; + // pt Range for pt dep cuts + Configurable highPtForCascDaugPtDep{"highPtForCascDaugPtDep", 4.0, "high pt range for pt dep cuts"}; + Configurable lowPtForCascDaugPtDep{"lowPtForCascDaugPtDep", 1.0, "low pt range for pt dep cuts"}; + } cascSelection; Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository to use"}; Configurable parameterCCDBPath{"parameterCCDBPath", "Users/k/kcui/LHC25b4a/parameter", "Path of the mean and sigma"}; @@ -186,11 +183,11 @@ struct HStrangeCorrelationFilter { // QA Configurable doTrueSelectionInMass{"doTrueSelectionInMass", false, "Fill mass histograms only with true primary Particles for MC"}; // Do declarative selections for DCAs, if possible - Filter preFilterTracks = nabs(aod::track::dcaXY) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * nabs(aod::track::signed1Pt); - Filter preFilterV0 = nabs(aod::v0data::dcapostopv) > systCuts.dcaPostopv&& - nabs(aod::v0data::dcanegtopv) > systCuts.dcaNegtopv&& aod::v0data::dcaV0daughters < systCuts.dcaV0dau; + Filter preFilterTracks = nabs(aod::track::dcaXY) < trackSelections.dcaXYconstant + trackSelections.dcaXYpTdep * nabs(aod::track::signed1Pt); + Filter preFilterV0 = nabs(aod::v0data::dcapostopv) > v0Selection.dcaPostopv&& + nabs(aod::v0data::dcanegtopv) > v0Selection.dcaNegtopv&& aod::v0data::dcaV0daughters < v0Selection.dcaV0dau; Filter preFilterCascade = - nabs(aod::cascdata::dcapostopv) > systCuts.dcaPostopv&& nabs(aod::cascdata::dcanegtopv) > systCuts.dcaNegtopv&& nabs(aod::cascdata::dcabachtopv) > systCuts.dcaBachtopv&& aod::cascdata::dcaV0daughters < systCuts.dcaV0dau&& aod::cascdata::dcacascdaughters < systCuts.dcaCascdau; + nabs(aod::cascdata::dcapostopv) > v0Selection.dcaPostopv&& nabs(aod::cascdata::dcanegtopv) > v0Selection.dcaNegtopv&& nabs(aod::cascdata::dcabachtopv) > cascSelection.dcaBachtopv&& aod::cascdata::dcaV0daughters < cascSelection.cascdcaV0dau&& aod::cascdata::dcacascdaughters < cascSelection.dcaCascdau; // using V0LinkedTagged = soa::Join; // using CascadesLinkedTagged = soa::Join; @@ -391,23 +388,23 @@ struct HStrangeCorrelationFilter { template bool isValidTrigger(TTrack track) { - if (track.eta() > systCuts.triggerEtaMax || track.eta() < systCuts.triggerEtaMin) { + if (track.eta() > generalSelections.triggerEtaMax || track.eta() < generalSelections.triggerEtaMin) { return false; } // if (track.sign()= 1 ) {continue;} - if (track.pt() > systCuts.triggerPtCutMax || track.pt() < systCuts.triggerPtCutMin) { + if (track.pt() > generalSelections.triggerPtCutMax || track.pt() < generalSelections.triggerPtCutMin) { return false; } - if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) { + if (track.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { return false; // crossed rows } - if (!track.hasITS() && systCuts.triggerRequireITS) { + if (!track.hasITS() && trackSelections.triggerRequireITS) { return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) } - if (track.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) { + if (track.tpcNClsShared() > trackSelections.triggerMaxTPCSharedClusters) { return false; // skip, has shared clusters } - if (!(BIT_CHECK(track.itsClusterMap(), 0)) && systCuts.triggerRequireL0) { + if (!(BIT_CHECK(track.itsClusterMap(), 0)) && trackSelections.triggerRequireL0) { return false; // skip, doesn't have cluster in ITS L0 } return true; @@ -415,16 +412,16 @@ struct HStrangeCorrelationFilter { template bool isValidAssocTrack(TTrack assoc) { - if (assoc.eta() > systCuts.assocEtaMax || assoc.eta() < systCuts.assocEtaMin) { + if (assoc.eta() > generalSelections.assocEtaMax || assoc.eta() < generalSelections.assocEtaMin) { return false; } - if (assoc.pt() > systCuts.assocPtCutMax || assoc.pt() < systCuts.assocPtCutMin) { + if (assoc.pt() > generalSelections.assocPtCutMax || assoc.pt() < generalSelections.assocPtCutMin) { return false; } - if (assoc.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) { + if (assoc.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { return false; // crossed rows } - if (!assoc.hasITS() && systCuts.assocRequireITS) { + if (!assoc.hasITS() && trackSelections.assocRequireITS) { return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) } @@ -432,26 +429,26 @@ struct HStrangeCorrelationFilter { float nSigmaTPCTOF[8] = {-10, -10, -10, -10, -10, -10, -10, -10}; if constexpr (requires { assoc.tofSignal(); } && !requires { assoc.mcParticle(); }) { if (assoc.tofSignal() > 0) { - if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > systCuts.assocPionNSigmaTPCFOF) + if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > trackSelections.assocPionNSigmaTPCFOF) return false; - if (assoc.tofNSigmaPr() < systCuts.rejectSigma) + if (assoc.tofNSigmaPr() < trackSelections.rejectSigma) return false; - if (assoc.tpcNSigmaPr() < systCuts.rejectSigma) + if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) return false; - if (assoc.tofNSigmaKa() < systCuts.rejectSigma) + if (assoc.tofNSigmaKa() < trackSelections.rejectSigma) return false; - if (assoc.tpcNSigmaKa() < systCuts.rejectSigma) + if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) return false; nSigmaTPCTOF[4] = assoc.tofNSigmaPi(); nSigmaTPCTOF[5] = assoc.tofNSigmaKa(); nSigmaTPCTOF[6] = assoc.tofNSigmaPr(); nSigmaTPCTOF[7] = assoc.tofNSigmaEl(); } else { - if (assoc.tpcNSigmaPi() > systCuts.assocPionNSigmaTPCFOF) + if (assoc.tpcNSigmaPi() > trackSelections.assocPionNSigmaTPCFOF) return false; - if (assoc.tpcNSigmaPr() < systCuts.rejectSigma) + if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) return false; - if (assoc.tpcNSigmaKa() < systCuts.rejectSigma) + if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) return false; } nSigmaTPCTOF[0] = assoc.tpcNSigmaPi(); @@ -495,39 +492,39 @@ struct HStrangeCorrelationFilter { bool cascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) { // bachBaryonCosPA - if (casc.bachBaryonCosPA() < MorePbPbsystCuts.bachBaryonCosPA) + if (casc.bachBaryonCosPA() < cascSelection.bachBaryonCosPA) return false; // bachBaryonDCAxyToPV - if (std::abs(casc.bachBaryonDCAxyToPV()) > MorePbPbsystCuts.bachBaryonDCAxyToPV) + if (std::abs(casc.bachBaryonDCAxyToPV()) > cascSelection.bachBaryonDCAxyToPV) return false; // casccosPA - if (casc.casccosPA(pvx, pvy, pvz) < systCuts.cascCospa) + if (casc.casccosPA(pvx, pvy, pvz) < cascSelection.cascCospa) return false; // dcacascdaughters - float ptDepCut = MorePbPbsystCuts.dcaCacsDauPar0; - if (casc.pt() > systCuts.lowPtForCascDaugPtDep && casc.pt() < systCuts.highPtForCascDaugPtDep) - ptDepCut = MorePbPbsystCuts.dcaCacsDauPar1; - else if (casc.pt() > systCuts.highPtForCascDaugPtDep) - ptDepCut = MorePbPbsystCuts.dcaCacsDauPar2; + float ptDepCut = cascSelection.dcaCacsDauPar0; + if (casc.pt() > cascSelection.lowPtForCascDaugPtDep && casc.pt() < cascSelection.highPtForCascDaugPtDep) + ptDepCut = cascSelection.dcaCacsDauPar1; + else if (casc.pt() > cascSelection.highPtForCascDaugPtDep) + ptDepCut = cascSelection.dcaCacsDauPar2; if (casc.dcacascdaughters() > ptDepCut) return false; // dcaV0daughters - if (casc.dcaV0daughters() > systCuts.dcaV0dau) + if (casc.dcaV0daughters() > cascSelection.cascdcaV0dau) return false; // dcav0topv - if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < MorePbPbsystCuts.cascdcaV0ToPV) + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascSelection.cascMindcav0topv) return false; // cascradius - if (casc.cascradius() < systCuts.cascRadius) + if (casc.cascradius() < cascSelection.cascRadius) return false; // v0radius - if (casc.v0radius() < MorePbPbsystCuts.cascv0RadiusMin) + if (casc.v0radius() < cascSelection.cascv0RadiusMin) return false; // v0cosPA - if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < MorePbPbsystCuts.cascv0cospa) + if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascSelection.cascv0cospa) return false; // lambdaMassWin - if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > MorePbPbsystCuts.lambdaMassWin) + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.lambdaMassWin) return false; return true; } @@ -733,10 +730,10 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Populate table with associated V0s for (auto const& v0 : V0s) { - if (v0.v0radius() < systCuts.v0RadiusMin || v0.v0radius() > systCuts.v0RadiusMax || v0.eta() > systCuts.assocEtaMax || v0.eta() < systCuts.assocEtaMin || v0.v0cosPA() < systCuts.v0Cospa) { + if (v0.v0radius() < v0Selection.v0RadiusMin || v0.v0radius() > v0Selection.v0RadiusMax || v0.eta() > generalSelections.assocEtaMax || v0.eta() < generalSelections.assocEtaMin || v0.v0cosPA() < v0Selection.v0Cospa) { continue; } - if (v0.pt() > systCuts.assocPtCutMax || v0.pt() < systCuts.assocPtCutMin) { + if (v0.pt() > generalSelections.assocPtCutMax || v0.pt() < generalSelections.assocPtCutMin) { continue; } // check dE/dx compatibility @@ -747,76 +744,61 @@ struct HStrangeCorrelationFilter { auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - if (negdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; - if (posdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; + bool isGoodK0Short = (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && + std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV && + v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha())); + bool isGoodLambda = (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda && + std::abs(v0.dcapostopv()) > v0Selection.dcaBaryonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV); + bool isGoodAntiLambda = (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar < v0Selection.lifetimecutLambda && + std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV); if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && - v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + if (doPPAnalysis || isGoodK0Short) { BIT_SET(compatibleK0Short, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && - v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + if (doPPAnalysis || isGoodK0Short) { BIT_SET(compatibleK0Short, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && - v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + if (doPPAnalysis || isGoodK0Short) { BIT_SET(compatibleK0Short, 2); } } - if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + if (v0.v0cosPA() > v0Selection.lambdaCospa) { + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { + if (doPPAnalysis || isGoodLambda) { BIT_SET(compatibleLambda, 0); } } - } - if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { + if (doPPAnalysis || isGoodLambda) { BIT_SET(compatibleLambda, 1); } } - } - if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { + if (doPPAnalysis || isGoodLambda) { BIT_SET(compatibleLambda, 2); } } - } - if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { + if (doPPAnalysis || isGoodAntiLambda) { BIT_SET(compatibleAntiLambda, 0); } } - } - if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { + if (doPPAnalysis || isGoodAntiLambda) { BIT_SET(compatibleAntiLambda, 1); } } - } - if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { + if (doPPAnalysis || isGoodAntiLambda) { BIT_SET(compatibleAntiLambda, 2); } } @@ -874,10 +856,10 @@ struct HStrangeCorrelationFilter { /// Populate table with associated V0s for (auto const& v0 : V0s) { - if (v0.v0radius() < systCuts.v0RadiusMin || v0.v0radius() > systCuts.v0RadiusMax || v0.eta() > systCuts.assocEtaMax || v0.eta() < systCuts.assocEtaMin || v0.v0cosPA() < systCuts.v0Cospa) { + if (v0.v0radius() < v0Selection.v0RadiusMin || v0.v0radius() > v0Selection.v0RadiusMax || v0.eta() > generalSelections.assocEtaMax || v0.eta() < generalSelections.assocEtaMin || v0.v0cosPA() < v0Selection.v0Cospa) { continue; } - if (v0.pt() > systCuts.assocPtCutMax || v0.pt() < systCuts.assocPtCutMin) { + if (v0.pt() > generalSelections.assocPtCutMax || v0.pt() < generalSelections.assocPtCutMin) { continue; } // check dE/dx compatibility @@ -888,76 +870,62 @@ struct HStrangeCorrelationFilter { auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - if (negdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; - if (posdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; + bool isGoodK0Short = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && + std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV && + v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha()); + bool isGoodLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda && + std::abs(v0.dcapostopv()) > v0Selection.dcaBaryonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV; + bool isGoodAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar < v0Selection.lifetimecutLambda && + std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV; if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && - v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + if (doPPAnalysis || isGoodK0Short) { BIT_SET(compatibleK0Short, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && - v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + if (doPPAnalysis || isGoodK0Short) { BIT_SET(compatibleK0Short, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && - v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + if (doPPAnalysis || isGoodK0Short) { BIT_SET(compatibleK0Short, 2); } } - if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + if (v0.v0cosPA() > v0Selection.lambdaCospa) { + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { + if (doPPAnalysis || isGoodLambda) { BIT_SET(compatibleLambda, 0); } } - } - if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { + if (doPPAnalysis || isGoodLambda) { BIT_SET(compatibleLambda, 1); } } - } - if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { + if (doPPAnalysis || isGoodLambda) { BIT_SET(compatibleLambda, 2); } } - } - if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { + if (doPPAnalysis || isGoodAntiLambda) { BIT_SET(compatibleAntiLambda, 0); } } - } - if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { + if (doPPAnalysis || isGoodAntiLambda) { BIT_SET(compatibleAntiLambda, 1); } } - } - if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { - if (v0.v0cosPA() > systCuts.lambdaCospa) { - if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && - std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { + if (doPPAnalysis || isGoodAntiLambda) { BIT_SET(compatibleAntiLambda, 2); } } @@ -1026,31 +994,36 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 3: Populate table with associated Cascades for (auto const& casc : Cascades) { - if (casc.eta() > systCuts.assocEtaMax || casc.eta() < systCuts.assocEtaMin) { + if (casc.eta() > generalSelections.assocEtaMax || casc.eta() < generalSelections.assocEtaMin) { continue; } - if (casc.pt() > systCuts.assocPtCutMax || casc.pt() < systCuts.assocPtCutMin) { + if (casc.pt() > generalSelections.assocPtCutMax || casc.pt() < generalSelections.assocPtCutMin) { continue; } - if (doPPAnalysis && (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.v0Cospa || - casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.cascCospa || - casc.cascradius() < systCuts.cascRadius || - std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < systCuts.cascMindcav0topv || - std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow)) + if (doPPAnalysis && (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascv0cospa || + casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascCospa || + casc.cascradius() < cascSelection.cascRadius || + std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascSelection.cascMindcav0topv || + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) continue; auto bachTrackCast = casc.bachelor_as(); auto posTrackCast = casc.posTrack_as(); auto negTrackCast = casc.negTrack_as(); // minimum TPC crossed rows - if (bachTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; - if (posTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; - if (negTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) continue; + + bool isGoodNegCascadePbPb = std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaBaryonToPV && + std::abs(casc.dcanegtopv()) > cascSelection.cascDcaMesonToPV; + bool isGoodPosCascadePbPb = std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaMesonToPV && + std::abs(casc.dcanegtopv()) > cascSelection.cascDcaBaryonToPV; // check dE/dx compatibility int compatibleXiMinus = 0; int compatibleXiPlus = 0; @@ -1061,90 +1034,70 @@ struct HStrangeCorrelationFilter { float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxi); float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomega); + bool isGoodXiPbPb = std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascSelection.rejcomp && + ctauXi < cascSelection.proplifetime && std::abs(casc.yXi()) < cascSelection.rapCut; + bool isGoodOmegaPbPb = std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascSelection.rejcomp && + ctauOmega < cascSelection.proplifetime && std::abs(casc.yOmega()) < cascSelection.rapCut; if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { BIT_SET(compatibleXiMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { BIT_SET(compatibleXiMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { BIT_SET(compatibleXiMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { BIT_SET(compatibleXiPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { BIT_SET(compatibleXiPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { BIT_SET(compatibleXiPlus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaPlus, 2); } } @@ -1197,17 +1150,17 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 3: Populate table with associated Cascades for (auto const& casc : Cascades) { - if (casc.eta() > systCuts.assocEtaMax || casc.eta() < systCuts.assocEtaMin) { + if (casc.eta() > generalSelections.assocEtaMax || casc.eta() < generalSelections.assocEtaMin) { continue; } - if (casc.pt() > systCuts.assocPtCutMax || casc.pt() < systCuts.assocPtCutMin) { + if (casc.pt() > generalSelections.assocPtCutMax || casc.pt() < generalSelections.assocPtCutMin) { continue; } - if (doPPAnalysis && (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.v0Cospa || - casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.cascCospa || - casc.cascradius() < systCuts.cascRadius || - std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < systCuts.cascMindcav0topv || - std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow)) + if (doPPAnalysis && (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascv0cospa || + casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascCospa || + casc.cascradius() < cascSelection.cascRadius || + std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascSelection.cascMindcav0topv || + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) continue; auto bachTrackCast = casc.bachelor_as(); @@ -1215,15 +1168,18 @@ struct HStrangeCorrelationFilter { auto negTrackCast = casc.negTrack_as(); // minimum TPC crossed rows - if (bachTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; - if (posTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; - if (negTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) continue; if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) continue; - + bool isGoodNegCascadePbPb = (std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaBaryonToPV && + std::abs(casc.dcanegtopv()) > cascSelection.cascDcaMesonToPV); + bool isGoodPosCascadePbPb = (std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaMesonToPV && + std::abs(casc.dcanegtopv()) > cascSelection.cascDcaBaryonToPV); // check dE/dx compatibility int compatibleXiMinus = 0; int compatibleXiPlus = 0; @@ -1234,90 +1190,70 @@ struct HStrangeCorrelationFilter { float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxi); float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomega); + bool iGoodXiPbPb = std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascSelection.rejcomp && + ctauXi < cascSelection.proplifetime && std::abs(casc.yXi()) < cascSelection.rapCut; + bool isGoodOmegaPbPb = std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascSelection.rejcomp && + ctauOmega < cascSelection.proplifetime && std::abs(casc.yOmega()) < cascSelection.rapCut; if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { BIT_SET(compatibleXiMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { BIT_SET(compatibleXiMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { BIT_SET(compatibleXiMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { BIT_SET(compatibleXiPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { BIT_SET(compatibleXiPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && - ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { BIT_SET(compatibleXiPlus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { - if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && - ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { BIT_SET(compatibleOmegaPlus, 2); } } diff --git a/PWGLF/TableProducer/Strangeness/lambdaJetPolarizationIons.cxx b/PWGLF/TableProducer/Strangeness/lambdaJetPolarizationIons.cxx new file mode 100644 index 00000000000..0ed6559e140 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/lambdaJetPolarizationIons.cxx @@ -0,0 +1,2031 @@ +// 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 lambdaJetPolarizationIons.cxx +/// \brief Lambda and antiLambda polarization analysis task using raw data +/// +/// \author Cicero Domenico Muncinelli , Campinas State University +// +// Jet Polarization Ions task +// ================ +// +// This code loops over a V0Datas table and produces standard derived +// data as output. In the post-processing stage, this analysis aims +// to measure the formation of vorticity rings in HI collisions. +// +// Comments, questions, complaints, suggestions? +// Please write to: +// cicero.domenico.muncinelli@cern.ch +// + +// Standard Library +#include +#include +#include +#include +#include +#include + +// PWGLF +#include "EventSelectionParams.h" +#include "RCTSelectionFlags.h" + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/lambdaJetPolarizationIons.h" +// #include "Common/DataModel/PIDResponseTOF.h" // Maybe switch this around with LFStrangenessPIDTables? +#include "PWGLF/DataModel/LFStrangenessTables.h" // For V0TOFPIDs and NSigmas getters. Better for considering the daughters as coming from V0s instead of from PV: + +// // MC +// #include "Common/DataModel/CollisionAssociationTables.h" +// #include "Common/DataModel/McCollisionExtra.h" +// #include "PWGLF/DataModel/mcCentrality.h" + +// PWGJE +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetUtilities.h" + +// Common DataModel +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +// Common Core +#include "Common/Core/RecoDecay.h" + +// Framework +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// O2 subsystems +#include "Common/CCDB/ctpRateFetcher.h" + +#include +#include +#include + +// External libraries +#include +#include +#include +#include +#include +#include +#include + +// ROOT math +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; + +///// Aliases for joined tables +/// Collisions: +using SelCollisions = soa::Join; // Added PVMults to get MultNTracksPVeta1 as centrality estimator +/// V0s and Daughter tracks: +using V0CandidatesWithTOF = soa::Join; // Tables created by o2-analysis-lf-strangenesstofpid +using DauTracks = soa::Join; +/// Jets: +// using JetTracks = soa::Join; // Simpler tracks access, yet can't pass this and DauTracks as subscriptions simultaneously. +/// MC: +// using SimCollisions = soa::Join; +// using DauTracksMC = soa::Join; + +enum CentEstimator { + kCentFT0C = 0, + kCentFT0M, + kCentFV0A +}; + +enum JetAlgorithm { + kKt = 0, + kCambridgeAachen, + kAntiKt +}; + +enum JetRecombScheme { + kEScheme = 0, + kPtScheme = 1, + kPt2Scheme = 2, + kWTAScheme = 7 +}; + +enum JetType { + kChargedJet = 0, + kFullJet, + kPhotonJet, + kZJet +}; + +enum BkgSubtraction { + kNoSubtraction = 0, + kAreaBased, + kConstituentBased +}; + +////////////////////////////////////////////// +struct lambdajetpolarizationions { + + // struct : ProducesGroup { + // } products; + Produces tableV0s; + Produces tableJets; + Produces tableLeadParticles; + Produces tableCollisions; + + // Define histogram registries: + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // master analysis switches + Configurable analyseLambda{"analyseLambda", true, "process Lambda-like candidates"}; + Configurable analyseAntiLambda{"analyseAntiLambda", false, "process AntiLambda-like candidates"}; // Will work only with Lambdas, in a first analysis + + Configurable doPPAnalysis{"doPPAnalysis", false, "if in pp, set to true. Default is HI"}; + Configurable irSource{"irSource", "ZNChadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNChadronic)"}; // Renamed David's "ZNC hadronic" to the proper code "ZNChadronic" + Configurable centralityEstimatorForQA{"centralityEstimatorForQA", kCentFT0M, "Run 3 centrality estimator (0:CentFT0C, 1:CentFT0M, 2:CentFV0A)"}; // Default is FT0M + // (Now saving all centralities at the derived data level -- Makes them all available for consumer) + // (But still using this variable for QA histograms) + + ///////////////////////////////////////////// + Configurable doEventQA{"doEventQA", false, "do event QA histograms"}; + // Configurable qaCentrality{"qaCentrality", false, "qa centrality flag: check base raw values"}; + Configurable doCompleteTopoQA{"doCompleteTopoQA", false, "do topological variables QA histograms"}; // Includes doPlainTopoQA from derivedlambdakzeroanalysis + Configurable doV0KinematicQA{"doV0KinematicQA", false, "do kinematic variables QA histograms"}; + Configurable doArmenterosQA{"doArmenterosQA", false, "do Armenteros QA histograms"}; + Configurable doTPCQA{"doTPCQA", false, "do TPC QA histograms"}; + Configurable doTOFQA{"doTOFQA", false, "do TOF QA histograms"}; + Configurable doEtaPhiQA{"doEtaPhiQA", false, "do Eta/Phi QA histograms for V0s and daughters"}; + Configurable doJetKinematicsQA{"doJetKinematicsQA", false, "do pT,Eta,Phi QA histograms for jets"}; + ///////////////////////////////////////////// + + // ///////////////////////////////////////////// + // MC block -- not implemented! (TODO) + // Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + // Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; + // Configurable doCollisionAssociationQA{"doCollisionAssociationQA", true, "check collision association"}; + // ///////////////////////////////////////////// + + // TODO: COMPLEMENTARY ANALYSES TO STUDY SPURIOUS POLARIZATION SOURCES! + // TODO: add an event plane selection procedure to get an angle between the global polarization axis and the jet axis to uncouple polarizations? + // TODO: (related to previous comment) if we already have event plane, also estimate v_2-caused polarization. Hydro papers indicate observable is unsensitive to this spurious polarization, but this is a perfect consistency check. + // TODO: add a longitudinal polarization block of code to estimate other sources of polarization (and possibly study their differential dependence on the angle wrlt the jets and their rings)? + // TODO: add a block of code that calculates polarization from Lambda fragmentation to estimate the contamination of this third source of polarization + + // Configurable groups: + struct : ConfigurableGroup { + std::string prefix = "eventSelections"; // JSON group name + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; // part of sel8, actually + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border (Run 3 only)"}; // part of sel8, actually + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border (Run 3 only)"}; // part of sel8, actually + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "require events with at least one ITS-TPC track (Run 3 only)"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference (Run 3 only)"}; // o2::aod::evsel::kIsGoodZvtxFT0vsPV. Recommended for OO + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF (Run 3 only)"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD (Run 3 only)"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC (Run 3 only)"}; // o2::aod::evsel::kNoSameBunchPileup. Recommended for OO + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds (Run 3 only)"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds (Run 3 only)"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds (Run 3 only)"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold (Run 3 only)"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF (Run 3 only)"}; + Configurable requireINEL0{"requireINEL0", true, "require INEL>0 event selection"}; // Only truly useful in pp + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + + Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; + Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", true, "Apply Z-vtx cut on the PV of the generated collision?"}; // I see no reason as to not do this by default + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + // fast check on interaction rate + Configurable minIR{"minIR", -1, "minimum IR collisions"}; + Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; + } eventSelections; + + struct : ConfigurableGroup { + std::string prefix = "v0Selections"; // JSON group name + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + + // Selection criteria: acceptance + Configurable rapidityCut{"rapidityCut", 1.0f, "rapidity"}; + Configurable v0EtaCut{"v0EtaCut", 0.9f, "eta cut for v0"}; + Configurable daughterEtaCut{"daughterEtaCut", 0.9f, "max eta for daughters"}; // Default is 0.8. Changed to 0.9 to agree with jet selection. TODO: test the impact/biasing of this! + + // Standard 5 topological criteria -- Closed a bit more for the Lambda analysis + Configurable v0cospa{"v0cospa", 0.995, "min V0 CosPA"}; // Default is 0.97 + Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; // Default is 1.0 + // Configurable dcanegtopv{"dcanegtopv", .2, "min DCA Neg To PV (cm)"}; // Default is .05 + // Configurable dcapostopv{"dcapostopv", .05, "min DCA Pos To PV (cm)"}; // Default is .05 + // Renamed for better consistency of candidate selection (the cut is not determined by charge, but by mass and how deflected the daughter is): + Configurable dcaPionToPV{"dcaPionToPV", .2, "min DCA pion-like daughter To PV (cm)"}; // Default is .05. Suppresses pion background. + Configurable dcaProtonToPV{"dcaProtonToPV", .05, "min DCA proton-like daughter To PV (cm)"}; // Default is .05 + Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; // Default is 1.2 + Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + Configurable lambdaLifetimeCut{"lambdaLifetimeCut", 30., "lifetime cut (c*tau) for Lambda (cm)"}; + + // invariant mass selection + Configurable compMassRejection{"compMassRejection", -1, "Competing mass rejection (GeV/#it{c}^{2})"}; // This was creating bumps in the pp analysis code's invariant mass. Turned off for now. + + // Track quality + Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"minITSclusters", 3, "minimum ITS clusters"}; // Default is off + Configurable minTPCrowsOverFindableClusters{"minTPCrowsOverFindableClusters", -1, "minimum nbr of TPC crossed rows over findable clusters"}; + Configurable minTPCfoundOverFindableClusters{"minTPCfoundOverFindableClusters", -1, "minimum nbr of found over findable TPC clusters"}; + Configurable maxFractionTPCSharedClusters{"maxFractionTPCSharedClusters", 1e+09, "maximum fraction of TPC shared clusters"}; + Configurable maxITSchi2PerNcls{"maxITSchi2PerNcls", 36.0f, "maximum ITS chi2 per clusters"}; // Default is 1e+09. New values from StraInJets recommendations + Configurable maxTPCchi2PerNcls{"maxTPCchi2PerNcls", 4.0f, "maximum TPC chi2 per clusters"}; // Default is 1e+09 + Configurable skipTPConly{"skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; + Configurable requirePosITSonly{"requirePosITSonly", false, "require that positive track is ITSonly (overrides TPC quality)"}; + Configurable requireNegITSonly{"requireNegITSonly", false, "require that negative track is ITSonly (overrides TPC quality)"}; + Configurable rejectPosITSafterburner{"rejectPosITSafterburner", false, "reject positive track formed out of afterburner ITS tracks"}; + Configurable rejectNegITSafterburner{"rejectNegITSafterburner", false, "reject negative track formed out of afterburner ITS tracks"}; + Configurable requirePosITSafterburnerOnly{"requirePosITSafterburnerOnly", false, "require positive track formed out of afterburner ITS tracks"}; + Configurable requireNegITSafterburnerOnly{"requireNegITSafterburnerOnly", false, "require negative track formed out of afterburner ITS tracks"}; + Configurable rejectTPCsectorBoundary{"rejectTPCsectorBoundary", false, "reject tracks close to the TPC sector boundaries"}; + Configurable phiLowCut{"phiLowCut", "0.06/x+pi/18.0-0.06", "Low azimuth cut parametrisation"}; + Configurable phiHighCut{"phiHighCut", "0.1/x+pi/18.0+0.06", "High azimuth cut parametrisation"}; + + // PID (TPC/TOF) + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 4, "tpcPidNsigmaCut"}; // Default is 5 + Configurable tofPidNsigmaCutLaPr{"tofPidNsigmaCutLaPr", 1e+6, "tofPidNsigmaCutLaPr"}; + Configurable tofPidNsigmaCutLaPi{"tofPidNsigmaCutLaPi", 1e+6, "tofPidNsigmaCutLaPi"}; + + // PID (TOF) + Configurable maxDeltaTimeProton{"maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimePion{"maxDeltaTimePion", 1e+9, "check maximum allowed time"}; + } v0Selections; + + // Helpers for the "isTrackFarFromTPCBoundary" function: + TF1* fPhiCutLow = new TF1("fPhiCutLow", v0Selections.phiLowCut.value.data(), 0, 100); + TF1* fPhiCutHigh = new TF1("fPhiCutHigh", v0Selections.phiHighCut.value.data(), 0, 100); + + // Run Condition Table (RCT) configurables + struct : ConfigurableGroup { + std::string prefix = "rctConfigurations"; // JSON group name + Configurable cfgRCTLabel{"cfgRCTLabel", "", "Which detector condition requirements? (CBT, CBT_hadronPID, CBT_electronPID, CBT_calo, CBT_muon, CBT_muon_glo)"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "Include ZDC flags in the bit selection (for Pb-Pb only)"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } rctConfigurations; + RCTFlagsChecker rctFlagsChecker{rctConfigurations.cfgRCTLabel.value}; + + // ML SELECTIONS BLOCK -- NOT IMPLEMENTED! (TODO) + + // CCDB options + struct : ConfigurableGroup { + std::string prefix = "ccdbConfigurations"; // JSON group name + 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 mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + + // manual magnetic field: + Configurable useCustomMagField{"useCustomMagField", false, "Use custom magnetic field value"}; + Configurable customMagField{"customMagField", 5.0f, "Manually set magnetic field"}; + } ccdbConfigurations; + + // Instantiating CCDB: + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + + // Other useful variables: + ctpRateFetcher rateFetcher; + int mRunNumber; + float magField; + std::map metadata; + o2::parameters::GRPMagField* grpmag = nullptr; + + // Histogram axes configuration: + struct : ConfigurableGroup { + std::string prefix = "axisConfigurations"; // JSON group name + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisPtXi{"axisPtXi", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for feeddown from Xi"}; + ConfigurableAxis axisPtCoarse{"axisPtCoarse", {VARIABLE_WIDTH, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 7.0f, 10.0f, 15.0f}, "pt axis for QA"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {450, 1.08f, 1.15f}, ""}; // Default is {200, 1.101f, 1.131f} + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}, "Centrality"}; + ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {500, 0, 50}, "Binning for the interaction rate (kHz)"}; + ConfigurableAxis axisMultFT0M{"axisMultFT0M", {500, 0.0f, +100000.0f}, "Multiplicity FT0M"}; + ConfigurableAxis axisMultFT0C{"axisMultFT0C", {500, 0.0f, +10000.0f}, "Multiplicity FT0C"}; + ConfigurableAxis axisMultFV0A{"axisMultFV0A", {500, 0.0f, +100000.0f}, "Multiplicity FV0A"}; + + ConfigurableAxis axisRawCentrality{"axisRawCentrality", {VARIABLE_WIDTH, 0.000f, 52.320f, 75.400f, 95.719f, 115.364f, 135.211f, 155.791f, 177.504f, 200.686f, 225.641f, 252.645f, 281.906f, 313.850f, 348.302f, 385.732f, 426.307f, 470.146f, 517.555f, 568.899f, 624.177f, 684.021f, 748.734f, 818.078f, 892.577f, 973.087f, 1058.789f, 1150.915f, 1249.319f, 1354.279f, 1465.979f, 1584.790f, 1710.778f, 1844.863f, 1985.746f, 2134.643f, 2291.610f, 2456.943f, 2630.653f, 2813.959f, 3006.631f, 3207.229f, 3417.641f, 3637.318f, 3865.785f, 4104.997f, 4354.938f, 4615.786f, 4885.335f, 5166.555f, 5458.021f, 5762.584f, 6077.881f, 6406.834f, 6746.435f, 7097.958f, 7462.579f, 7839.165f, 8231.629f, 8635.640f, 9052.000f, 9484.268f, 9929.111f, 10389.350f, 10862.059f, 11352.185f, 11856.823f, 12380.371f, 12920.401f, 13476.971f, 14053.087f, 14646.190f, 15258.426f, 15890.617f, 16544.433f, 17218.024f, 17913.465f, 18631.374f, 19374.983f, 20136.700f, 20927.783f, 21746.796f, 22590.880f, 23465.734f, 24372.274f, 25314.351f, 26290.488f, 27300.899f, 28347.512f, 29436.133f, 30567.840f, 31746.818f, 32982.664f, 34276.329f, 35624.859f, 37042.588f, 38546.609f, 40139.742f, 41837.980f, 43679.429f, 45892.130f, 400000.000f}, "raw centrality signal"}; // for QA + + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}, "Occupancy"}; + + // topological variable QA axes + ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {20, 0.0f, 1.0f}, "DCA (cm)"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {20, 0.0f, 2.0f}, "DCA (cm)"}; + ConfigurableAxis axisPointingAngle{"axisPointingAngle", {20, 0.0f, 2.0f}, "pointing angle (rad)"}; + ConfigurableAxis axisV0Radius{"axisV0Radius", {20, 0.0f, 60.0f}, "V0 2D radius (cm)"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10.0f, 10.0f}, "N sigma TPC"}; + ConfigurableAxis axisTPCsignal{"axisTPCsignal", {200, 0.0f, 200.0f}, "TPC signal"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {200, -10.0f, 10.0f}, "N sigma TOF"}; + ConfigurableAxis axisTOFdeltaT{"axisTOFdeltaT", {200, -5000.0f, 5000.0f}, "TOF Delta T (ps)"}; + ConfigurableAxis axisPhi{"axisPhi", {50, 0.0f, constants::math::TwoPI}, "Azimuth angle (rad)"}; + ConfigurableAxis axisPhiMod{"axisPhiMod", {100, 0.0f, constants::math::TwoPI / 18}, "Azimuth angle wrt TPC sector (rad.)"}; + ConfigurableAxis axisEta{"axisEta", {50, -1.0f, 1.0f}, "#eta"}; + ConfigurableAxis axisRapidity{"axisRapidity", {50, -1.0f, 1.0f}, "y"}; + ConfigurableAxis axisITSchi2{"axisITSchi2", {100, 0.0f, 100.0f}, "#chi^{2} per ITS clusters"}; + ConfigurableAxis axisTPCchi2{"axisTPCchi2", {100, 0.0f, 100.0f}, "#chi^{2} per TPC clusters"}; + ConfigurableAxis axisTPCrowsOverFindable{"axisTPCrowsOverFindable", {120, 0.0f, 1.2f}, "Fraction of TPC crossed rows over findable clusters"}; + ConfigurableAxis axisTPCfoundOverFindable{"axisTPCfoundOverFindable", {120, 0.0f, 1.2f}, "Fraction of TPC found over findable clusters"}; + ConfigurableAxis axisTPCsharedClusters{"axisTPCsharedClusters", {101, -0.005f, 1.005f}, "Fraction of TPC shared clusters"}; + + // AP plot axes + ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; + ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + + // Track quality axes + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + ConfigurableAxis axisITSclus{"axisITSclus", {7, 0.0f, 7.0f}, "N ITS Clusters"}; + ConfigurableAxis axisITScluMap{"axisITScluMap", {128, -0.5f, 127.5f}, "ITS Cluster map"}; + ConfigurableAxis axisDetMap{"axisDetMap", {16, -0.5f, 15.5f}, "Detector use map"}; + ConfigurableAxis axisITScluMapCoarse{"axisITScluMapCoarse", {16, -3.5f, 12.5f}, "ITS Coarse cluster map"}; + ConfigurableAxis axisDetMapCoarse{"axisDetMapCoarse", {5, -0.5f, 4.5f}, "Detector Coarse user map"}; + + // MC coll assoc QA axis + ConfigurableAxis axisMonteCarloNch{"axisMonteCarloNch", {300, 0.0f, 3000.0f}, "N_{ch} MC"}; + + // Jet QA axes: + ConfigurableAxis JetsPerEvent{"JetsPerEvent", {20, 0, 20}, "Jets per event"}; + + ConfigurableAxis axisLeadingParticlePt{"axisLeadingParticlePt", {200, 0.f, 200.f}, "Leading particle p_{T} (GeV/c)"}; // Simpler version! + ConfigurableAxis axisJetPt{"axisJetPt", {200, 0.f, 200.f}, "Jet p_{t} (GeV)"}; + ConfigurableAxis axisCosTheta{"axisCosTheta", {50, -1.f, 1.f}, "cos(#Delta #theta_{jet})"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {50, -constants::math::PI, constants::math::PI}, "#Delta #phi"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {50, -1.5f, 1.5f}, "#Delta #phi"}; // Calculated as twice the subtraction "eta_max=0.9 - R_min=0.2", with a margin + ConfigurableAxis axisDeltaR{"axisDeltaR", {50, 0, 3.5f}, "#Delta R"}; // From 0 to about the maximum Delta R possible with R = 0.2 + ConfigurableAxis axisEnergy{"axisEnergy", {200, 0.f, 200.f}, "E_{jet} (GeV) (#pi mass hypothesis)"}; // Jet energy is not that well defined here, due to track mass hypothesis being of pions! This is just to include px,py,pz in full! + } axisConfigurations; + + // Jet selection configuration: + // (TODO: create a reasonable track selection for full, photon, and Z-tagged jet tracks, including detector angular acceptance parameters for EMCal) + struct : ConfigurableGroup { + std::string prefix = "jetConfigurations"; // JSON group name + Configurable minJetPt{"minJetPt", 30.0f, "Minimum reconstructed pt of the jet (GeV/c)"}; // Something in between pp and PbPb minima. Change for bkgSubtraction true or false! + Configurable radiusJet{"radiusJet", 0.4f, "Jet resolution parameter (R)"}; // (TODO: check if the JE people don't define this as a rescaled int to not lose precision for stricter selections) + // Notice that the maximum Eta of the jet will then be 0.9 - R to keep the jet contained within the ITS+TPC barrel. + + Configurable jetAlgorithm{"jetAlgorithm", kAntiKt, "jet clustering algorithm. 0 = kT, 1 = C/A, 2 = Anti-kT"}; + Configurable jetRecombScheme{"jetRecombScheme", kEScheme, "Jet recombination scheme: 0: E_scheme, 1: pT-scheme, 2: pt2-scheme, 7: WTA_pt_scheme"}; // See PWGJE/JetFinders/jetFinder.h for more info. + Configurable bkgSubtraction{"bkgSubtraction", kNoSubtraction, "Jet background subtraction: No subtraction (false), Area (true), Constituent (TODO)"}; // Selection bool for background subtraction strategy + Configurable GhostedAreaSpecRapidity{"GhostedAreaSpecRapidity", 1.1, "Max ghost particle rapidity for jet area estimates"}; // At least 1.0 for tracks and jets within the |eta| < 0.9 window of ITS+TPC + // Using an enum for readability: + Configurable jetType{"jetType", kChargedJet, "Jet type: 0: Charged Jet, 1: Full Jet, 2: Photon-tagged, 3: Z-tagged"}; // TODO: implement full, photon and Z jets + // (TODO: check the maximum pT of jets used in my analyses! If it is way too hard, it might not be the best jet to use!) + + // (TODO: Check which of these configurables might be useful for the photon-tagged and regular analyses) + // // Configurables from JE PWG: + // Configurable jetEWSPtMin{"jetEWSPtMin", 0.0, "minimum event-wise subtracted jet pT"}; + // Configurable jetEWSPtMax{"jetEWSPtMax", 1000.0, "maximum event-wise subtracted jet pT"}; + // Configurable jetGhostArea{"jetGhostArea", 0.005, "jet ghost area"}; + // Configurable ghostRepeat{"ghostRepeat", 0, "set to 0 to gain speed if you dont need area calculation"}; + // Configurable DoTriggering{"DoTriggering", false, "used for the charged jet trigger to remove the eta constraint on the jet axis"}; + // Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + // // cluster level configurables + // Configurable clusterDefinitionS{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; + // Configurable clusterEtaMin{"clusterEtaMin", -0.71, "minimum cluster eta"}; // For ECMAL: |eta| < 0.7, phi = 1.40 - 3.26 + // Configurable clusterEtaMax{"clusterEtaMax", 0.71, "maximum cluster eta"}; // For ECMAL: |eta| < 0.7, phi = 1.40 - 3.26 + // Configurable clusterPhiMin{"clusterPhiMin", 1.39, "minimum cluster phi"}; + // Configurable clusterPhiMax{"clusterPhiMax", 3.27, "maximum cluster phi"}; + // Configurable clusterEnergyMin{"clusterEnergyMin", 0.5, "minimum cluster energy in EMCAL (GeV)"}; + // Configurable clusterTimeMin{"clusterTimeMin", -25., "minimum Cluster time (ns)"}; + // Configurable clusterTimeMax{"clusterTimeMax", 25., "maximum Cluster time (ns)"}; + // Configurable clusterRejectExotics{"clusterRejectExotics", true, "Reject exotic clusters"}; + // Configurable hadronicCorrectionType{"hadronicCorrectionType", 0, "0 = no correction, 1 = CorrectedOneTrack1, 2 = CorrectedOneTrack2, 3 = CorrectedAllTracks1, 4 = CorrectedAllTracks2"}; + // Configurable doEMCALEventSelection{"doEMCALEventSelection", true, "apply the selection to the event alias_bit for full and neutral jets"}; + // Configurable doEMCALEventSelectionChargedJets{"doEMCALEventSelectionChargedJets", false, "apply the selection to the event alias_bit for charged jets"}; + + Configurable minLeadParticlePt{"minLeadParticlePt", 2.0f, "Minimum Pt for a lead track to be considered a valid proxy for a jet"}; // For OO, about 2 or 3 should be enough (z~0.3 of jet), and for PbPb maybe 8 GeV + } jetConfigurations; + + // Creating a short map to make sure the proper FastJet enums are used (safeguard against possible updates in FastJet indices): + fastjet::JetAlgorithm mapFJAlgorithm(int algoIdx) + { + switch (algoIdx) { + case 0: + return fastjet::kt_algorithm; + case 1: + return fastjet::cambridge_algorithm; + case 2: + return fastjet::antikt_algorithm; + default: + throw std::invalid_argument("Unknown jet algorithm"); + } + } + fastjet::RecombinationScheme mapFJRecombScheme(int schemeIdx) + { + switch (schemeIdx) { + case 0: + return fastjet::E_scheme; + case 1: + return fastjet::pt_scheme; + case 2: + return fastjet::pt2_scheme; + case 7: + return fastjet::WTA_pt_scheme; + default: + throw std::invalid_argument("Unknown recombination scheme"); + } + } + + // Track analysis parameters -- A specific group that is different from the v0Selections. In jet analyses we need to control our PseudoJet candidates! + // (TODO: include minimal selection criteria for electrons, muons and photons) + // Notice you do NOT need any PID for the PseudoJet candidates! Only need is to know the 4-momentum appropriately. Thus removed nsigma checks on PID + struct : ConfigurableGroup { + std::string prefix = "pseudoJetCandidateTrackSelections"; // JSON group name + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70, "Minimum number of TPC crossed rows"}; + Configurable minITSnCls{"minITSnCls", -1, "Minimum number of ITS clusters"}; + Configurable maxChi2TPC{"maxChi2TPC", 5.0f, "Maximum chi2 per cluster TPC"}; // Loose cuts for pseudojet candidate selection + Configurable maxChi2ITS{"maxChi2ITS", 40.0f, "Maximum chi2 per cluster ITS"}; + Configurable etaCut{"etaCut", 0.9f, "Maximum eta absolute value"}; // (TODO: same test as the previous 0.8 eta cut) + + Configurable minCandidatePt{"minCandidatePt", 0.15f, "Minimum track pt for pseudojet candidate (GeV/c)"}; // Reduces number of pseudojet candidates from IR radiation + // (TODO: test these minimal ratios to suppress split tracks in high occupancy PbPb or OO) + // Configurable minTPCrowsOverFindableClusters{"minTPCrowsOverFindableClusters", -1, "minimum nbr of TPC crossed rows over findable clusters"}; + // Configurable minTPCfoundOverFindableClusters{"minTPCfoundOverFindableClusters", 0.8f, "minimum nbr of found over findable TPC clusters"}; + + // Jets typical cuts (suppress non-primary candidates): + Configurable doDCAcuts{"doDCAcuts", false, "Apply DCA cuts to jet candidates (biases towards primary-vertex/prompt hadron jets)"}; + Configurable maxDCAz{"maxDCAz", 3.2f, "Max DCAz to primary vertex [cm] (remove pileup influence)"}; + + // Configurable maxDCAxy{"maxDCAxy", 2.4f,"Max DCAxy to primary vertex [cm]"}; + // Using same cuts as the StrangenessInJets analysis, with a pt dependence (which may bias high pt, so use with care): + Configurable dcaxyMaxTrackPar0{"dcaxyMaxTrackPar0", 0.0105f, "Asymptotic DCA resolution at high pt [cm]"}; + Configurable dcaxyMaxTrackPar1{"dcaxyMaxTrackPar1", 0.035f, "Low pt multiple-scattering term for DCA resolution [cm*(GeV/c)^Par2]"}; + Configurable dcaxyMaxTrackPar2{"dcaxyMaxTrackPar2", 1.1f, "Exponent of pt dependence of DCA resolution"}; + } pseudoJetCandidateTrackSelections; + + JetBkgSubUtils backgroundSub; + + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL(ccdbConfigurations.ccdbUrl); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + // Initialise the RCTFlagsChecker + rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); + + // Event Counters + histos.add("hEventSelection", "hEventSelection", kTH1D, {{23, -0.5f, +20.5f}}); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } else { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "Above max occup."); + } + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(21, "RCT flags"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(22, "hasRingJet"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(23, "hasRingV0"); + // (notice we lack a hasRingJet AND hasRingV0 bin because the tasks run separately on all events!) + // (this QA number can be obtained at derived data level with ease) + + histos.add("Centrality/hEventCentrality", "hEventCentrality", kTH1D, {{101, 0.0f, 101.0f}}); + histos.add("Centrality/hCentralityVsNch", "hCentralityVsNch", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisNch}); + if (doEventQA) { + histos.add("hEventSelectionVsCentrality", "hEventSelectionVsCentrality", kTH2D, {{23, -0.5f, +20.5f}, {101, 0.0f, 101.0f}}); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } else { + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(17, "Below min occup."); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(18, "Above max occup."); + } + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(19, "Below min IR"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(20, "Above max IR"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(21, "RCT flags"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(22, "hasRingJet"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(23, "hasRingV0"); + + // Centrality: + histos.add("Centrality/hEventCentVsMultFT0M", "hEventCentVsMultFT0M", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisMultFT0M}); + histos.add("Centrality/hEventCentVsMultFT0C", "hEventCentVsMultFT0C", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisMultFT0C}); + histos.add("Centrality/hEventCentVsMultFV0A", "hEventCentVsMultFV0A", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisMultFV0A}); + histos.add("Centrality/hEventMultFT0CvsMultFV0A", "hEventMultFT0CvsMultFV0A", kTH2D, {axisConfigurations.axisMultFT0C, axisConfigurations.axisMultFV0A}); + } + + histos.add("hEventPVz", "hEventPVz", kTH1D, {{100, -20.0f, +20.0f}}); + histos.add("hCentralityVsPVz", "hCentralityVsPVz", kTH2D, {{101, 0.0f, 101.0f}, {100, -20.0f, +20.0f}}); + + // (TODO: add MC centrality vs PVz histos) + + histos.add("hEventOccupancy", "hEventOccupancy", kTH1D, {axisConfigurations.axisOccupancy}); + histos.add("hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisOccupancy}); + histos.add("hInteractionRate", "hInteractionRate", kTH1D, {axisConfigurations.axisIRBinning}); + histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisIRBinning}); + histos.add("hInteractionRateVsOccupancy", "hInteractionRateVsOccupancy", kTH2D, {axisConfigurations.axisIRBinning, axisConfigurations.axisOccupancy}); + + // for QA and test purposes + // auto hRawCentrality = histos.add("Centrality/hRawCentrality", "hRawCentrality", kTH1D, {axisConfigurations.axisRawCentrality}); + + // for (int ii = 1; ii < 101; ii++) { + // float value = 100.5f - static_cast(ii); + // hRawCentrality->SetBinContent(ii, value); + // } + + ////////////////////////////////////////////////////////////// + /// Lambda / AntiLambda V0 selection QA + ////////////////////////////////////////////////////////////// + struct CutLabel { + std::string label; + bool enabled; + }; // A method of hiding labels of selections which were not used! + std::vector v0LambdaSelectionLabels = { + {"All V0 candidates", true}, + {"V0 radius (min)", true}, + {"V0 radius (max)", true}, + {"V0 cosPA", true}, + {"DCA_{V0 daughters}", true}, + {"|y_{#Lambda}|", v0Selections.rapidityCut > 0.f}, + {"K^{0}_{S} mass rejection", v0Selections.compMassRejection >= 0.f}, + {"ITS clusters (pos)", v0Selections.minITSclusters > 0}, + {"ITS #chi^{2}/N_{cls} (pos)", v0Selections.maxITSchi2PerNcls < 1e8}, + {"Reject ITS afterburner (pos)", v0Selections.rejectPosITSafterburner}, + {"Require ITS afterburner (pos)", v0Selections.requirePosITSafterburnerOnly}, + {"ITS clusters (neg)", v0Selections.minITSclusters > 0}, + {"ITS #chi^{2}/N_{cls} (neg)", v0Selections.maxITSchi2PerNcls < 1e8}, + {"Reject ITS afterburner (neg)", v0Selections.rejectNegITSafterburner}, + {"Require ITS afterburner (neg)", v0Selections.requireNegITSafterburnerOnly}, + {"TPC crossed rows (pos)", v0Selections.minTPCrows > 0}, + {"TPC #chi^{2}/N_{cls} (pos)", v0Selections.maxTPCchi2PerNcls < 1e8}, + {"TPC rows / findable (pos)", v0Selections.minTPCrowsOverFindableClusters >= 0}, + {"TPC found / findable (pos)", v0Selections.minTPCfoundOverFindableClusters >= 0}, + {"TPC shared clusters (pos)", v0Selections.maxFractionTPCSharedClusters < 1e8}, + {"TPC sector boundary (pos)", v0Selections.rejectTPCsectorBoundary}, + {"TPC crossed rows (neg)", v0Selections.minTPCrows > 0}, + {"TPC #chi^{2}/N_{cls} (neg)", v0Selections.maxTPCchi2PerNcls < 1e8}, + {"TPC rows / findable (neg)", v0Selections.minTPCrowsOverFindableClusters >= 0}, + {"TPC found / findable (neg)", v0Selections.minTPCfoundOverFindableClusters >= 0}, + {"TPC shared clusters (neg)", v0Selections.maxFractionTPCSharedClusters < 1e8}, + {"TPC sector boundary (neg)", v0Selections.rejectTPCsectorBoundary}, + {"Require ITS-only (pos)", v0Selections.requirePosITSonly}, + {"Require ITS-only (neg)", v0Selections.requireNegITSonly}, + {"Reject TPC-only (pos)", v0Selections.skipTPConly}, + {"Reject TPC-only (neg)", v0Selections.skipTPConly}, + }; // First, the labels that are hypothesis-agnostic + // Adding the Lambda or AntiLambda hypothesis labels as needed: + auto addHypothesis = [&](bool isLambda, bool analysisEnabled) { + if (!analysisEnabled) + return; // i.e., don't add these labels if not analyzing said particle type + std::string p = isLambda ? "#Lambda: " : "#bar{#Lambda}: "; + v0LambdaSelectionLabels.insert(v0LambdaSelectionLabels.end(), {{p + "DCA_{p} to PV", true}, + {p + "DCA_{#pi} to PV", true}, + {p + "TPC PID p", v0Selections.tpcPidNsigmaCut > 0}, + {p + "TPC PID #pi", v0Selections.tpcPidNsigmaCut > 0}, + {p + "TOF #Delta t p", v0Selections.maxDeltaTimeProton < 1e+9}, + {p + "TOF #Delta t #pi", v0Selections.maxDeltaTimePion < 1e+9}, + {p + "TOF PID p", v0Selections.tofPidNsigmaCutLaPr < 1e+6}, + {p + "TOF PID #pi", v0Selections.tofPidNsigmaCutLaPi < 1e+6}, + {p + "c#tau", v0Selections.lambdaLifetimeCut > 0}}); + }; + constexpr bool Lambda = true; // Some constexpr to make it more readable (works at compile level) + constexpr bool AntiLambda = false; // "false" is just a flag for this addHypothesis function! It just means fill "AntiLambda" labels + addHypothesis(Lambda, analyseLambda); + addHypothesis(AntiLambda, analyseAntiLambda); + + auto hSelectionV0s = histos.add("GeneralQA/hSelectionV0s", "V0 #rightarrow #Lambda / #bar{#Lambda} selection flow", kTH1D, + {{static_cast(v0LambdaSelectionLabels.size()), -0.5, static_cast(v0LambdaSelectionLabels.size()) - 0.5}}); + for (size_t i = 0; i < v0LambdaSelectionLabels.size(); ++i) { + auto lbl = v0LambdaSelectionLabels[i].label; + if (!v0LambdaSelectionLabels[i].enabled) + lbl = "#color[16]{(off) " + lbl + "}"; + hSelectionV0s->GetXaxis()->SetBinLabel(i + 1, lbl.c_str()); // First non-underflow bin is bin 1 + } + //////////////////////////////////////////////// + // Jet track candidate selection flow (analogous to hSelectionV0s): + // Each label's "enabled" flag reflects whether the corresponding configurable + // makes that cut active, so disabled stages are shown in grey in the output. + std::vector jetTrackSelectionLabels = { + {"All track candidates", true}, + {"ITS clusters (min)", pseudoJetCandidateTrackSelections.minITSnCls >= 0}, + {"TPC crossed rows (min)", pseudoJetCandidateTrackSelections.minNCrossedRowsTPC > 0}, + {"TPC #chi^{2}/N_{cls} (max)", pseudoJetCandidateTrackSelections.maxChi2TPC < 1.e8f}, + {"ITS #chi^{2}/N_{cls} (max)", pseudoJetCandidateTrackSelections.maxChi2ITS < 1.e8f}, + {"p_{T} min", pseudoJetCandidateTrackSelections.minCandidatePt > 0.f}, + {"|#eta| cut", pseudoJetCandidateTrackSelections.etaCut < 1.5f}, + {"DCA_{z} to PV", pseudoJetCandidateTrackSelections.doDCAcuts.value}, + {"DCA_{xy} to PV (parametric)", pseudoJetCandidateTrackSelections.doDCAcuts.value}, + }; + auto hSelectionJetTracks = histos.add("GeneralQA/hSelectionJetTracks", "Charged pseudojet candidate selection flow", kTH1D, + {{static_cast(jetTrackSelectionLabels.size()), -0.5, static_cast(jetTrackSelectionLabels.size()) - 0.5}}); + for (size_t i = 0; i < jetTrackSelectionLabels.size(); ++i) { + auto lbl = jetTrackSelectionLabels[i].label; + if (!jetTrackSelectionLabels[i].enabled) + lbl = "#color[16]{(off) " + lbl + "}"; + hSelectionJetTracks->GetXaxis()->SetBinLabel(i + 1, lbl.c_str()); + } + //////////////////////////////////////////////// + + // Histograms versus mass: + if (analyseLambda) { + histos.add("Lambda/h2dNbrOfLambdaVsCentrality", "h2dNbrOfLambdaVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("Lambda/h3dMassLambda", "h3dMassLambda", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // Non-UPC info + histos.add("Lambda/h3dMassLambdaHadronic", "h3dMassLambdaHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + if (doTPCQA) { + histos.add("Lambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + } + if (doTOFQA) { + histos.add("Lambda/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + } + // (TODO: add collision association capabilities in MC) + if (doEtaPhiQA) { + histos.add("Lambda/h5dV0PhiVsEta", "h5dV0PhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("Lambda/h5dPosPhiVsEta", "h5dPosPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("Lambda/h5dNegPhiVsEta", "h5dNegPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + } + } + if (analyseAntiLambda) { + histos.add("AntiLambda/h2dNbrOfAntiLambdaVsCentrality", "h2dNbrOfAntiLambdaVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("AntiLambda/h3dMassAntiLambda", "h3dMassAntiLambda", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // Non-UPC info + histos.add("AntiLambda/h3dMassAntiLambdaHadronic", "h3dMassAntiLambdaHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + if (doTPCQA) { + histos.add("AntiLambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + } + if (doTOFQA) { + histos.add("AntiLambda/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + } + if (doEtaPhiQA) { + histos.add("AntiLambda/h5dV0PhiVsEta", "h5dV0PhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("AntiLambda/h5dPosPhiVsEta", "h5dPosPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("AntiLambda/h5dNegPhiVsEta", "h5dNegPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + } + } + + if (analyseLambda) { + histos.add("hMassLambda", "hMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("Lambda/hLambdasPerEvent", "hLambdasPerEvent", kTH1D, {{15, 0, 15}}); + } + if (analyseAntiLambda) { + histos.add("hMassAntiLambda", "hMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("AntiLambda/hAntiLambdasPerEvent", "hAntiLambdasPerEvent", kTH1D, {{15, 0, 15}}); + } + if (analyseLambda && analyseAntiLambda) { + histos.add("hAmbiguousLambdaCandidates", "hAmbiguousLambdaCandidates", kTH1D, {{1, 0, 1}}); + histos.add("hAmbiguousPerEvent", "hAmbiguousPerEvent", kTH1D, {{15, 0, 15}}); + } + + // QA histograms if requested + if (doV0KinematicQA) { + if (analyseLambda) { + // --- Basic kinematics --- + histos.add("V0KinematicQA/Lambda/hPt", "Lambda p_{T}", kTH1D, {axisConfigurations.axisPt}); + histos.add("V0KinematicQA/Lambda/hY", "Lambda rapidity", kTH1D, {axisConfigurations.axisRapidity}); + histos.add("V0KinematicQA/Lambda/hPhi", "Lambda #varphi", kTH1D, {axisConfigurations.axisPhi}); + // --- Mass correlations --- + histos.add("V0KinematicQA/Lambda/hMassVsPt", "Lambda mass vs p_{T}", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("V0KinematicQA/Lambda/hMassVsY", "Lambda mass vs y", kTH2D, {axisConfigurations.axisRapidity, axisConfigurations.axisLambdaMass}); + histos.add("V0KinematicQA/Lambda/hMassVsPhi", "Lambda mass vs #varphi", kTH2D, {axisConfigurations.axisPhi, axisConfigurations.axisLambdaMass}); + // --- Kinematic correlations --- + histos.add("V0KinematicQA/Lambda/hYVsPt", "Lambda y vs p_{T}", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisRapidity}); + histos.add("V0KinematicQA/Lambda/hPhiVsPt", "Lambda #varphi vs p_{T}", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPhi}); + } + if (analyseAntiLambda) { + // --- Basic kinematics --- + histos.add("V0KinematicQA/AntiLambda/hPt", "AntiLambda p_{T}", kTH1D, {axisConfigurations.axisPt}); + histos.add("V0KinematicQA/AntiLambda/hY", "AntiLambda rapidity", kTH1D, {axisConfigurations.axisRapidity}); + histos.add("V0KinematicQA/AntiLambda/hPhi", "AntiLambda #varphi", kTH1D, {axisConfigurations.axisPhi}); + // --- Mass correlations --- + histos.add("V0KinematicQA/AntiLambda/hMassVsPt", "AntiLambda mass vs p_{T}", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("V0KinematicQA/AntiLambda/hMassVsY", "AntiLambda mass vs y", kTH2D, {axisConfigurations.axisRapidity, axisConfigurations.axisLambdaMass}); + histos.add("V0KinematicQA/AntiLambda/hMassVsPhi", "AntiLambda mass vs #varphi", kTH2D, {axisConfigurations.axisPhi, axisConfigurations.axisLambdaMass}); + // --- Kinematic correlations --- + histos.add("V0KinematicQA/AntiLambda/hYVsPt", "AntiLambda y vs p_{T}", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisRapidity}); + histos.add("V0KinematicQA/AntiLambda/hPhiVsPt", "AntiLambda #varphi vs p_{T}", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPhi}); + } + } + + if (doCompleteTopoQA) { + if (analyseLambda) { + histos.add("Lambda/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/h4dDCADaughters", "h4dDCADaughters", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAdau}); + histos.add("Lambda/h4dPointingAngle", "h4dPointingAngle", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPointingAngle}); + histos.add("Lambda/h4dV0Radius", "h4dV0Radius", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisV0Radius}); + } + if (analyseAntiLambda) { + histos.add("AntiLambda/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/h4dDCADaughters", "h4dDCADaughters", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAdau}); + histos.add("AntiLambda/h4dPointingAngle", "h4dPointingAngle", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPointingAngle}); + histos.add("AntiLambda/h4dV0Radius", "h4dV0Radius", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisV0Radius}); + } + + // For all received candidates: + histos.add("V0KinematicQA/hPosDCAToPV", "hPosDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("V0KinematicQA/hNegDCAToPV", "hNegDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("V0KinematicQA/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("V0KinematicQA/hPointingAngle", "hPointingAngle", kTH1D, {axisConfigurations.axisPointingAngle}); + histos.add("V0KinematicQA/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("V0KinematicQA/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("V0KinematicQA/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("V0KinematicQA/h2dPositivePtVsPhi", "h2dPositivePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + histos.add("V0KinematicQA/h2dNegativePtVsPhi", "h2dNegativePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + if (analyseLambda) { + histos.add("Lambda/hPosDCAToPV", "hPosDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/hNegDCAToPV", "hNegDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("Lambda/hPointingAngle", "hPointingAngle", kTH1D, {axisConfigurations.axisPointingAngle}); + histos.add("Lambda/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("Lambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("Lambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("Lambda/h2dPositivePtVsPhi", "h2dPositivePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + histos.add("Lambda/h2dNegativePtVsPhi", "h2dNegativePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + } + if (analyseAntiLambda) { + histos.add("AntiLambda/hPosDCAToPV", "hPosDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/hNegDCAToPV", "hNegDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("AntiLambda/hPointingAngle", "hPointingAngle", kTH1D, {axisConfigurations.axisPointingAngle}); + histos.add("AntiLambda/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("AntiLambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("AntiLambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("AntiLambda/h2dPositivePtVsPhi", "h2dPositivePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + histos.add("AntiLambda/h2dNegativePtVsPhi", "h2dNegativePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + } + } + + // Check ambiguous candidates in AP space: + histos.add("GeneralQA/h2dArmenterosAll", "h2dArmenterosAll", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosKinematicSelected", "h2dArmenterosKinematicSelected", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosFullSelected", "h2dArmenterosFullSelected", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosFullSelectedLambda", "h2dArmenterosFullSelectedLambda", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosFullSelectedAntiLambda", "h2dArmenterosFullSelectedAntiLambda", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosFullSelectedNonAmbiguous", "h2dArmenterosFullSelectedNonAmbiguous", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosFullSelectedAmbiguous", "h2dArmenterosFullSelectedAmbiguous", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + + // Jets histograms: + // Histogram that needs to be present even out of QA: + histos.add("hEventsWithJet", "hEventsWithJet", kTH1D, {{1, 0, 1}}); + histos.add("hJetsPerEvent", "hJetsPerEvent", kTH1D, {axisConfigurations.JetsPerEvent}); + // counter of events with jet (could be interesting to compare with the minimum pT cut or between the background subtraction vs no background subtraction cases) + // number of jets per event + if (doJetKinematicsQA) { + histos.add("JetKinematicsQA/hJetPt", "hJetPt", kTH1D, {axisConfigurations.axisJetPt}); + histos.add("JetKinematicsQA/hJetEta", "hJetEta", kTH1D, {axisConfigurations.axisEta}); + histos.add("JetKinematicsQA/hJetPhi", "hJetPhi", kTH1D, {axisConfigurations.axisPhi}); + + histos.add("JetKinematicsQA/hCosThetaToLeadingJet", "hCosThetaToLeadingJet", kTH1D, {axisConfigurations.axisCosTheta}); + histos.add("JetKinematicsQA/hDeltaPhiToLeadingJet", "hDeltaPhiToLeadingJet", kTH1D, {axisConfigurations.axisDeltaPhi}); + histos.add("JetKinematicsQA/hDeltaEtaToLeadingJet", "hDeltaEtaToLeadingJet", kTH1D, {axisConfigurations.axisDeltaEta}); + histos.add("JetKinematicsQA/hDeltaRToLeadingJet", "hDeltaRToLeadingJet", kTH1D, {axisConfigurations.axisDeltaR}); + + histos.add("JetKinematicsQA/hLeadingJetPt", "hLeadingJetPt", kTH1D, {axisConfigurations.axisJetPt}); + histos.add("JetKinematicsQA/hLeadingJetEta", "hLeadingJetEta", kTH1D, {axisConfigurations.axisEta}); + histos.add("JetKinematicsQA/hLeadingJetPhi", "hLeadingJetPhi", kTH1D, {axisConfigurations.axisPhi}); + + // 2D correlations: + histos.add("JetKinematicsQA/h2dJetsPerEventvsLeadJetPt", "h2dJetsPerEventvsLeadJetPt", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisJetPt}); + histos.add("JetKinematicsQA/h2dJetsPerEventvsJetPt", "h2dJetsPerEventvsJetPt", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisJetPt}); + histos.add("JetKinematicsQA/h2dCosThetaToLeadvsDeltaPhiToLead", "h2dCosThetaToLeadvsDeltaPhiToLead", kTH2D, {axisConfigurations.axisCosTheta, axisConfigurations.axisDeltaPhi}); + histos.add("JetKinematicsQA/h2dCosThetaToLeadvsDeltaEtaToLead", "h2dCosThetaToLeadvsDeltaEtaToLead", kTH2D, {axisConfigurations.axisCosTheta, axisConfigurations.axisDeltaEta}); + histos.add("JetKinematicsQA/h2dCosThetaToLeadvsDeltaRToLead", "h2dCosThetaToLeadvsDeltaRToLead", kTH2D, {axisConfigurations.axisCosTheta, axisConfigurations.axisDeltaR}); + histos.add("JetKinematicsQA/h2dDeltaPhiToLeadvsDeltaEtaToLead", "h2dDeltaPhiToLeadvsDeltaEtaToLead", kTH2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisDeltaEta}); // to see existence of back-to-back jets, and in which window + + // Comparisons to jet energy: + histos.add("JetKinematicsQA/h2dJetPtvsDeltaPhiToLead", "h2dJetPtvsDeltaPhiToLead", kTH2D, {axisConfigurations.axisJetPt, axisConfigurations.axisDeltaPhi}); + histos.add("JetKinematicsQA/h2dJetEnergyvsDeltaPhiToLead", "h2dJetEnergyvsDeltaPhiToLead", kTH2D, {axisConfigurations.axisEnergy, axisConfigurations.axisDeltaPhi}); + histos.add("JetKinematicsQA/h2dJetEnergyvsCosThetaToLead", "h2dJetEnergyvsCosThetaToLead", kTH2D, {axisConfigurations.axisEnergy, axisConfigurations.axisCosTheta}); + + // Jets per event vs correlation to lead jet + histos.add("JetKinematicsQA/h2dJetsPerEventvsDeltaPhiToLead", "h2dJetsPerEventvsDeltaPhiToLead", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisDeltaPhi}); + histos.add("JetKinematicsQA/h2dJetsPerEventvsDeltaEtaToLead", "h2dJetsPerEventvsDeltaEtaToLead", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisDeltaEta}); + histos.add("JetKinematicsQA/h2dJetsPerEventvsCosThetaToLead", "h2dJetsPerEventvsCosThetaToLead", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisCosTheta}); + + //////////////////////////// + // Leading particle 1D QA: + histos.add("JetVsLeadingParticleQA/hLeadingParticlePt", "hLeadingParticlePt", kTH1D, {axisConfigurations.axisLeadingParticlePt}); + histos.add("JetVsLeadingParticleQA/hLeadingParticleEta", "hLeadingParticleEta", kTH1D, {axisConfigurations.axisEta}); + histos.add("JetVsLeadingParticleQA/hLeadingParticlePhi", "hLeadingParticlePhi", kTH1D, {axisConfigurations.axisPhi}); + + // 1D correlations to lead jet: + histos.add("JetVsLeadingParticleQA/hCosThetaLeadParticleToJet", "hCosThetaLeadParticleToJet", kTH1D, {axisConfigurations.axisCosTheta}); + histos.add("JetVsLeadingParticleQA/hDeltaPhiLeadParticleToJet", "hDeltaPhiLeadParticleToJet", kTH1D, {axisConfigurations.axisDeltaPhi}); + histos.add("JetVsLeadingParticleQA/hDeltaEtaToLeadParticleToJet", "hDeltaEtaToLeadParticleToJet", kTH1D, {axisConfigurations.axisDeltaEta}); + + // Leading particle correlations: + histos.add("JetVsLeadingParticleQA/h2dDeltaPhiParticleToLeadvsDeltaEtaParticleToLead", "h2dDeltaPhiParticleToLeadvsDeltaEtaParticleToLead", kTH2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisDeltaEta}); + + // Jets-per-event vs particle-to-lead correlations: + histos.add("JetVsLeadingParticleQA/h2dJetsPerEventvsDeltaPhiParticleToLead", "h2dJetsPerEventvsDeltaPhiParticleToLead", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisDeltaPhi}); + histos.add("JetVsLeadingParticleQA/h2dJetsPerEventvsDeltaEtaParticleToLead", "h2dJetsPerEventvsDeltaEtaParticleToLead", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisDeltaEta}); + histos.add("JetVsLeadingParticleQA/h2dJetsPerEventvsCosThetaParticleToLead", "h2dJetsPerEventvsCosThetaParticleToLead", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisCosTheta}); + + // Main "Leading jet vs leading particle" correlations: + histos.add("JetVsLeadingParticleQA/h2dJetsPerEventvsLeadParticlePt", "h2dJetsPerEventvsLeadParticlePt", kTH2D, {axisConfigurations.JetsPerEvent, axisConfigurations.axisLeadingParticlePt}); + histos.add("JetVsLeadingParticleQA/h2dLeadJetPtvsLeadParticlePt", "h2dLeadJetPtvsLeadParticlePt", kTH2D, {axisConfigurations.axisJetPt, axisConfigurations.axisLeadingParticlePt}); + histos.add("JetVsLeadingParticleQA/h2dLeadJetPtvsCosThetaParticleToLead", "h2dLeadJetPtvsCosThetaParticleToLead", kTH2D, {axisConfigurations.axisJetPt, axisConfigurations.axisCosTheta}); + histos.add("JetVsLeadingParticleQA/h2dLeadParticlePtvsCosThetaParticleToLead", "h2dLeadParticlePtvsCosThetaParticleToLead", kTH2D, {axisConfigurations.axisLeadingParticlePt, axisConfigurations.axisCosTheta}); + histos.add("JetVsLeadingParticleQA/h2dLeadJetPtvsDeltaPhiParticleToLead", "h2dLeadJetPtvsDeltaPhiParticleToLead", kTH2D, {axisConfigurations.axisJetPt, axisConfigurations.axisDeltaPhi}); + histos.add("JetVsLeadingParticleQA/h2dLeadParticlePtvsDeltaPhiParticleToLead", "h2dLeadParticlePtvsDeltaPhiParticleToLead", kTH2D, {axisConfigurations.axisLeadingParticlePt, axisConfigurations.axisDeltaPhi}); + } + + // inspect histogram sizes, please + histos.print(); + } + + template + auto getCentrality(TCollision const& collision) + { + if (centralityEstimatorForQA == kCentFT0M) + return collision.centFT0M(); + else if (centralityEstimatorForQA == kCentFT0C) + return collision.centFT0C(); + else if (centralityEstimatorForQA == kCentFV0A) + return collision.centFV0A(); + return -1.f; + } + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + mRunNumber = bc.runNumber(); + + // Fetching magnetic field as requested + // In case override, don't proceed, please - no CCDB access required + if (ccdbConfigurations.useCustomMagField) { + magField = ccdbConfigurations.customMagField; + } else { + grpmag = ccdb->getForRun(ccdbConfigurations.grpmagPath, mRunNumber); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.grpPath << " of object GRPObject for run " << mRunNumber; + } + // Fetch magnetic field from ccdb for current bc + magField = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for run " << mRunNumber << " with magnetic field of " << magField << " kZG"; + } + } + + // Minimal helper to fill the hSelectionV0s histogram without having to deal with bins by myself + // (CAUTION! If you change selection order, change this too!) + struct V0SelectionFlowCounter { // Using struct to keep internal bin counter over different functions + int binValue = -1; // Starts at x=-1, which will go to bin 0 (underflow) in the definition of hSelectionV0s + // Made it like this because we use ++binValue when filling, so the first filled + // bin will always be x=0 due to operator precedence. + HistogramRegistry* histos = nullptr; // Had to pass the histos group to this struct, as it was not visible to the members of this struct + + void resetForNewV0() { binValue = -1; } + // Advance to targetBinX, filling all intermediate bins. + // Use this for DISABLED cuts within a single hypothesis + // (shows pass-through count as a flat line, making it visually + // clear that the stage was not active). + // (Replaces N dummy fill() calls) + void fillUpTo(int targetBinX) + { + while (binValue < targetBinX) + histos->fill(HIST("GeneralQA/hSelectionV0s"), ++binValue); + } + + void advanceTo(int targetBinX) { binValue = targetBinX - 1; } // next fill() lands at targetBin. Needed to deal with early exits at isLambda vs isAntiLambda checks + void fill() { histos->fill(HIST("GeneralQA/hSelectionV0s"), ++binValue); } // Hardcoded hSelectionV0s histogram, as it will not change. Increments before filling, by default + }; + V0SelectionFlowCounter V0SelCounter{-1, &histos}; // Could initialize with any index (resetForNewV0 is always called for a new V0 anyways) + // Calculating some bins, for convenience: + int nGenericCuts = 31; // x=0 to x=30 + int nHypoCuts = 9; // per hypothesis (x=31..39 for Lambda) + int lambdaHypoEnd = nGenericCuts + nHypoCuts - 1; // x=39 + + // Minimal helper to fill hSelectionJetTracks, mirroring V0SelectionFlowCounter. + // Reset once per track candidate, fill once per passed cut stage. + struct JetTrackSelectionFlowCounter { + int binValue = -1; // Same convention as V0: starts at -1, first fill goes to bin x=0 + HistogramRegistry* histos = nullptr; + void resetForNewTrack() { binValue = -1; } + void fill() { histos->fill(HIST("GeneralQA/hSelectionJetTracks"), ++binValue); } + }; + JetTrackSelectionFlowCounter JetTrackSelCounter{-1, &histos}; + + // Short inlined helper to simplify QA + inline void fillEventSelectionQA(int bin, float centrality) + { + histos.fill(HIST("hEventSelection"), bin); + histos.fill(HIST("hEventSelectionVsCentrality"), bin, centrality); + } + + // Fill reconstructed event centrality information + // Based off fillReconstructedEventProperties, but optimized to avoid re-accessing information already present on isEventAccepted! + template + void fillCentralityProperties(TCollision const& collision, float centrality) + { + // if (qaCentrality) { + // auto hRawCentrality = histos.get(HIST("Centrality/hRawCentrality")); + // centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(doPPAnalysis ? collision.multFT0A() + collision.multFT0C() : collision.multFT0C())); + // } + histos.fill(HIST("Centrality/hEventCentrality"), centrality); + histos.fill(HIST("Centrality/hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + if (doEventQA) { + histos.fill(HIST("Centrality/hEventCentVsMultFT0M"), collision.centFT0M(), collision.multFT0A() + collision.multFT0C()); + histos.fill(HIST("Centrality/hEventCentVsMultFT0C"), collision.centFT0C(), collision.multFT0C()); + histos.fill(HIST("Centrality/hEventCentVsMultFV0A"), collision.centFV0A(), collision.multFV0A()); + histos.fill(HIST("Centrality/hEventMultFT0CvsMultFV0A"), collision.multFT0C(), collision.multFV0A()); + } + return; + } + + ///////////////////////////////////////////// + // Computation helper functions: + double computePhiMod(double phi, int sign) + // Compute phi wrt to a TPC sector + // Calculation taken from CF: https://github.com/AliceO2Group/O2Physics/blob/376392cb87349886a300c75fa2492b50b7f46725/PWGCF/Flow/Tasks/flowAnalysisGF.cxx#L470 + { + if (magField < 0) // for negative polarity field + phi = o2::constants::math::TwoPI - phi; + if (sign < 0) // for negative charge + phi = o2::constants::math::TwoPI - phi; + if (phi < 0) + LOGF(warning, "phi < 0: %g", phi); + + phi += o2::constants::math::PI / 18.0; // to center gap in the middle + return fmod(phi, o2::constants::math::PI / 9.0); + } + + bool isTrackFarFromTPCBoundary(double trackPt, double trackPhi, int sign) + // check whether the track passes close to a TPC sector boundary + { + double phiModn = computePhiMod(trackPhi, sign); + if (phiModn > fPhiCutHigh->Eval(trackPt)) + return true; // keep track + if (phiModn < fPhiCutLow->Eval(trackPt)) + return true; // keep track + + return false; // reject track + } + + inline float cosThetaJets(const fastjet::PseudoJet& a, const fastjet::PseudoJet& b) + { + const double dot = a.px() * b.px() + a.py() * b.py() + a.pz() * b.pz(); + const double magA = std::sqrt(a.px() * a.px() + a.py() * a.py() + a.pz() * a.pz()); + const double magB = std::sqrt(b.px() * b.px() + b.py() * b.py() + b.pz() * b.pz()); + return dot / (magA * magB); + } + + ///////////////////////////////////////////// + // Helper functions for event and candidate selection: + template + bool isEventAccepted(TCollision const& collision, TBC const& bc, float centrality, bool fillHists) + { // check whether the collision passes our collision selections + int selectionIdx = 0; // To loop over QA histograms. First bin is already filled: first call will already increment this index (not actually the bin index, but a value in the X axis). + if (eventSelections.requireSel8 && !collision.sel8()) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + + const float collisionPVz = collision.posZ(); + if (std::abs(collisionPVz) > eventSelections.maxZVtxPosition) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + + if (doPPAnalysis) { // we are in pp + if constexpr (requires { collision.multNTracksPVeta1(); }) { + // Only considers compiling this block when the collision type actually + // has multNTracksPVeta1(). This is done to reduce collision-table + // subscriptions in the jet processing function. + // This is a compile-time check: since the function is templated, it + // is instantiated separately for Jets and V0s, and this block will be + // properly compiled for each use case and table subscription automatically! + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + } + } else { // Performing selections as if in Pb-Pb: + const float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + + // Fetch interaction rate only if required (in order to limit ccdb calls) + const double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3 : -1; + if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(collision)) + return false; + if (fillHists) + fillEventSelectionQA(++selectionIdx, centrality); + + // Filling histograms previously filled in fillReconstructedEventProperties here, to avoid re-accessing data: + if (fillHists) { + histos.fill(HIST("hEventOccupancy"), collisionOccupancy); + histos.fill(HIST("hCentralityVsOccupancy"), centrality, collisionOccupancy); + histos.fill(HIST("hInteractionRate"), interactionRate); + histos.fill(HIST("hCentralityVsInteractionRate"), centrality, interactionRate); + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); + } + } + + if (fillHists) { + histos.fill(HIST("hCentralityVsPVz"), centrality, collisionPVz); + histos.fill(HIST("hEventPVz"), collisionPVz); + } + return true; + } + + template + bool isCandidateForChargedPseudojetAccepted(JetCandidate const& track) + { // (TODO: add an equivalent for photon jets and Z jets, which don't consider charged particles) + // if (track.sign() == 0) return false; // Tracks are always either positive or negative, at least in TPC and ITS, which are the ones used (not looking at photon-jets right now) + // ITS/TPC cuts: + if (pseudoJetCandidateTrackSelections.minITSnCls >= 0) { + if (track.itsNCls() < pseudoJetCandidateTrackSelections.minITSnCls) + return false; + } + JetTrackSelCounter.fill(); // bin: ITS clusters (min) + + if (track.tpcNClsCrossedRows() < pseudoJetCandidateTrackSelections.minNCrossedRowsTPC) + return false; + JetTrackSelCounter.fill(); + + if (track.tpcChi2NCl() > pseudoJetCandidateTrackSelections.maxChi2TPC) + return false; + JetTrackSelCounter.fill(); + if (track.itsChi2NCl() > pseudoJetCandidateTrackSelections.maxChi2ITS) + return false; + JetTrackSelCounter.fill(); + + // Kinematics: + const float pt = track.pt(); + if (pt < pseudoJetCandidateTrackSelections.minCandidatePt) + return false; + JetTrackSelCounter.fill(); + if (std::fabs(track.eta()) > pseudoJetCandidateTrackSelections.etaCut) + return false; + JetTrackSelCounter.fill(); + + // DCA pseudojet candidate selections -- These select primary vertex particles for the jet: + if (pseudoJetCandidateTrackSelections.doDCAcuts) { + // if (std::fabs(track.dcaXY()) > pseudoJetCandidateTrackSelections.maxDCAxy) return false; + if (std::fabs(track.dcaZ()) > pseudoJetCandidateTrackSelections.maxDCAz) + return false; + JetTrackSelCounter.fill(); + // Slightly more physics-motivated cut (parametrizes the DCA resolution as function of pt) + if (std::fabs(track.dcaXY()) > (pseudoJetCandidateTrackSelections.dcaxyMaxTrackPar0 + + pseudoJetCandidateTrackSelections.dcaxyMaxTrackPar1 / std::pow(pt, pseudoJetCandidateTrackSelections.dcaxyMaxTrackPar2))) + return false; + JetTrackSelCounter.fill(); + } else { // Should fill counters an equal number of times to advance indices (future-proofing, but could do it by just advancing indices by hand in JetTrackSelectionFlowCounter) + JetTrackSelCounter.fill(); + JetTrackSelCounter.fill(); + } + return true; + } + + // Lambda selections: + template + bool passesGenericV0Cuts(TV0 const& v0) + { + // Base topological variables (high rejection, low cost checks) + if (v0.v0radius() < v0Selections.v0radius) + return false; + V0SelCounter.fill(); + if (v0.v0radius() > v0Selections.v0radiusMax) + return false; + V0SelCounter.fill(); + if (v0.v0cosPA() < v0Selections.v0cospa) + return false; + V0SelCounter.fill(); + if (v0.dcaV0daughters() > v0Selections.dcav0dau) + return false; + V0SelCounter.fill(); + + // pseudorapidity cuts: + if (std::fabs(v0.yLambda()) > v0Selections.rapidityCut) + return false; + // if (std::fabs(v0.eta()) > v0Selections.v0EtaCut) return false; + V0SelCounter.fill(); + // if (std::fabs(v0.eta()) > v0Selections.daughterEtaCut) return false; // (TODO: properly consider this in daughter selection!) + + // competing mass rejection (if compMassRejection < 0, this cut does nothing) + if (std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0Selections.compMassRejection) + return false; + V0SelCounter.fill(); + + const auto posTrackExtra = v0.template posTrack_as(); // (TODO: is it worth it to cache these transformations outside of the function? They are reused in the Lambda hypothesis checks) + const auto negTrackExtra = v0.template negTrack_as(); + + // ITS quality cuts + bool posIsFromAfterburner = posTrackExtra.isITSAfterburner(); + bool negIsFromAfterburner = negTrackExtra.isITSAfterburner(); + + // check minimum number of ITS clusters + maximum ITS chi2 per clusters + reject or select ITS afterburner tracks if requested + if (posTrackExtra.itsNCls() < v0Selections.minITSclusters) + return false; // check minimum ITS clusters + V0SelCounter.fill(); + if (posTrackExtra.itsChi2NCl() >= v0Selections.maxITSchi2PerNcls) + return false; // check maximum ITS chi2 per clusters + V0SelCounter.fill(); + if (v0Selections.rejectPosITSafterburner && posIsFromAfterburner) + return false; // reject afterburner track or not + V0SelCounter.fill(); + if (v0Selections.requirePosITSafterburnerOnly && !posIsFromAfterburner) + return false; // keep afterburner track or not + V0SelCounter.fill(); + + if (negTrackExtra.itsNCls() < v0Selections.minITSclusters) + return false; // check minimum ITS clusters + V0SelCounter.fill(); + if (negTrackExtra.itsChi2NCl() >= v0Selections.maxITSchi2PerNcls) + return false; // check maximum ITS chi2 per clusters + V0SelCounter.fill(); + if (v0Selections.rejectNegITSafterburner && negIsFromAfterburner) + return false; // reject afterburner track or not + V0SelCounter.fill(); + if (v0Selections.requireNegITSafterburnerOnly && !negIsFromAfterburner) + return false; // keep afterburner track or not + V0SelCounter.fill(); + + // TPC quality cuts + if (posTrackExtra.tpcNClsCrossedRows() < v0Selections.minTPCrows) + return false; // check minimum TPC crossed rows + V0SelCounter.fill(); + if (posTrackExtra.tpcChi2NCl() >= v0Selections.maxTPCchi2PerNcls) + return false; // check maximum TPC chi2 per clusters + V0SelCounter.fill(); + if (posTrackExtra.tpcCrossedRowsOverFindableCls() < v0Selections.minTPCrowsOverFindableClusters) + return false; // check minimum fraction of TPC rows over findable + V0SelCounter.fill(); + if (posTrackExtra.tpcFoundOverFindableCls() < v0Selections.minTPCfoundOverFindableClusters) + return false; // check minimum fraction of found over findable TPC clusters + V0SelCounter.fill(); + if (posTrackExtra.tpcFractionSharedCls() >= v0Selections.maxFractionTPCSharedClusters) + return false; // check the maximum fraction of allowed shared TPC clusters + V0SelCounter.fill(); + if (v0Selections.rejectTPCsectorBoundary && !isTrackFarFromTPCBoundary(v0.positivept(), v0.positivephi(), +1)) + return false; // reject track far from TPC sector boundary or not + V0SelCounter.fill(); + + if (negTrackExtra.tpcNClsCrossedRows() < v0Selections.minTPCrows) + return false; // check minimum TPC crossed rows + V0SelCounter.fill(); + if (negTrackExtra.tpcChi2NCl() >= v0Selections.maxTPCchi2PerNcls) + return false; // check maximum TPC chi2 per clusters + V0SelCounter.fill(); + if (negTrackExtra.tpcCrossedRowsOverFindableCls() < v0Selections.minTPCrowsOverFindableClusters) + return false; // check minimum fraction of TPC rows over findable + V0SelCounter.fill(); + if (negTrackExtra.tpcFoundOverFindableCls() < v0Selections.minTPCfoundOverFindableClusters) + return false; // check minimum fraction of found over findable TPC clusters + V0SelCounter.fill(); + if (negTrackExtra.tpcFractionSharedCls() >= v0Selections.maxFractionTPCSharedClusters) + return false; // check the maximum fraction of allowed shared TPC clusters + V0SelCounter.fill(); + if (v0Selections.rejectTPCsectorBoundary && !isTrackFarFromTPCBoundary(v0.negativept(), v0.negativephi(), -1)) + return false; // reject track far from TPC sector boundary or not + V0SelCounter.fill(); + + // ITS only tag + if (v0Selections.requirePosITSonly && posTrackExtra.tpcNClsCrossedRows() > 1) + return false; + V0SelCounter.fill(); + if (v0Selections.requireNegITSonly && negTrackExtra.tpcNClsCrossedRows() > 1) + return false; + V0SelCounter.fill(); + + // TPC only tag + if (v0Selections.skipTPConly && posTrackExtra.detectorMap() == o2::aod::track::TPC) + return false; + V0SelCounter.fill(); + if (v0Selections.skipTPConly && negTrackExtra.detectorMap() == o2::aod::track::TPC) + return false; + V0SelCounter.fill(); + + return true; + } + + // Tests the hypothesis of the V0 being a Lambda or of it being an antiLambda. + template + bool passesLambdaLambdaBarHypothesis(TV0 const& v0, TCollision const& collision, bool Lambda_hypothesis) + { + // Remaining topological cuts that were charge-dependent: + // (there is no real gain in doing a looser version of these in the passesGenericV0Cuts function. + // The DCA check will be done anyways and is very unexpensive) + // (even though they are high rejection, they demand a Lambda vs AntiLambda hypothesis, so they + // only appear here...) + const float dcaProtonToPV = Lambda_hypothesis ? std::abs(v0.dcapostopv()) : std::abs(v0.dcanegtopv()); + if (dcaProtonToPV < v0Selections.dcaProtonToPV) + return false; + V0SelCounter.fill(); + const float dcaPionToPV = Lambda_hypothesis ? std::abs(v0.dcanegtopv()) : std::abs(v0.dcapostopv()); // Checks Lambda_hypothesis twice, but compiler can handle it cleanly. + if (dcaPionToPV < v0Selections.dcaPionToPV) + return false; + V0SelCounter.fill(); + + const auto posTrackExtra = v0.template posTrack_as(); + const auto negTrackExtra = v0.template negTrack_as(); + + // For the PID cuts to be properly applied while also keeping this function + // general enough for Lambdas and AntiLambdas, we identify the roles of + // proton-like and pion-like for the pos and neg tracks accordingly: + auto const& protonTrack = Lambda_hypothesis ? posTrackExtra : negTrackExtra; + auto const& pionTrack = Lambda_hypothesis ? negTrackExtra : posTrackExtra; + + ///// Expensive PID checks come last: + // TPC PID + if (std::fabs(protonTrack.tpcNSigmaPr()) > v0Selections.tpcPidNsigmaCut) + return false; + V0SelCounter.fill(); + if (std::fabs(pionTrack.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) + return false; + V0SelCounter.fill(); + + // Only do TOF checks when actually using TOF subscriptions: + // if (doprocessDataWithTOF) { + if constexpr (requires { v0.tofNSigmaLaPr(); }) { // Compile-time check is better in hot-loop + // TOF PID in DeltaT (if TOF is not available, then uses the track. If is available, uses it. In this sense, TOF is optional) + // const bool posHasTOF = posTrackExtra.hasTOF(); // For the older version, which worked only for Lambdas + const bool protonHasTOF = protonTrack.hasTOF(); // Should work even without PIDResponseTOF.h, as it is a TracksExtra property + const bool pionHasTOF = pionTrack.hasTOF(); + + // Proton-like track + if (protonHasTOF && std::abs(Lambda_hypothesis ? v0.posTOFDeltaTLaPr() : v0.negTOFDeltaTLaPr()) > v0Selections.maxDeltaTimeProton) + return false; + V0SelCounter.fill(); + // Pion-like track + if (pionHasTOF && std::abs(Lambda_hypothesis ? v0.negTOFDeltaTLaPi() : v0.posTOFDeltaTLaPi()) > v0Selections.maxDeltaTimePion) + return false; + V0SelCounter.fill(); + + // TOF PID in NSigma (TODO: add asymmetric NSigma windows for purity tuning?) + // Proton-like track (notice usage of tofNSigmaLaPr vs tofNSigmaALaPr) + if (protonHasTOF && std::fabs(Lambda_hypothesis ? v0.tofNSigmaLaPr() : v0.tofNSigmaALaPr()) > v0Selections.tofPidNsigmaCutLaPr) + return false; // (No need to select which candidate is which with the Lambda_hypothesis. Automatically done already!) + V0SelCounter.fill(); + // Pion-like track + if (pionHasTOF && std::fabs(Lambda_hypothesis ? v0.tofNSigmaLaPi() : v0.tofNSigmaALaPi()) > v0Selections.tofPidNsigmaCutLaPi) + return false; + V0SelCounter.fill(); + + // (CAUTION!) You cannot use the getter for raw data's PIDResponseTOF.h instead of LFStrangenessPIDTables.h (as below) + // If you do use, TOF will just try to identify that track as a proton from the PV, instead of using the correct path + // length from the V0s PV-DCA and the such! In other words, it is a naive estimator of TOF PID, because it does not + // correct for the V0 mother's travel time and considers all tracks as if they came from the PV! + // if (protonHasTOF && std::fabs(protonTrack.tofNSigmaPr()) > v0Selections.tofPidNsigmaCutLaPr) return false; + // To properly use the LFStrangenessPIDTables version, you need to call o2-analysis-lf-strangenesstofpid too. + } else { // Should fill counters an equal number of times to advance indices + V0SelCounter.fillUpTo(V0SelCounter.binValue + 4); // Fills the 4 times "V0SelCounter.fill()" would be called + } + + // proper lifetime + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 > v0Selections.lambdaLifetimeCut) + return false; + V0SelCounter.fill(); + + return true; + } + + // Function to help distinguish ambiguous candidates (via Armenteros) that pass both + // the Lambda_hypothesis true (i.e., a Lambda) or false (i.e., an AntiLambda) checks + // (This function is only called in about 1-3% of the Lambda-Like V0s which remain ambiguous after all other cuts) + // int isCandidateArmenterosLambda(const float alpha, const float qt){ + // // Remove K0s band + // if (std::abs(alpha) < v0Selections.armK0AlphaThreshold && qt < v0Selections.armK0QtThreshold) return kIsArmenterosK0; + // // std::abs(alpha) < 0.2 && qt < 0.1 + // if (std::abs(alpha) < v0Selections.armMinAlpha) return kArmenterosAmbiguous; + // // std::abs(alpha) < 0.01f + // // Lambda selection + // if (alpha > 0) return kIsArmenterosLambda; + // else return kIsArmenterosAntiLambda; + // } + + // TODO: another possible check that could be done (if not implemented already inside mLambda() getters) + // template + // int isCandidateMassLambda(TV0 const& v0) { + // float m1 = v0.mLambda(); // proton=positive + // float m2 = v0.mAntiLambda(); // proton=negative + // float d = std::abs(m1 - mLambdaTrue) - std::abs(m2 - mLambdaTrue); + // if (d < 0.f) return +1; // Lambda + // else return -1; // AntiLambda + // } + + template + void jetsProcess(TJetTracks const& tracks, const int ringCollIdx, const float centrality) + { + // Loop over reconstructed tracks: + std::vector fjParticles; + int leadingParticleIdx = -1; // Initialized as -1, but could leave it unitialized as well. We reject any invalid events where this could pose a problem (e.g., pT<=0) + float leadingParticlePt = 0; + for (auto const& track : tracks) { + JetTrackSelCounter.resetForNewTrack(); // reset bin counter for this candidate + JetTrackSelCounter.fill(); // bin: "All track candidates" + + // Require that tracks pass selection criteria + if (!isCandidateForChargedPseudojetAccepted(track)) + continue; + + // Constructing pseudojet candidates vector: + // Using pion mass as hypothesis for track energy estimate (before PID, all particles treated as if with the same invariant mass) + // (TODO: study the possibility of using identified PseudoJet candidates for this estimate) + fastjet::PseudoJet candidate(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(candidate); + + // Calculating leading particle + float pt = candidate.pt(); + if (pt > leadingParticlePt) { + leadingParticlePt = pt; + leadingParticleIdx = fjParticles.size() - 1; + } + } + // Reject empty events + if (fjParticles.size() < 1) + return; + + int lastBinEvSel = histos.get(HIST("hEventSelection"))->GetXaxis()->GetNbins(); + + auto const& leadingParticle = fjParticles[leadingParticleIdx]; + if (leadingParticle.pt() > jetConfigurations.minLeadParticlePt) { // If not, leading particle is probably a bad proxy + tableLeadParticles(ringCollIdx, leadingParticle.pt(), leadingParticle.eta(), leadingParticle.phi()); + } + + // Start jet clusterization: + // Cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(mapFJAlgorithm(jetConfigurations.jetAlgorithm), jetConfigurations.radiusJet, mapFJRecombScheme(jetConfigurations.jetRecombScheme)); + if (jetConfigurations.bkgSubtraction == kAreaBased) { + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(jetConfigurations.GhostedAreaSpecRapidity)); + fastjet::ClusterSequenceArea clustSeq(fjParticles, jetDef, areaDef); // Attributes an area for each pseudojet in the list + std::vector jets = fastjet::sorted_by_pt(clustSeq.inclusive_jets()); // No minimum pt before background subtraction + if (jets.empty()) + return; + // Perpendicular cone area subtraction, not the traditional subtraction (TODO: include an option for traditional area subtraction) + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], jetConfigurations.radiusJet); // This uses a geometric, pi*R^2 area, not exactly a ghost-based area! + + // Loop over clustered jets: + int selectedJets = 0; + + fastjet::PseudoJet leadingJetSub; + float leadingJetPt = -1.f; + for (const auto& jet : jets) { + // Jet must be fully contained in the acceptance (0.9 for ITS+TPC barrel) + const float jet_eta = jet.eta(); + if (std::fabs(jet_eta) > (0.9f - jetConfigurations.radiusJet)) + continue; + + auto jetForSub = jet; + // Subtracts same background estimated for highest pt jet, but every jet might have a slightly different area + // (TODO: check possible problems with OO and physics impacts of this particular cone method and choice of single background estimator based on leading jet) + // (TODO: improve for Pb-Pb, specially central!) + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + // Jet pt must be larger than threshold: + if (jetMinusBkg.pt() < jetConfigurations.minJetPt) + continue; + selectedJets++; + + // Store jet: + tableJets(ringCollIdx, + jetMinusBkg.pt(), + jetMinusBkg.eta(), // Using eta instead of rapidity + jetMinusBkg.phi(), + jetMinusBkg.constituents().size()); + + // Finding the leading jet after subtraction (leading jet is NOT known a priori!): + if (jetMinusBkg.pt() > leadingJetPt) { + leadingJetPt = jetMinusBkg.pt(); + leadingJetSub = jetMinusBkg; + } + } + histos.fill(HIST("hJetsPerEvent"), selectedJets); + if (selectedJets == 0) + return; + histos.fill(HIST("hEventsWithJet"), 0.5); + // Another version of this counter, which is already integrated in the Event Selection flow: + if (doEventQA) + fillEventSelectionQA(lastBinEvSel - 1, centrality); // hasRingJet passes + + if (doJetKinematicsQA) { + histos.fill(HIST("JetKinematicsQA/hLeadingJetPt"), leadingJetSub.pt()); + histos.fill(HIST("JetKinematicsQA/hLeadingJetEta"), leadingJetSub.eta()); + histos.fill(HIST("JetKinematicsQA/hLeadingJetPhi"), leadingJetSub.phi()); + + // Now looping through jets again to calculate the correlations: + for (const auto& jet : jets) { + // Will recalculated background subtraction during QA to avoid storing jets in memory when running in non-QA cases: + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + + if (jetMinusBkg.pt() < jetConfigurations.minJetPt) + continue; + + float cosTheta = cosThetaJets(leadingJetSub, jetMinusBkg); + float deltaPhi = RecoDecay::constrainAngle(leadingJetSub.phi() - jetMinusBkg.phi(), -o2::constants::math::PI); + float deltaEta = leadingJetSub.eta() - jetMinusBkg.eta(); + float deltaR = std::sqrt(deltaPhi * deltaPhi + deltaEta * deltaEta); + + histos.fill(HIST("JetKinematicsQA/hCosThetaToLeadingJet"), cosTheta); + histos.fill(HIST("JetKinematicsQA/hDeltaPhiToLeadingJet"), deltaPhi); + histos.fill(HIST("JetKinematicsQA/hDeltaEtaToLeadingJet"), deltaEta); + histos.fill(HIST("JetKinematicsQA/hDeltaRToLeadingJet"), deltaR); + + // 2D correlations: + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsLeadJetPt"), selectedJets, leadingJetSub.pt()); + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsJetPt"), selectedJets, jetMinusBkg.pt()); + histos.fill(HIST("JetKinematicsQA/h2dCosThetaToLeadvsDeltaPhiToLead"), cosTheta, deltaPhi); + histos.fill(HIST("JetKinematicsQA/h2dCosThetaToLeadvsDeltaEtaToLead"), cosTheta, deltaEta); + histos.fill(HIST("JetKinematicsQA/h2dCosThetaToLeadvsDeltaRToLead"), cosTheta, deltaR); + histos.fill(HIST("JetKinematicsQA/h2dDeltaPhiToLeadvsDeltaEtaToLead"), deltaPhi, deltaEta); + + histos.fill(HIST("JetKinematicsQA/h2dJetPtvsDeltaPhiToLead"), jetMinusBkg.pt(), deltaPhi); // Can't really get the energy of the jet, just the pt to make this comparison + histos.fill(HIST("JetKinematicsQA/h2dJetEnergyvsDeltaPhiToLead"), jetMinusBkg.E(), deltaPhi); // Just a different scale + histos.fill(HIST("JetKinematicsQA/h2dJetEnergyvsCosThetaToLead"), jetMinusBkg.E(), cosTheta); + + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsDeltaPhiToLead"), selectedJets, deltaPhi); + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsDeltaEtaToLead"), selectedJets, deltaEta); + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsCosThetaToLead"), selectedJets, cosTheta); + } + // Leading particle comparisons: + histos.fill(HIST("JetVsLeadingParticleQA/hLeadingParticlePt"), leadingParticle.pt()); + histos.fill(HIST("JetVsLeadingParticleQA/hLeadingParticleEta"), leadingParticle.eta()); + histos.fill(HIST("JetVsLeadingParticleQA/hLeadingParticlePhi"), leadingParticle.phi()); + + float deltaPhiParticleToJet = RecoDecay::constrainAngle(leadingJetSub.phi() - leadingParticle.phi(), -o2::constants::math::PI); + float deltaEtaParticleToJet = leadingJetSub.eta() - leadingParticle.eta(); + float cosThetaParticleToJet = cosThetaJets(leadingJetSub, leadingParticle); // Takes advantage of the fact that this leading particle is a PseudoJet object + + histos.fill(HIST("JetVsLeadingParticleQA/hCosThetaLeadParticleToJet"), cosThetaParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/hDeltaPhiLeadParticleToJet"), deltaPhiParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/hDeltaEtaToLeadParticleToJet"), deltaEtaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dDeltaPhiParticleToLeadvsDeltaEtaParticleToLead"), deltaPhiParticleToJet, deltaEtaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsDeltaPhiParticleToLead"), selectedJets, deltaPhiParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsDeltaEtaParticleToLead"), selectedJets, deltaEtaParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsCosThetaParticleToLead"), selectedJets, cosThetaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsLeadParticlePt"), selectedJets, leadingParticle.pt()); + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadJetPtvsLeadParticlePt"), leadingJetSub.pt(), leadingParticle.pt()); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadJetPtvsCosThetaParticleToLead"), leadingJetSub.pt(), cosThetaParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadParticlePtvsCosThetaParticleToLead"), leadingParticle.pt(), cosThetaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadJetPtvsDeltaPhiParticleToLead"), leadingJetSub.pt(), deltaPhiParticleToJet); // To see if there is any backgound in phi due to soft jets (or soft particles below) + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadParticlePtvsDeltaPhiParticleToLead"), leadingParticle.pt(), deltaPhiParticleToJet); + } + } else { // Otherwise, simple jet clustering (TODO: this is the fall back for kConstituentBased while not implemented) + fastjet::ClusterSequence clustSeq(fjParticles, jetDef); + // Jet pt must be larger than threshold: + std::vector jets = fastjet::sorted_by_pt(clustSeq.inclusive_jets(jetConfigurations.minJetPt)); + + const int jetsInEvent = jets.size(); + histos.fill(HIST("hJetsPerEvent"), jetsInEvent); // Fills even in empty events, as this is a useful number to know! + + if (jetsInEvent == 0) + return; + histos.fill(HIST("hEventsWithJet"), 0.5); + // Another version of this counter, which is already integrated in the Event Selection flow: + if (doEventQA) + fillEventSelectionQA(lastBinEvSel - 1, centrality); // hasRingJet passes + + const auto& leadingJet = jets[0]; + for (const auto& jet : jets) { + // Jet must be fully contained in the acceptance (0.9 for ITS+TPC barrel) + const float jet_eta = jet.eta(); + if (std::fabs(jet_eta) > (0.9f - jetConfigurations.radiusJet)) + continue; + + tableJets(ringCollIdx, + jet.pt(), + jet_eta, // Using eta instead of rapidity + jet.phi(), + jet.constituents().size()); + + if (doJetKinematicsQA) { + histos.fill(HIST("JetKinematicsQA/hJetPt"), jet.pt()); + histos.fill(HIST("JetKinematicsQA/hJetEta"), jet_eta); + histos.fill(HIST("JetKinematicsQA/hJetPhi"), jet.phi()); + + // Calculate angle to leading jet: + float cosTheta = cosThetaJets(leadingJet, jet); + + // Calculate angular separation in projected angles: + float deltaPhi = RecoDecay::constrainAngle(leadingJet.phi() - jet.phi(), -o2::constants::math::PI); + float deltaEta = leadingJet.eta() - jet_eta; + float deltaR = std::sqrt(deltaPhi * deltaPhi + deltaEta * deltaEta); // 2D angular distance in the eta-phi plane + + histos.fill(HIST("JetKinematicsQA/hCosThetaToLeadingJet"), cosTheta); // Measuring the cosine, not angle, because it is faster! + histos.fill(HIST("JetKinematicsQA/hDeltaPhiToLeadingJet"), deltaPhi); + histos.fill(HIST("JetKinematicsQA/hDeltaEtaToLeadingJet"), deltaEta); + histos.fill(HIST("JetKinematicsQA/hDeltaRToLeadingJet"), deltaR); + + // 2D correlations: + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsLeadJetPt"), jetsInEvent, leadingJet.pt()); + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsJetPt"), jetsInEvent, jet.pt()); + histos.fill(HIST("JetKinematicsQA/h2dCosThetaToLeadvsDeltaPhiToLead"), cosTheta, deltaPhi); + histos.fill(HIST("JetKinematicsQA/h2dCosThetaToLeadvsDeltaEtaToLead"), cosTheta, deltaEta); + histos.fill(HIST("JetKinematicsQA/h2dCosThetaToLeadvsDeltaRToLead"), cosTheta, deltaR); + histos.fill(HIST("JetKinematicsQA/h2dDeltaPhiToLeadvsDeltaEtaToLead"), deltaPhi, deltaEta); + + histos.fill(HIST("JetKinematicsQA/h2dJetPtvsDeltaPhiToLead"), jet.pt(), deltaPhi); // Can't really get the energy of the jet, just the pt to make this comparison + histos.fill(HIST("JetKinematicsQA/h2dJetEnergyvsDeltaPhiToLead"), jet.E(), deltaPhi); // Just a different scale + histos.fill(HIST("JetKinematicsQA/h2dJetEnergyvsCosThetaToLead"), jet.E(), cosTheta); + + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsDeltaPhiToLead"), jetsInEvent, deltaPhi); + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsDeltaEtaToLead"), jetsInEvent, deltaEta); + histos.fill(HIST("JetKinematicsQA/h2dJetsPerEventvsCosThetaToLead"), jetsInEvent, cosTheta); + } + } + if (doJetKinematicsQA) { + histos.fill(HIST("JetKinematicsQA/hLeadingJetPt"), leadingJet.pt()); + histos.fill(HIST("JetKinematicsQA/hLeadingJetEta"), leadingJet.eta()); + histos.fill(HIST("JetKinematicsQA/hLeadingJetPhi"), leadingJet.phi()); + + // Leading particle comparisons: + histos.fill(HIST("JetVsLeadingParticleQA/hLeadingParticlePt"), leadingParticle.pt()); + histos.fill(HIST("JetVsLeadingParticleQA/hLeadingParticleEta"), leadingParticle.eta()); + histos.fill(HIST("JetVsLeadingParticleQA/hLeadingParticlePhi"), leadingParticle.phi()); + + double deltaPhiParticleToJet = RecoDecay::constrainAngle(leadingJet.phi() - leadingParticle.phi(), -o2::constants::math::PI); + double deltaEtaParticleToJet = leadingJet.eta() - leadingParticle.eta(); + double cosThetaParticleToJet = cosThetaJets(leadingJet, leadingParticle); // Takes advantage of the fact that this leading particle is a PseudoJet object + + histos.fill(HIST("JetVsLeadingParticleQA/hCosThetaLeadParticleToJet"), cosThetaParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/hDeltaPhiLeadParticleToJet"), deltaPhiParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/hDeltaEtaToLeadParticleToJet"), deltaEtaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dDeltaPhiParticleToLeadvsDeltaEtaParticleToLead"), deltaPhiParticleToJet, deltaEtaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsDeltaPhiParticleToLead"), jetsInEvent, deltaPhiParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsDeltaEtaParticleToLead"), jetsInEvent, deltaEtaParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsCosThetaParticleToLead"), jetsInEvent, cosThetaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dJetsPerEventvsLeadParticlePt"), jetsInEvent, leadingParticle.pt()); + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadJetPtvsLeadParticlePt"), leadingJet.pt(), leadingParticle.pt()); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadJetPtvsCosThetaParticleToLead"), leadingJet.pt(), cosThetaParticleToJet); + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadParticlePtvsCosThetaParticleToLead"), leadingParticle.pt(), cosThetaParticleToJet); + + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadJetPtvsDeltaPhiParticleToLead"), leadingJet.pt(), deltaPhiParticleToJet); // To see if there is any backgound in phi due to soft jets (or soft particles below) + histos.fill(HIST("JetVsLeadingParticleQA/h2dLeadParticlePtvsDeltaPhiParticleToLead"), leadingParticle.pt(), deltaPhiParticleToJet); + } + } + } + + // No longer use a separate JetTracks joined table -- it was mostly a subset of DauTracks + TracksIU (which was not used) + template + void dataProcess(TCollision const& collision, TV0Candidates const& V0s, TDaughterTracks const& V0DauTracks, aod::BCsWithTimestamps const& bcs) + { + float centrality = getCentrality(collision); // Strictly for QA. We save other types of centrality estimators in the derived data! + + // For event QA the last two indices never change for NEv_withJets and NEv_withV0s + // (Not the best way to initialize this: runs once per collision! TODO: think of a better way to do it) + int lastBinEvSel = histos.get(HIST("hEventSelection"))->GetXaxis()->GetNbins(); + bool validV0AlreadyFound = false; + + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + histos.fill(HIST("hEventSelectionVsCentrality"), 0. /* all collisions */, centrality); + + auto bc = bcs.iteratorAt(collision.bcId()); + if (!isEventAccepted(collision, bc, centrality, doEventQA)) + return; // Uses return instead of continue, as there is no explicit loop here + + if (doEventQA) + fillCentralityProperties(collision, centrality); + if (v0Selections.rejectTPCsectorBoundary) + initCCDB(bc); // Substituted call from collision to bc for raw data + + // Fill event table: + tableCollisions(collision.centFT0M(), + collision.centFT0C(), + collision.centFV0A()); // (TODO: add InteractionRate info and other useful cuts for later on in the analysis?) + + // Get the derived collision row index for this event: + const int ringCollIdx = tableCollisions.lastIndex(); + + // Call to jets process: + jetsProcess(V0DauTracks, ringCollIdx, centrality); // V0DauTracks takes the place of jetTracks now + + uint NLambdas = 0; // Counting particles per event + uint NAntiLambdas = 0; + uint NAmbiguous = 0; + for (auto const& v0 : V0s) { + V0SelCounter.resetForNewV0(); + V0SelCounter.fill(); // Fill for all v0 candidates + if (doArmenterosQA) + histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.alpha(), v0.qtarm()); // fill AP plot for all V0s + if (!passesGenericV0Cuts(v0)) + continue; + + if (doArmenterosQA) + histos.fill(HIST("GeneralQA/h2dArmenterosKinematicSelected"), v0.alpha(), v0.qtarm()); + + // Else, just continue the loop: + bool isLambda = false; + bool isAntiLambda = false; + if (analyseLambda) + isLambda = passesLambdaLambdaBarHypothesis(v0, collision, true); + if (analyseAntiLambda) { + if (analyseLambda) // We only need to advance when the Lambda hypothesis had an early exit on the counters + V0SelCounter.advanceTo(lambdaHypoEnd + 1); // sync to bin 41 (x=40 means bin 41, the first #bar{#Lambda} bin) + isAntiLambda = passesLambdaLambdaBarHypothesis(v0, collision, false); + } + + if (!isLambda && !isAntiLambda) + continue; // Candidate is not considered to be a Lambda-like + + if (isLambda) + NLambdas++; + if (isAntiLambda) + NAntiLambdas++; + + if (doArmenterosQA) + histos.fill(HIST("GeneralQA/h2dArmenterosFullSelected"), v0.alpha(), v0.qtarm()); // cross-check + if (isLambda && !isAntiLambda) + histos.fill(HIST("GeneralQA/h2dArmenterosFullSelectedLambda"), v0.alpha(), v0.qtarm()); + if (!isLambda && isAntiLambda) + histos.fill(HIST("GeneralQA/h2dArmenterosFullSelectedAntiLambda"), v0.alpha(), v0.qtarm()); + + // XOR check: + if (isLambda ^ isAntiLambda) + histos.fill(HIST("GeneralQA/h2dArmenterosFullSelectedNonAmbiguous"), v0.alpha(), v0.qtarm()); + + // int lambdaIdx = -1; // No need to pass armenteros + if (isLambda && isAntiLambda) { + NAmbiguous++; + histos.fill(HIST("hAmbiguousLambdaCandidates"), 0); + if (doArmenterosQA) + histos.fill(HIST("GeneralQA/h2dArmenterosFullSelectedAmbiguous"), v0.alpha(), v0.qtarm()); // To know the discerning power of Armenteros in an Ambiguous Lambda vs AntiLambda case + + // Armenteros cut is not worth it! From QA histograms, only about 0.05% of ambiguous candidates are in the regions probable to be Lamda/AntiLambdas! + // The statistics gain is not worth it. + // // Third and final check to distinguish between Lambda and AntiLambda ambiguous v0s: + // // (This check is only performed to recycle AMBIGUOUS candidates! Not a hard cut on all candidates!) + // lambdaIdx = isCandidateArmenterosLambda(v0.alpha(), v0.qtarm()); + } + // if (lambdaIdx == kIsArmenterosK0) continue; // Should just skip this step then! + + if (doEventQA) + fillEventSelectionQA(lastBinEvSel, centrality); // hasRingV0 passes + + // // Extra competing mass rejection of Lambdas // (TODO: test competing mass cuts) + // v0.mLambda() + + // Saving the Lambdas into a derived data column: + auto const v0pt = v0.pt(); + const auto posTrackExtra = v0.template posTrack_as(); + const auto negTrackExtra = v0.template negTrack_as(); + tableV0s(ringCollIdx, + v0pt, v0.eta(), v0.phi(), // Using eta instead of rapidity + isLambda, isAntiLambda, + v0.mLambda(), v0.mAntiLambda(), + v0.positivept(), v0.positiveeta(), v0.positivephi(), + v0.negativept(), v0.negativeeta(), v0.negativephi(), + posTrackExtra.tpcNSigmaPr(), posTrackExtra.tpcNSigmaPi(), + negTrackExtra.tpcNSigmaPr(), negTrackExtra.tpcNSigmaPi(), + v0.v0cosPA(), v0.v0radius(), v0.dcaV0daughters(), v0.dcapostopv(), v0.dcanegtopv()); + if (doEventQA && !validV0AlreadyFound) + fillEventSelectionQA(lastBinEvSel, centrality); // hasRingV0 passes + validV0AlreadyFound = true; + + if (doV0KinematicQA) { + // Cache kinematics once + const float v0y = v0.yLambda(); + const float v0phi = v0.phi(); + const float mLambda = v0.mLambda(); + const float mAntiLambda = v0.mAntiLambda(); + if (analyseLambda && isLambda) { + // --- Basic kinematics --- + histos.fill(HIST("V0KinematicQA/Lambda/hPt"), v0pt); + histos.fill(HIST("V0KinematicQA/Lambda/hY"), v0y); + histos.fill(HIST("V0KinematicQA/Lambda/hPhi"), v0phi); + // --- Mass correlations --- + histos.fill(HIST("V0KinematicQA/Lambda/hMassVsPt"), v0pt, mLambda); + histos.fill(HIST("V0KinematicQA/Lambda/hMassVsY"), v0y, mLambda); + histos.fill(HIST("V0KinematicQA/Lambda/hMassVsPhi"), v0phi, mLambda); + // --- Kinematic correlations --- + histos.fill(HIST("V0KinematicQA/Lambda/hYVsPt"), v0pt, v0y); + histos.fill(HIST("V0KinematicQA/Lambda/hPhiVsPt"), v0pt, v0phi); + } + if (analyseAntiLambda && isAntiLambda) { + // --- Basic kinematics --- + histos.fill(HIST("V0KinematicQA/AntiLambda/hPt"), v0pt); + histos.fill(HIST("V0KinematicQA/AntiLambda/hY"), v0y); + histos.fill(HIST("V0KinematicQA/AntiLambda/hPhi"), v0phi); + // --- Mass correlations --- + histos.fill(HIST("V0KinematicQA/AntiLambda/hMassVsPt"), v0pt, mAntiLambda); + histos.fill(HIST("V0KinematicQA/AntiLambda/hMassVsY"), v0y, mAntiLambda); + histos.fill(HIST("V0KinematicQA/AntiLambda/hMassVsPhi"), v0phi, mAntiLambda); + // --- Kinematic correlations --- + histos.fill(HIST("V0KinematicQA/AntiLambda/hYVsPt"), v0pt, v0y); + histos.fill(HIST("V0KinematicQA/AntiLambda/hPhiVsPt"), v0pt, v0phi); + } + } + + if (doCompleteTopoQA) { + // Remaking these variables outside of the passesLambdaLambdaBarHypothesis. Loses performance, but that should be OK for QA + histos.fill(HIST("V0KinematicQA/hPosDCAToPV"), v0.dcapostopv()); + histos.fill(HIST("V0KinematicQA/hNegDCAToPV"), v0.dcanegtopv()); + histos.fill(HIST("V0KinematicQA/hDCADaughters"), v0.dcaV0daughters()); + histos.fill(HIST("V0KinematicQA/hPointingAngle"), std::acos(v0.v0cosPA())); + histos.fill(HIST("V0KinematicQA/hV0Radius"), v0.v0radius()); + histos.fill(HIST("V0KinematicQA/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcNClsCrossedRows(), posTrackExtra.itsNCls()); + histos.fill(HIST("V0KinematicQA/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcNClsCrossedRows(), negTrackExtra.itsNCls()); + histos.fill(HIST("V0KinematicQA/h2dPositivePtVsPhi"), v0.positivept(), computePhiMod(v0.positivephi(), 1)); + histos.fill(HIST("V0KinematicQA/h2dNegativePtVsPhi"), v0.negativept(), computePhiMod(v0.negativephi(), -1)); + if (isLambda && analyseLambda) { + histos.fill(HIST("hMassLambda"), v0.mLambda()); + histos.fill(HIST("Lambda/h3dMassLambda"), centrality, v0pt, v0.mLambda()); + histos.fill(HIST("Lambda/hPosDCAToPV"), v0.dcapostopv()); + histos.fill(HIST("Lambda/hNegDCAToPV"), v0.dcanegtopv()); + histos.fill(HIST("Lambda/hDCADaughters"), v0.dcaV0daughters()); + histos.fill(HIST("Lambda/hPointingAngle"), std::acos(v0.v0cosPA())); + histos.fill(HIST("Lambda/hV0Radius"), v0.v0radius()); + histos.fill(HIST("Lambda/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcNClsCrossedRows(), posTrackExtra.itsNCls()); + histos.fill(HIST("Lambda/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcNClsCrossedRows(), negTrackExtra.itsNCls()); + histos.fill(HIST("Lambda/h2dPositivePtVsPhi"), v0.positivept(), computePhiMod(v0.positivephi(), 1)); + histos.fill(HIST("Lambda/h2dNegativePtVsPhi"), v0.negativept(), computePhiMod(v0.negativephi(), -1)); + if (doTPCQA) { + histos.fill(HIST("Lambda/h3dPosNsigmaTPC"), centrality, v0pt, posTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTPC"), centrality, v0pt, negTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("Lambda/h3dPosTPCsignal"), centrality, v0pt, posTrackExtra.tpcSignal()); + histos.fill(HIST("Lambda/h3dNegTPCsignal"), centrality, v0pt, negTrackExtra.tpcSignal()); + histos.fill(HIST("Lambda/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("Lambda/h3dPosTPCsignalVsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcSignal()); + histos.fill(HIST("Lambda/h3dNegTPCsignalVsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcSignal()); + histos.fill(HIST("Lambda/h3dPosNsigmaTPCvsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTPCvsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("Lambda/h3dPosTPCsignalVsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcSignal()); + histos.fill(HIST("Lambda/h3dNegTPCsignalVsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcSignal()); + } + if constexpr (requires { v0.tofNSigmaLaPr(); }) { + if (doTOFQA) { + histos.fill(HIST("Lambda/h3dPosNsigmaTOF"), centrality, v0pt, v0.tofNSigmaLaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTOF"), centrality, v0pt, v0.tofNSigmaLaPi()); + histos.fill(HIST("Lambda/h3dPosTOFdeltaT"), centrality, v0pt, v0.posTOFDeltaTLaPr()); + histos.fill(HIST("Lambda/h3dNegTOFdeltaT"), centrality, v0pt, v0.negTOFDeltaTLaPi()); + histos.fill(HIST("Lambda/h3dPosNsigmaTOFvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.tofNSigmaLaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTOFvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.tofNSigmaLaPi()); + histos.fill(HIST("Lambda/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.posTOFDeltaTLaPr()); + histos.fill(HIST("Lambda/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.negTOFDeltaTLaPi()); + histos.fill(HIST("Lambda/h3dPosNsigmaTOFvsTrackPt"), centrality, v0.positivept(), v0.tofNSigmaLaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTOFvsTrackPt"), centrality, v0.negativept(), v0.tofNSigmaLaPi()); + histos.fill(HIST("Lambda/h3dPosTOFdeltaTvsTrackPt"), centrality, v0.positivept(), v0.posTOFDeltaTLaPr()); + histos.fill(HIST("Lambda/h3dNegTOFdeltaTvsTrackPt"), centrality, v0.negativept(), v0.negTOFDeltaTLaPi()); + } + } + if (doEtaPhiQA) { + histos.fill(HIST("Lambda/h5dV0PhiVsEta"), centrality, v0pt, v0.mLambda(), v0.phi(), v0.eta()); + histos.fill(HIST("Lambda/h5dPosPhiVsEta"), centrality, v0.positivept(), v0.mLambda(), v0.positivephi(), v0.positiveeta()); + histos.fill(HIST("Lambda/h5dNegPhiVsEta"), centrality, v0.negativept(), v0.mLambda(), v0.negativephi(), v0.negativeeta()); + } + } + if (isAntiLambda && analyseAntiLambda) { + histos.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + histos.fill(HIST("AntiLambda/h3dMassAntiLambda"), centrality, v0pt, v0.mAntiLambda()); + histos.fill(HIST("AntiLambda/hPosDCAToPV"), v0.dcapostopv()); + histos.fill(HIST("AntiLambda/hNegDCAToPV"), v0.dcanegtopv()); + histos.fill(HIST("AntiLambda/hDCADaughters"), v0.dcaV0daughters()); + histos.fill(HIST("AntiLambda/hPointingAngle"), std::acos(v0.v0cosPA())); + histos.fill(HIST("AntiLambda/hV0Radius"), v0.v0radius()); + histos.fill(HIST("AntiLambda/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcNClsCrossedRows(), posTrackExtra.itsNCls()); + histos.fill(HIST("AntiLambda/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcNClsCrossedRows(), negTrackExtra.itsNCls()); + histos.fill(HIST("AntiLambda/h2dPositivePtVsPhi"), v0.positivept(), computePhiMod(v0.positivephi(), 1)); + histos.fill(HIST("AntiLambda/h2dNegativePtVsPhi"), v0.negativept(), computePhiMod(v0.negativephi(), -1)); + if (doTPCQA) { + histos.fill(HIST("AntiLambda/h3dPosNsigmaTPC"), centrality, v0pt, posTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTPC"), centrality, v0pt, negTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("AntiLambda/h3dPosTPCsignal"), centrality, v0pt, posTrackExtra.tpcSignal()); + histos.fill(HIST("AntiLambda/h3dNegTPCsignal"), centrality, v0pt, negTrackExtra.tpcSignal()); + histos.fill(HIST("AntiLambda/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("AntiLambda/h3dPosTPCsignalVsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcSignal()); + histos.fill(HIST("AntiLambda/h3dNegTPCsignalVsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcSignal()); + histos.fill(HIST("AntiLambda/h3dPosNsigmaTPCvsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTPCvsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("AntiLambda/h3dPosTPCsignalVsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcSignal()); + histos.fill(HIST("AntiLambda/h3dNegTPCsignalVsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcSignal()); + } + if constexpr (requires { v0.tofNSigmaLaPr(); }) { + if (doTOFQA) { + histos.fill(HIST("AntiLambda/h3dPosNsigmaTOF"), centrality, v0pt, v0.tofNSigmaALaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTOF"), centrality, v0pt, v0.tofNSigmaALaPr()); + histos.fill(HIST("AntiLambda/h3dPosTOFdeltaT"), centrality, v0pt, v0.posTOFDeltaTLaPi()); + histos.fill(HIST("AntiLambda/h3dNegTOFdeltaT"), centrality, v0pt, v0.negTOFDeltaTLaPr()); + histos.fill(HIST("AntiLambda/h3dPosNsigmaTOFvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.tofNSigmaALaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTOFvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.tofNSigmaALaPr()); + histos.fill(HIST("AntiLambda/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.posTOFDeltaTLaPi()); + histos.fill(HIST("AntiLambda/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.negTOFDeltaTLaPr()); + histos.fill(HIST("AntiLambda/h3dPosNsigmaTOFvsTrackPt"), centrality, v0.positivept(), v0.tofNSigmaALaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTOFvsTrackPt"), centrality, v0.negativept(), v0.tofNSigmaALaPr()); + histos.fill(HIST("AntiLambda/h3dPosTOFdeltaTvsTrackPt"), centrality, v0.positivept(), v0.posTOFDeltaTLaPi()); + histos.fill(HIST("AntiLambda/h3dNegTOFdeltaTvsTrackPt"), centrality, v0.negativept(), v0.negTOFDeltaTLaPr()); + } + } + if (doEtaPhiQA) { + histos.fill(HIST("AntiLambda/h5dV0PhiVsEta"), centrality, v0pt, v0.mAntiLambda(), v0.phi(), v0.eta()); + histos.fill(HIST("AntiLambda/h5dPosPhiVsEta"), centrality, v0.positivept(), v0.mAntiLambda(), v0.positivephi(), v0.positiveeta()); + histos.fill(HIST("AntiLambda/h5dNegPhiVsEta"), centrality, v0.negativept(), v0.mAntiLambda(), v0.negativephi(), v0.negativeeta()); + } + } + } // end CompleteTopoQA + } // end V0s loop + + // Fill histograms on a per-event level: + histos.fill(HIST("Lambda/hLambdasPerEvent"), NLambdas); + histos.fill(HIST("AntiLambda/hAntiLambdasPerEvent"), NAntiLambdas); + histos.fill(HIST("hAmbiguousPerEvent"), NAmbiguous); + histos.fill(HIST("Lambda/h2dNbrOfLambdaVsCentrality"), centrality, NLambdas); + histos.fill(HIST("AntiLambda/h2dNbrOfAntiLambdaVsCentrality"), centrality, NAntiLambdas); + } + + void processData(SelCollisions::iterator const& collision, aod::V0Datas const& V0s, DauTracks const& V0DauTracks, aod::BCsWithTimestamps const& bcs) + { + dataProcess(collision, V0s, V0DauTracks, bcs); // No longer need "JetTracks const& jetTracks" -- using DauTracks subscription instead + } + + void processDataWithTOF(SelCollisions::iterator const& collision, V0CandidatesWithTOF const& V0s, DauTracks const& V0DauTracks, aod::BCsWithTimestamps const& bcs) + { + dataProcess(collision, V0s, V0DauTracks, bcs); + } + + PROCESS_SWITCH(lambdajetpolarizationions, processData, "Process jets and V0s, produces derived data in Run 3 Data", true); + PROCESS_SWITCH(lambdajetpolarizationions, processDataWithTOF, "Process jets and V0s (with TOF), produces derived data in Run 3 Data", false); + // PROCESS_SWITCH(lambdajetpolarizationions, processMC, "Process jets and V0s, produces derived data in Run 3 MC", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/sigmaHadCorr.cxx b/PWGLF/TableProducer/Strangeness/sigmaHadCorr.cxx new file mode 100644 index 00000000000..d31c384addf --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/sigmaHadCorr.cxx @@ -0,0 +1,739 @@ +// 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 sigmaHadCorr.cxx +/// \brief Analysis task for sigma-hadron correlations +/// \author Francesco Mazzaschi + +#include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFSigmaHadTables.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" + +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using TracksFull = soa::Join; +using TracksFullMC = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; + +struct sigmaHadCand { + + float ptHad() const + { + return std::hypot(pxHad, pyHad); + } + float sigmaPt() const + { + return std::hypot(sigmaPx, sigmaPy); + } + + int sigmaCharge = 0; // Charge of the sigma candidate + float sigmaMass = -1.f; // Mass of the Sigma candidate + float sigmaPx = -1; // Px of the Sigma candidate + float sigmaPy = -1; // Py of the Sigma candidate + float sigmaPz = -1; // Pz of the Sigma candidate + float sigmaDauPx = -1; // Px of the daughter track from Sigma decay + float sigmaDauPy = -1; // Py of the daughter track from Sigma decay + float sigmaDauPz = -1; // Pz of the daughter track from Sigma decay + float sigmaDecRadius = -1; // Decay radius of the Sigma candidate + float sigmaCosPA = -1; // Cosine of pointing angle of the Sigma candidate + + int chargeHad = 0; // Charge of the hadron candidate + float pxHad = -1; // Px of the hadron candidate + float pyHad = -1; // Py of the hadron candidate + float pzHad = -1; // Pz of the hadron candidate + + float nSigmaTPCHad = -1; // Number of sigmas for the hadron candidate + float nSigmaTOFHad = -1; // Number of sigmas for the hadron candidate using TOF + + int kinkDauID = -1; // ID of the pion from Sigma decay in MC + int sigmaID = -1; // ID of the Sigma candidate in MC + int hadID = -1; // ID of the hadron candidate in MC +}; + +struct sigmaHadCorrTask { + + std::vector sigmaHadCandidates; // Vector to store Sigma-hadron candidates + Produces outputDataTable; // Output table for Sigma-hadron candidates + Produces outputDataTableMC; // Output table for Sigma-hadron candidates in MC + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rSigmaHad{"sigmaHad", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // Configurable for event selection + Configurable cutzvertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + + Configurable minPtSigma{"minPtSigma", 1.f, "Minimum pT for Sigma candidates (GeV/c)"}; + Configurable cutEtaDaught{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; + Configurable cutDCAtoPVSigma{"cutDCAtoPVSigma", 0.1f, "Max DCA to primary vertex for Sigma candidates (cm)"}; + Configurable doSigmaMinus{"doSigmaMinus", true, "If true, pair Sigma- candidates, else Sigma+"}; + Configurable cutSigmaRadius{"cutSigmaRadius", 20.f, "Minimum radius for Sigma candidates (cm)"}; + Configurable cutSigmaMass{"cutSigmaMass", 0.3, "Sigma mass window (GeV/c^2)"}; + Configurable alphaAPCut{"alphaAPCut", 0., "Alpha AP cut for Sigma candidates"}; + Configurable qtAPCutLow{"qtAPCutLow", 0.15, "Lower qT AP cut for Sigma candidates (GeV/c)"}; + Configurable qtAPCutHigh{"qtAPCutHigh", 0.2, "Upper qT AP cut for Sigma candidates (GeV/c)"}; + + Configurable cutNITSClusPr{"cutNITSClusPr", 5, "Minimum number of ITS clusters for hadron track"}; + Configurable cutNTPCClusPr{"cutNTPCClusPr", 90, "Minimum number of TPC clusters for hadron track"}; + Configurable cutNSigmaTPC{"cutNSigmaTPC", 3, "TPC nSigma cut for hadron track"}; + Configurable cutNSigmaTOF{"cutNSigmaTOF", 3, "TOF nSigma cut for hadron track"}; + Configurable applyTOFPIDKinkDaughter{"applyTOFPIDKinkDaughter", false, "If true, apply TOF PID cut to the kink daughter track"}; + Configurable doSigmaPion{"doSigmaPion", false, "If true, pair Sigma with pions instead of protons"}; + + Configurable cutMaxKStar{"cutMaxKStar", 1.5, "Maximum k* for Sigma-hadron pairs (GeV/c)"}; + Configurable useRecalculatedSigmaMomentum{"useRecalculatedSigmaMomentum", true, "If true, compute k* using Sigma momentum recalculated from daughter kinematics"}; + + Configurable fillOutputTree{"fillOutputTree", true, "If true, fill the output tree with Sigma-hadron candidates"}; + Configurable fillSparseInvMassKstar{"fillSparseInvMassKstar", false, "If true, fill THn with invmass, k*, sigma charge, proton charge, sigma decay radius, cosPA, sigma pt"}; + + ConfigurableAxis CfgVtxBins{"CfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; + ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0, 40.0, 80.0, 500.0}, "Mixing bins - number of contributor"}; + Configurable nEvtMixingBkg{"nEvtMixingBkg", 5, "Number of events to mix for background reconstruction"}; + + Preslice kinkCandsPerCollisionPreslice = aod::kinkcand::collisionId; + Preslice tracksPerCollisionPreslice = aod::track::collisionId; + Preslice tracksMCPerCollisionPreslice = aod::track::collisionId; + + void init(InitContext const&) + { + // Axes + const AxisSpec ptAxis{100, -10, 10, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec massResolutionAxis{100, -0.1, 0.1, "m_{rec} - m_{gen} (GeV/#it{c}^{2})"}; + const AxisSpec nSigmaHadAxis{100, -5, 5, "n#sigma_{had}"}; + const AxisSpec sigmaMassAxis{50, 1.1, 1.3, "m (GeV/#it{c}^{2})"}; + const AxisSpec kStarAxis{200, 0.0, 2., "k* (GeV/#it{c})"}; + const AxisSpec ptHadAxis{100, 0.0, 10.0, "#it{p}_{T,had} (GeV/#it{c})"}; + const AxisSpec sigmaPtAxis{100, 0.0, 10.0, "#it{p}_{T,#Sigma} (GeV/#it{c})"}; + const AxisSpec sigmaPtAxisCoarse{20, 0.0, 10.0, "#it{p}_{T,#Sigma} (GeV/#it{c})"}; + const AxisSpec sigmaChargeAxis{2, -1.5, 1.5, "#Sigma charge"}; + const AxisSpec hadronChargeAxis{2, -1.5, 1.5, "Hadron charge"}; + const AxisSpec sigmaDecRadiusAxis{25, 14.5, 40.5, "#Sigma decay radius (cm)"}; + const AxisSpec sigmaDecRadiusAxisCoarse{5, 14.5, 40.5, "#Sigma decay radius (cm)"}; + const AxisSpec cosPAAxis{50, 0.9, 1.0, "cos(PA)"}; + const AxisSpec cosPAAxisCoarse{5, 0.9, 1.0, "cos(PA)"}; + const AxisSpec alphaAPAxis{100, -1.0, 1.0, "#alpha_{AP}"}; + const AxisSpec qtAPAxis{100, 0.0, 0.5, "q_{T,AP} (GeV/#it{c})"}; + const AxisSpec vertexZAxis{100, -15., 15., "vrtx_{Z} [cm]"}; + + // qa histograms + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + // Dedicated QA folder + rSigmaHad.add("QA/h2TPCNSigmaHadVsPtHad", "TPC n#sigma_{had} vs #it{p}_{T,had}", {HistType::kTH2F, {ptHadAxis, nSigmaHadAxis}}); + rSigmaHad.add("QA/h2TOFNSigmaHadVsPtHad", "TOF n#sigma_{had} vs #it{p}_{T,had}", {HistType::kTH2F, {ptHadAxis, nSigmaHadAxis}}); + rSigmaHad.add("QA/hSigmaPt", "#Sigma #it{p}_{T}", {HistType::kTH1F, {sigmaPtAxis}}); + rSigmaHad.add("QA/hSigmaPtRecal", "#Sigma #it{p}_{T} recalculated", {HistType::kTH1F, {sigmaPtAxis}}); + rSigmaHad.add("QA/h2InvMassVsPtSigma", "m_{#Sigma} vs #it{p}_{T,#Sigma}", {HistType::kTH2F, {sigmaPtAxis, sigmaMassAxis}}); + rSigmaHad.add("QA/h2QtAPvsAlphaAP", "q_{T,AP} vs #alpha_{AP}", {HistType::kTH2F, {alphaAPAxis, qtAPAxis}}); + + if (fillSparseInvMassKstar) { + rSigmaHad.add("hSparseSigmaHad", + "7D THnSparse: invmass, k*, sigma charge, hadron charge, sigma decay radius, cosPA, sigma pt", + {HistType::kTHnSparseF, {sigmaMassAxis, kStarAxis, sigmaChargeAxis, hadronChargeAxis, sigmaDecRadiusAxisCoarse, cosPAAxisCoarse, sigmaPtAxisCoarse}}); + rSigmaHad.add("hSparseSigmaHadMC", + "8D THnSparse (MC): invmass, k*, sigma charge, hadron charge, sigma decay radius, cosPA, sigma pt, k* gen", + {HistType::kTHnSparseF, {sigmaMassAxis, kStarAxis, sigmaChargeAxis, hadronChargeAxis, sigmaDecRadiusAxisCoarse, cosPAAxisCoarse, sigmaPtAxisCoarse, kStarAxis}}); + } + + LOG(info) << "Sigma-hadron correlation task initialized"; + LOG(info) << "Process SE enabled: " << doprocessSameEvent; + LOG(info) << "Process ME enabled: " << doprocessMixedEvent; + LOG(info) << "Process SE MC enabled: " << doprocessSameEventMC; + LOG(info) << "Process ME MC enabled: " << doprocessMixedEventMC; + LOG(info) << "Pairing mode: " << (doSigmaPion ? "Sigma-pion" : "Sigma-proton"); + } + + float getAlphaAP(const std::array& momMother, const std::array& momKink) + { + std::array momMissing = {momMother[0] - momKink[0], momMother[1] - momKink[1], momMother[2] - momKink[2]}; + float lQlP = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float lQlN = std::inner_product(momMother.begin(), momMother.end(), momMissing.begin(), 0.f); + return (lQlP - lQlN) / (lQlP + lQlN); + } + + float getQtAP(const std::array& momMother, const std::array& momKink) + { + float dp = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float p2V0 = std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f); + float p2A = std::inner_product(momKink.begin(), momKink.end(), momKink.begin(), 0.f); + return std::sqrt(p2A - dp * dp / p2V0); + } + + float getCosPA(const std::array& momMother, const std::array& decayVertex, const std::array& primaryVertex) + { + std::array decayVec = {decayVertex[0] - primaryVertex[0], decayVertex[1] - primaryVertex[1], decayVertex[2] - primaryVertex[2]}; + float dotProduct = std::inner_product(momMother.begin(), momMother.end(), decayVec.begin(), 0.f); + float momMotherMag = std::sqrt(std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f)); + float decayVecMag = std::sqrt(std::inner_product(decayVec.begin(), decayVec.end(), decayVec.begin(), 0.f)); + return dotProduct / (momMotherMag * decayVecMag); + } + + float getRecalculatedSigmaMomentum(const sigmaHadCand& candidate) + { + constexpr float massPion = o2::constants::physics::MassPionCharged; + constexpr float massNeutron = o2::constants::physics::MassNeutron; + float massSigma = doSigmaMinus ? o2::constants::physics::MassSigmaMinus : o2::constants::physics::MassSigmaPlus; + + float pMother = std::sqrt(candidate.sigmaPx * candidate.sigmaPx + candidate.sigmaPy * candidate.sigmaPy + candidate.sigmaPz * candidate.sigmaPz); + if (pMother < 1e-6f) { + return -999.f; + } + float versorX = candidate.sigmaPx / pMother; + float versorY = candidate.sigmaPy / pMother; + float versorZ = candidate.sigmaPz / pMother; + float ePi = std::sqrt(massPion * massPion + candidate.sigmaDauPx * candidate.sigmaDauPx + candidate.sigmaDauPy * candidate.sigmaDauPy + candidate.sigmaDauPz * candidate.sigmaDauPz); + float a = versorX * candidate.sigmaDauPx + versorY * candidate.sigmaDauPy + versorZ * candidate.sigmaDauPz; + float K = massSigma * massSigma + massPion * massPion - massNeutron * massNeutron; + float A = 4.f * (ePi * ePi - a * a); + float B = -4.f * a * K; + float C = 4.f * ePi * ePi * massSigma * massSigma - K * K; + if (std::abs(A) < 1e-6f) { + return -999.f; + } + float D = B * B - 4.f * A * C; + if (D < 0.f) { + return -999.f; + } + float sqrtD = std::sqrt(D); + float P1 = (-B + sqrtD) / (2.f * A); + float P2 = (-B - sqrtD) / (2.f * A); + if (P2 < 0.f && P1 < 0.f) { + return -999.f; + } + if (P2 < 0.f) { + return P1; + } + float p1Diff = std::abs(P1 - pMother); + float p2Diff = std::abs(P2 - pMother); + return (p1Diff < p2Diff) ? P1 : P2; + } + + std::array getSigmaMomentumForKstar(const sigmaHadCand& candidate) + { + std::array sigmaMomentum = {candidate.sigmaPx, candidate.sigmaPy, candidate.sigmaPz}; + if (!useRecalculatedSigmaMomentum) { + return sigmaMomentum; + } + + float pNew = getRecalculatedSigmaMomentum(candidate); + if (pNew <= 0.f) { + return sigmaMomentum; + } + + float pOld = std::sqrt(candidate.sigmaPx * candidate.sigmaPx + candidate.sigmaPy * candidate.sigmaPy + candidate.sigmaPz * candidate.sigmaPz); + if (pOld <= 0.f) { + return sigmaMomentum; + } + + float scale = pNew / pOld; + sigmaMomentum[0] *= scale; + sigmaMomentum[1] *= scale; + sigmaMomentum[2] *= scale; + return sigmaMomentum; + } + + float getHadTrackMass() + { + return doSigmaPion ? o2::constants::physics::MassPionCharged : o2::constants::physics::MassProton; + } + + float getSigmaMassForKstar() + { + return doSigmaMinus ? o2::constants::physics::MassSigmaMinus : o2::constants::physics::MassSigmaPlus; + } + + template + float getTPCNSigmaHad(const Ttrack& track) + { + return doSigmaPion ? track.tpcNSigmaPi() : track.tpcNSigmaPr(); + } + + template + float getTOFNSigmaHad(const Ttrack& track) + { + return doSigmaPion ? track.tofNSigmaPi() : track.tofNSigmaPr(); + } + + TLorentzVector trackSum, PartOneCMS, PartTwoCMS, trackRelK; + float getKStar(const sigmaHadCand& candidate) + { + TLorentzVector part1; // Sigma + TLorentzVector part2; // Hadron track (proton/pion) + part1.SetXYZM(candidate.sigmaPx, candidate.sigmaPy, candidate.sigmaPz, getSigmaMassForKstar()); + part2.SetXYZM(candidate.pxHad, candidate.pyHad, candidate.pzHad, getHadTrackMass()); + trackSum = part1 + part2; + const float beta = trackSum.Beta(); + const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betaz = beta * std::cos(trackSum.Theta()); + PartOneCMS.SetXYZM(part1.Px(), part1.Py(), part1.Pz(), part1.M()); + PartTwoCMS.SetXYZM(part2.Px(), part2.Py(), part2.Pz(), part2.M()); + const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); + PartOneCMS = boostPRF(PartOneCMS); + PartTwoCMS = boostPRF(PartTwoCMS); + trackRelK = PartOneCMS - PartTwoCMS; + return 0.5 * trackRelK.P(); + } + + float getKStar(float sigmaPx, float sigmaPy, float sigmaPz, float pxHad, float pyHad, float pzHad) + { + TLorentzVector part1; // Sigma + TLorentzVector part2; // Hadron track (proton/pion) + part1.SetXYZM(sigmaPx, sigmaPy, sigmaPz, getSigmaMassForKstar()); + part2.SetXYZM(pxHad, pyHad, pzHad, getHadTrackMass()); + trackSum = part1 + part2; + const float beta = trackSum.Beta(); + const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betaz = beta * std::cos(trackSum.Theta()); + PartOneCMS.SetXYZM(part1.Px(), part1.Py(), part1.Pz(), part1.M()); + PartTwoCMS.SetXYZM(part2.Px(), part2.Py(), part2.Pz(), part2.M()); + const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); + PartOneCMS = boostPRF(PartOneCMS); + PartTwoCMS = boostPRF(PartTwoCMS); + trackRelK = PartOneCMS - PartTwoCMS; + return 0.5 * trackRelK.P(); + } + + template + bool selectHadTrack(const Ttrack& candidate) + { + if (std::abs(getTPCNSigmaHad(candidate)) > cutNSigmaTPC || candidate.tpcNClsFound() < cutNTPCClusPr || std::abs(candidate.eta()) > cutEtaDaught) { + return false; + } + + if (candidate.itsNCls() < cutNITSClusPr) { + return false; + } + + float ptMinTOF = 0.75f; // Minimum pT to use TOF for hadron-track PID + if (candidate.pt() < ptMinTOF) { + return true; // No TOF cut for low pT + } + + if (!candidate.hasTOF()) { + return false; + } + if (std::abs(getTOFNSigmaHad(candidate)) > cutNSigmaTOF) { + return false; + } + return true; // Track is selected + } + + template + bool selectSigma(aod::KinkCands::iterator const& sigmaCand, Ttrack const& kinkDauTrack) + { + float mass = doSigmaMinus ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); + std::array momMoth = {sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + std::array momDaug = {sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; + float alphaAP = getAlphaAP(momMoth, momDaug); + float qtAP = getQtAP(momMoth, momDaug); + + if (alphaAP > alphaAPCut || (qtAP < qtAPCutLow || qtAP > qtAPCutHigh)) { + return false; + } + float decRad = std::hypot(sigmaCand.xDecVtx(), sigmaCand.yDecVtx()); + if (decRad < cutSigmaRadius) { + return false; + } + + if (doSigmaMinus) { + if (mass < o2::constants::physics::MassSigmaMinus - cutSigmaMass || mass > o2::constants::physics::MassSigmaMinus + cutSigmaMass) { + return false; + } + if (std::abs(kinkDauTrack.tpcNSigmaPi()) > cutNSigmaTPC) { + return false; + } + } else { + if (mass < o2::constants::physics::MassSigmaPlus - cutSigmaMass || mass > o2::constants::physics::MassSigmaPlus + cutSigmaMass) { + return false; + } + if (std::abs(kinkDauTrack.tpcNSigmaPr()) > cutNSigmaTPC) { + return false; + } + } + + if (applyTOFPIDKinkDaughter) { + constexpr float ptMinTOF = 0.75f; + if (kinkDauTrack.pt() >= ptMinTOF) { + if (!kinkDauTrack.hasTOF()) { + return false; + } + float kinkDauTOFNSigma = doSigmaMinus ? kinkDauTrack.tofNSigmaPi() : kinkDauTrack.tofNSigmaPr(); + if (std::abs(kinkDauTOFNSigma) > cutNSigmaTOF) { + return false; + } + } + } + + if (std::abs(sigmaCand.dcaMothPv()) > cutDCAtoPVSigma) { + return false; + } + return true; + } + + template + void fillTreeAndHistograms(aod::KinkCands const& kinkCands, Ttrack const& tracksDauSigma, Ttrack const& tracks, Tcollision const& collision, bool isMC) + { + for (const auto& sigmaCand : kinkCands) { + auto kinkDauTrack = tracksDauSigma.rawIteratorAt(sigmaCand.trackDaugId()); + if (!selectSigma(sigmaCand, kinkDauTrack)) { + continue; + } + + std::array momMothAll = {sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + std::array momDaugAll = {sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; + float alphaAP = getAlphaAP(momMothAll, momDaugAll); + float qtAP = getQtAP(momMothAll, momDaugAll); + rSigmaHad.fill(HIST("QA/h2QtAPvsAlphaAP"), alphaAP, qtAP); + + sigmaHadCand sigmaForPt; + sigmaForPt.sigmaPx = sigmaCand.pxMoth(); + sigmaForPt.sigmaPy = sigmaCand.pyMoth(); + sigmaForPt.sigmaPz = sigmaCand.pzMoth(); + sigmaForPt.sigmaDauPx = sigmaCand.pxDaug(); + sigmaForPt.sigmaDauPy = sigmaCand.pyDaug(); + sigmaForPt.sigmaDauPz = sigmaCand.pzDaug(); + auto sigmaPRecal = getSigmaMomentumForKstar(sigmaForPt); + float sigmaPtRecal = std::hypot(sigmaPRecal[0], sigmaPRecal[1]); + float sigmaMassForQa = doSigmaMinus ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); + + if (sigmaPtRecal < minPtSigma) { + continue; + } + + rSigmaHad.fill(HIST("QA/hSigmaPt"), sigmaCand.ptMoth()); + rSigmaHad.fill(HIST("QA/hSigmaPtRecal"), sigmaPtRecal); + rSigmaHad.fill(HIST("QA/h2InvMassVsPtSigma"), sigmaPtRecal, sigmaMassForQa); + + for (const auto& hadTrack : tracks) { + if (hadTrack.globalIndex() == sigmaCand.trackDaugId()) { + continue; + } + + if (!selectHadTrack(hadTrack)) { + continue; + } + + sigmaHadCand candidate; + candidate.sigmaCharge = sigmaCand.mothSign(); + candidate.sigmaPx = sigmaCand.pxMoth(); + candidate.sigmaPy = sigmaCand.pyMoth(); + candidate.sigmaPz = sigmaCand.pzMoth(); + candidate.sigmaDauPx = sigmaCand.pxDaug(); + candidate.sigmaDauPy = sigmaCand.pyDaug(); + candidate.sigmaDauPz = sigmaCand.pzDaug(); + candidate.sigmaDecRadius = std::hypot(sigmaCand.xDecVtx(), sigmaCand.yDecVtx()); + + std::array momMoth = {sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + std::array decayVtx = {sigmaCand.xDecVtx(), sigmaCand.yDecVtx(), sigmaCand.zDecVtx()}; + std::array primaryVtx = {collision.posX(), collision.posY(), collision.posZ()}; + candidate.sigmaCosPA = getCosPA(momMoth, decayVtx, primaryVtx); + + candidate.chargeHad = hadTrack.sign(); + candidate.pxHad = hadTrack.px(); + candidate.pyHad = hadTrack.py(); + candidate.pzHad = hadTrack.pz(); + candidate.nSigmaTPCHad = getTPCNSigmaHad(hadTrack); + candidate.nSigmaTOFHad = getTOFNSigmaHad(hadTrack); + candidate.sigmaMass = doSigmaMinus ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); + + candidate.sigmaID = sigmaCand.trackMothId(); + candidate.kinkDauID = sigmaCand.trackDaugId(); + candidate.hadID = hadTrack.globalIndex(); + + float kStar = getKStar(sigmaPRecal[0], sigmaPRecal[1], sigmaPRecal[2], candidate.pxHad, candidate.pyHad, candidate.pzHad); + if (kStar > cutMaxKStar) { + continue; + } + + rSigmaHad.fill(HIST("QA/h2TPCNSigmaHadVsPtHad"), candidate.ptHad(), candidate.nSigmaTPCHad); + if (hadTrack.hasTOF()) { + rSigmaHad.fill(HIST("QA/h2TOFNSigmaHadVsPtHad"), candidate.ptHad(), candidate.nSigmaTOFHad); + } + if (fillSparseInvMassKstar && !isMC) { + rSigmaHad.fill(HIST("hSparseSigmaHad"), + candidate.sigmaMass, + kStar, + candidate.sigmaCharge, + candidate.chargeHad, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + sigmaPtRecal); + } + sigmaHadCandidates.push_back(candidate); + } + } + } + + void processSameEvent(CollisionsFull const& collisions, aod::KinkCands const& kinkCands, TracksFull const& tracks) + { + for (auto const& collision : collisions) { + + sigmaHadCandidates.clear(); + auto kinkCands_c = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); + auto tracks_c = tracks.sliceBy(tracksPerCollisionPreslice, collision.globalIndex()); + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + continue; + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + fillTreeAndHistograms(kinkCands_c, tracks, tracks_c, collision, false); + if (fillOutputTree) { + // Fill output table + for (const auto& candidate : sigmaHadCandidates) { + outputDataTable(candidate.sigmaCharge, + candidate.sigmaPx, + candidate.sigmaPy, + candidate.sigmaPz, + candidate.sigmaDauPx, + candidate.sigmaDauPy, + candidate.sigmaDauPz, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + candidate.chargeHad, + candidate.pxHad, + candidate.pyHad, + candidate.pzHad, + candidate.nSigmaTPCHad, + candidate.nSigmaTOFHad); + } + } + } + } + PROCESS_SWITCH(sigmaHadCorrTask, processSameEvent, "Process Same event", true); + + // Processing Event Mixing + SliceCache cache; + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{CfgVtxBins, CfgMultBins}, true}; + + void processMixedEvent(const CollisionsFull& collisions, const aod::KinkCands& kinkCands, const TracksFull& tracks) + { + for (auto const& [collision1, collision2] : + selfCombinations(colBinning, nEvtMixingBkg, -1, collisions, collisions)) { + if (collision1.index() == collision2.index()) + continue; + + sigmaHadCandidates.clear(); + if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) { + continue; + } + if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) { + continue; + } + auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); + auto tracks_c1 = tracks.sliceBy(tracksPerCollisionPreslice, collision1.globalIndex()); + auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); + fillTreeAndHistograms(kinkCands_c1, tracks, tracks_c2, collision1, false); + + if (fillOutputTree) { + // Fill output table + for (const auto& candidate : sigmaHadCandidates) { + outputDataTable(candidate.sigmaCharge, + candidate.sigmaPx, + candidate.sigmaPy, + candidate.sigmaPz, + candidate.sigmaDauPx, + candidate.sigmaDauPy, + candidate.sigmaDauPz, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + candidate.chargeHad, + candidate.pxHad, + candidate.pyHad, + candidate.pzHad, + candidate.nSigmaTPCHad, + candidate.nSigmaTOFHad); + } + } + } + LOG(debug) << "Processing mixed event"; + } + PROCESS_SWITCH(sigmaHadCorrTask, processMixedEvent, "Process Mixed event", false); + + void processSameEventMC(CollisionsFullMC const& collisions, aod::KinkCands const& kinkCands, TracksFullMC const& tracks, aod::McParticles const&) + { + for (auto const& collision : collisions) { + + sigmaHadCandidates.clear(); + auto kinkCands_c = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); + auto tracks_c = tracks.sliceBy(tracksMCPerCollisionPreslice, collision.globalIndex()); + + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + continue; + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + fillTreeAndHistograms(kinkCands_c, tracks, tracks_c, collision, true); + for (const auto& candidate : sigmaHadCandidates) { + auto mcLabelSigma = tracks.rawIteratorAt(candidate.sigmaID); + auto mcLabelSigmaDau = tracks.rawIteratorAt(candidate.kinkDauID); + auto mcLabelHad = tracks.rawIteratorAt(candidate.hadID); + + if (!mcLabelSigma.has_mcParticle() || !mcLabelSigmaDau.has_mcParticle() || !mcLabelHad.has_mcParticle()) { + continue; // Skip candidates where MC truth is not available + } + + auto mcPartSigma = mcLabelSigma.mcParticle_as(); + auto mcPartSigmaDau = mcLabelSigmaDau.mcParticle_as(); + auto mcPartHad = mcLabelHad.mcParticle_as(); + auto pdgSigma = mcPartSigma.pdgCode(); + auto pdgSigmaDau = mcLabelSigmaDau.has_mcParticle() ? mcPartSigmaDau.pdgCode() : -999; + auto pdgHad = mcLabelHad.has_mcParticle() ? mcPartHad.pdgCode() : -999; + + float sigmaPtGen = std::hypot(mcPartSigma.px(), mcPartSigma.py()); + float hadPtGen = std::hypot(mcPartHad.px(), mcPartHad.py()); + float kStarGen = getKStar(mcPartSigma.px(), mcPartSigma.py(), mcPartSigma.pz(), mcPartHad.px(), mcPartHad.py(), mcPartHad.pz()); + + if (fillSparseInvMassKstar) { + auto sigmaMomForKstar = getSigmaMomentumForKstar(candidate); + float kStarRec = getKStar(sigmaMomForKstar[0], sigmaMomForKstar[1], sigmaMomForKstar[2], candidate.pxHad, candidate.pyHad, candidate.pzHad); + float sigmaPtUsed = std::hypot(sigmaMomForKstar[0], sigmaMomForKstar[1]); + rSigmaHad.fill(HIST("hSparseSigmaHadMC"), + candidate.sigmaMass, + kStarRec, + candidate.sigmaCharge, + candidate.chargeHad, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + sigmaPtUsed, + kStarGen); + } + + if (fillOutputTree) { + outputDataTableMC(candidate.sigmaCharge, + candidate.sigmaPx, + candidate.sigmaPy, + candidate.sigmaPz, + candidate.sigmaDauPx, + candidate.sigmaDauPy, + candidate.sigmaDauPz, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + candidate.chargeHad, + candidate.pxHad, + candidate.pyHad, + candidate.pzHad, + candidate.nSigmaTPCHad, + candidate.nSigmaTOFHad, + pdgSigma, + pdgSigmaDau, + pdgHad, + sigmaPtGen, + hadPtGen, + kStarGen); + } + } + } + } + PROCESS_SWITCH(sigmaHadCorrTask, processSameEventMC, "Process Same event MC", false); + + void processMixedEventMC(const CollisionsFullMC& collisions, const aod::KinkCands& kinkCands, const TracksFullMC& tracks, const aod::McParticles&) + { + for (auto const& [collision1, collision2] : + selfCombinations(colBinning, nEvtMixingBkg, -1, collisions, collisions)) { + if (collision1.index() == collision2.index()) + continue; + + sigmaHadCandidates.clear(); + if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) { + continue; + } + if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) { + continue; + } + auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); + auto tracks_c1 = tracks.sliceBy(tracksPerCollisionPreslice, collision1.globalIndex()); + auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); + fillTreeAndHistograms(kinkCands_c1, tracks, tracks_c2, collision1, true); + + for (const auto& candidate : sigmaHadCandidates) { + auto mcLabelSigma = tracks.rawIteratorAt(candidate.sigmaID); + auto mcLabelSigmaDau = tracks.rawIteratorAt(candidate.kinkDauID); + auto mcLabelHad = tracks.rawIteratorAt(candidate.hadID); + + if (!mcLabelSigma.has_mcParticle() || !mcLabelSigmaDau.has_mcParticle() || !mcLabelHad.has_mcParticle()) { + continue; // Skip candidates where MC truth is not available + } + + auto mcPartSigma = mcLabelSigma.mcParticle_as(); + auto mcPartSigmaDau = mcLabelSigmaDau.mcParticle_as(); + auto mcPartHad = mcLabelHad.mcParticle_as(); + auto pdgSigma = mcPartSigma.pdgCode(); + auto pdgSigmaDau = mcLabelSigmaDau.has_mcParticle() ? mcPartSigmaDau.pdgCode() : -999; + auto pdgHad = mcLabelHad.has_mcParticle() ? mcPartHad.pdgCode() : -999; + float sigmaPtGen = std::hypot(mcPartSigma.px(), mcPartSigma.py()); + float hadPtGen = std::hypot(mcPartHad.px(), mcPartHad.py()); + float kStarGen = getKStar(mcPartSigma.px(), mcPartSigma.py(), mcPartSigma.pz(), mcPartHad.px(), mcPartHad.py(), mcPartHad.pz()); + + if (fillSparseInvMassKstar) { + auto sigmaMomForKstar = getSigmaMomentumForKstar(candidate); + float kStarRec = getKStar(sigmaMomForKstar[0], sigmaMomForKstar[1], sigmaMomForKstar[2], candidate.pxHad, candidate.pyHad, candidate.pzHad); + float sigmaPtUsed = std::hypot(sigmaMomForKstar[0], sigmaMomForKstar[1]); + rSigmaHad.fill(HIST("hSparseSigmaHadMC"), + candidate.sigmaMass, + kStarRec, + candidate.sigmaCharge, + candidate.chargeHad, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + sigmaPtUsed, + kStarGen); + } + + if (fillOutputTree) { + outputDataTableMC(candidate.sigmaCharge, + candidate.sigmaPx, + candidate.sigmaPy, + candidate.sigmaPz, + candidate.sigmaDauPx, + candidate.sigmaDauPy, + candidate.sigmaDauPz, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + candidate.chargeHad, + candidate.pxHad, + candidate.pyHad, + candidate.pzHad, + candidate.nSigmaTPCHad, + candidate.nSigmaTOFHad, + pdgSigma, + pdgSigmaDau, + pdgHad, + sigmaPtGen, + hadPtGen, + kStarGen); + } + } + } + LOG(debug) << "Processing mixed event MC"; + } + PROCESS_SWITCH(sigmaHadCorrTask, processMixedEventMC, "Process Mixed event MC", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/sigmaProtonCorr.cxx b/PWGLF/TableProducer/Strangeness/sigmaProtonCorr.cxx deleted file mode 100644 index 26c4eee67d7..00000000000 --- a/PWGLF/TableProducer/Strangeness/sigmaProtonCorr.cxx +++ /dev/null @@ -1,547 +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 sigmaProtonCorr.cxx -/// \brief Analysis task for sigma-proton correlations -/// \author Francesco Mazzaschi - -#include "PWGLF/DataModel/LFKinkDecayTables.h" -#include "PWGLF/DataModel/LFSigmaProtonTables.h" - -#include "Common/Core/PID/PIDTOF.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponseTOF.h" -#include "Common/DataModel/PIDResponseTPC.h" - -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/PID.h" - -#include -#include -#include -#include - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using TracksFull = soa::Join; -using TracksFullMC = soa::Join; -using CollisionsFull = soa::Join; -using CollisionsFullMC = soa::Join; - -struct sigmaProtonCand { - - float ptPr() const - { - return std::hypot(pxPr, pyPr); - } - float sigmaPt() const - { - return std::hypot(sigmaPx, sigmaPy); - } - - int sigmaCharge = 0; // Charge of the sigma candidate - int sigmaMass = -1; // Mass of the Sigma candidate - float sigmaPx = -1; // Px of the Sigma candidate - float sigmaPy = -1; // Py of the Sigma candidate - float sigmaPz = -1; // Pz of the Sigma candidate - float sigmaDauPx = -1; // Px of the daughter track from Sigma decay - float sigmaDauPy = -1; // Py of the daughter track from Sigma decay - float sigmaDauPz = -1; // Pz of the daughter track from Sigma decay - float sigmaDecRadius = -1; // Decay radius of the Sigma candidate - float sigmaCosPA = -1; // Cosine of pointing angle of the Sigma candidate - - int chargePr = 0; // Charge of the proton candidate - float pxPr = -1; // Px of the proton candidate - float pyPr = -1; // Py of the proton candidate - float pzPr = -1; // Pz of the proton candidate - - float nSigmaTPCPr = -1; // Number of sigmas for the proton candidate - float nSigmaTOFPr = -1; // Number of sigmas for the proton candidate using TOF - - int kinkDauID = -1; // ID of the pion from Sigma decay in MC - int sigmaID = -1; // ID of the Sigma candidate in MC - int prID = -1; // ID of the proton candidate in MC -}; - -struct sigmaProtonCorrTask { - - std::vector sigmaProtonCandidates; // Vector to store Sigma-Proton candidates - Produces outputDataTable; // Output table for Sigma-Proton candidates - Produces outputDataTableMC; // Output table for Sigma-Proton candidates in MC - // Histograms are defined with HistogramRegistry - HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rSigmaProton{"sigmaProton", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - // Configurable for event selection - Configurable cutzvertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; - - Configurable minPtSigma{"minPtSigma", 1.f, "Minimum pT for Sigma candidates (GeV/c)"}; - Configurable cutEtaDaught{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; - Configurable cutDCAtoPVSigma{"cutDCAtoPVSigma", 0.1f, "Max DCA to primary vertex for Sigma candidates (cm)"}; - Configurable doSigmaMinus{"doSigmaMinus", true, "If true, pair Sigma- candidates, else Sigma+"}; - Configurable cutSigmaRadius{"cutSigmaRadius", 20.f, "Minimum radius for Sigma candidates (cm)"}; - Configurable cutSigmaMass{"cutSigmaMass", 0.3, "Sigma mass window (GeV/c^2)"}; - Configurable alphaAPCut{"alphaAPCut", 0., "Alpha AP cut for Sigma candidates"}; - Configurable qtAPCutLow{"qtAPCutLow", 0.15, "Lower qT AP cut for Sigma candidates (GeV/c)"}; - Configurable qtAPCutHigh{"qtAPCutHigh", 0.2, "Upper qT AP cut for Sigma candidates (GeV/c)"}; - - Configurable cutNITSClusPr{"cutNITSClusPr", 5, "Minimum number of ITS clusters for proton candidate"}; - Configurable cutNTPCClusPr{"cutNTPCClusPr", 90, "Minimum number of TPC clusters for proton candidate"}; - Configurable cutNSigmaTPC{"cutNSigmaTPC", 3, "NSigmaTPCPr"}; - Configurable cutNSigmaTOF{"cutNSigmaTOF", 3, "NSigmaTOFPr"}; - - Configurable cutMaxKStar{"cutMaxKStar", 1.5, "Maximum k* for Sigma-Proton pairs (GeV/c)"}; - - Configurable fillOutputTree{"fillOutputTree", true, "If true, fill the output tree with Sigma-Proton candidates"}; - - ConfigurableAxis CfgVtxBins{"CfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; - ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0, 40.0, 80.0, 500.0}, "Mixing bins - number of contributor"}; - Configurable nEvtMixingBkg{"nEvtMixingBkg", 5, "Number of events to mix for background reconstruction"}; - - Preslice kinkCandsPerCollisionPreslice = aod::kinkcand::collisionId; - Preslice tracksPerCollisionPreslice = aod::track::collisionId; - Preslice tracksMCPerCollisionPreslice = aod::track::collisionId; - - void init(InitContext const&) - { - // Axes - const AxisSpec ptAxis{100, -10, 10, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec massResolutionAxis{100, -0.1, 0.1, "m_{rec} - m_{gen} (GeV/#it{c}^{2})"}; - const AxisSpec nSigmaPrAxis{100, -5, 5, "n#sigma_{#pr}"}; - const AxisSpec sigmaMassAxis{100, 1.1, 1.4, "m (GeV/#it{c}^{2})"}; - const AxisSpec vertexZAxis{100, -15., 15., "vrtx_{Z} [cm]"}; - - // qa histograms - rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); - rSigmaProton.add("h2PtMassSigma", "h2PtMassSigma", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); - rSigmaProton.add("h2PtPrNSigma", "h2PtPrNSigma", {HistType::kTH2F, {ptAxis, nSigmaPrAxis}}); - rSigmaProton.add("h2PtPrNSigmaTOF", "h2PtPrNSigmaTOF", {HistType::kTH2F, {ptAxis, nSigmaPrAxis}}); - - LOG(info) << "Sigma-Proton correlation task initialized"; - LOG(info) << "Process SE enabled: " << doprocessSameEvent; - LOG(info) << "Process ME enabled: " << doprocessMixedEvent; - LOG(info) << "Process SE MC enabled: " << doprocessSameEventMC; - LOG(info) << "Process ME MC enabled: " << doprocessMixedEventMC; - } - - float getAlphaAP(const std::array& momMother, const std::array& momKink) - { - std::array momMissing = {momMother[0] - momKink[0], momMother[1] - momKink[1], momMother[2] - momKink[2]}; - float lQlP = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); - float lQlN = std::inner_product(momMother.begin(), momMother.end(), momMissing.begin(), 0.f); - return (lQlP - lQlN) / (lQlP + lQlN); - } - - float getQtAP(const std::array& momMother, const std::array& momKink) - { - float dp = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); - float p2V0 = std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f); - float p2A = std::inner_product(momKink.begin(), momKink.end(), momKink.begin(), 0.f); - return std::sqrt(p2A - dp * dp / p2V0); - } - - float getCosPA(const std::array& momMother, const std::array& decayVertex, const std::array& primaryVertex) - { - std::array decayVec = {decayVertex[0] - primaryVertex[0], decayVertex[1] - primaryVertex[1], decayVertex[2] - primaryVertex[2]}; - float dotProduct = std::inner_product(momMother.begin(), momMother.end(), decayVec.begin(), 0.f); - float momMotherMag = std::sqrt(std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f)); - float decayVecMag = std::sqrt(std::inner_product(decayVec.begin(), decayVec.end(), decayVec.begin(), 0.f)); - return dotProduct / (momMotherMag * decayVecMag); - } - - TLorentzVector trackSum, PartOneCMS, PartTwoCMS, trackRelK; - float getKStar(const sigmaProtonCand& candidate) - { - TLorentzVector part1; // Sigma - TLorentzVector part2; // Proton - part1.SetXYZM(candidate.sigmaPx, candidate.sigmaPy, candidate.sigmaPz, o2::constants::physics::MassSigmaMinus); - part2.SetXYZM(candidate.pxPr, candidate.pyPr, candidate.pzPr, o2::constants::physics::MassProton); - trackSum = part1 + part2; - const float beta = trackSum.Beta(); - const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); - const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); - const float betaz = beta * std::cos(trackSum.Theta()); - PartOneCMS.SetXYZM(part1.Px(), part1.Py(), part1.Pz(), part1.M()); - PartTwoCMS.SetXYZM(part2.Px(), part2.Py(), part2.Pz(), part2.M()); - const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); - PartOneCMS = boostPRF(PartOneCMS); - PartTwoCMS = boostPRF(PartTwoCMS); - trackRelK = PartOneCMS - PartTwoCMS; - return 0.5 * trackRelK.P(); - } - - float getKStar(float sigmaPx, float sigmaPy, float sigmaPz, float pxPr, float pyPr, float pzPr) - { - TLorentzVector part1; // Sigma - TLorentzVector part2; // Proton - part1.SetXYZM(sigmaPx, sigmaPy, sigmaPz, o2::constants::physics::MassSigmaMinus); - part2.SetXYZM(pxPr, pyPr, pzPr, o2::constants::physics::MassProton); - trackSum = part1 + part2; - const float beta = trackSum.Beta(); - const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); - const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); - const float betaz = beta * std::cos(trackSum.Theta()); - PartOneCMS.SetXYZM(part1.Px(), part1.Py(), part1.Pz(), part1.M()); - PartTwoCMS.SetXYZM(part2.Px(), part2.Py(), part2.Pz(), part2.M()); - const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); - PartOneCMS = boostPRF(PartOneCMS); - PartTwoCMS = boostPRF(PartTwoCMS); - trackRelK = PartOneCMS - PartTwoCMS; - return 0.5 * trackRelK.P(); - } - - template - bool selectPrTrack(const Ttrack& candidate) - { - if (std::abs(candidate.tpcNSigmaPr()) > cutNSigmaTPC || candidate.tpcNClsFound() < cutNTPCClusPr || std::abs(candidate.eta()) > cutEtaDaught) { - return false; - } - - if (candidate.itsNCls() < cutNITSClusPr) { - return false; - } - - float ptMinTOF = 0.75f; // Minimum pT to use TOF for proton PID - if (candidate.pt() < ptMinTOF) { - return true; // No TOF cut for low pT - } - - if (!candidate.hasTOF()) { - return false; - } - if (std::abs(candidate.tofNSigmaPr()) > cutNSigmaTOF) { - return false; - } - return true; // Track is selected - } - - template - bool selectSigma(aod::KinkCands::iterator const& sigmaCand, Ttrack const&) - { - - auto kinkDauTrack = sigmaCand.trackDaug_as(); - float mass = doSigmaMinus ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); - std::array momMoth = {sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; - std::array momDaug = {sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; - float alphaAP = getAlphaAP(momMoth, momDaug); - float qtAP = getQtAP(momMoth, momDaug); - - if (sigmaCand.ptMoth() < minPtSigma) { - return false; - } - - if (alphaAP > alphaAPCut || (qtAP < qtAPCutLow || qtAP > qtAPCutHigh)) { - return false; - } - float decRad = std::hypot(sigmaCand.xDecVtx(), sigmaCand.yDecVtx()); - if (decRad < cutSigmaRadius) { - return false; - } - - if (doSigmaMinus) { - if (mass < o2::constants::physics::MassSigmaMinus - cutSigmaMass || mass > o2::constants::physics::MassSigmaMinus + cutSigmaMass) { - return false; - } - if (std::abs(kinkDauTrack.tpcNSigmaPi()) > cutNSigmaTPC) { - return false; - } - } else { - if (mass < o2::constants::physics::MassSigmaPlus - cutSigmaMass || mass > o2::constants::physics::MassSigmaPlus + cutSigmaMass) { - return false; - } - if (std::abs(kinkDauTrack.tpcNSigmaPr()) > cutNSigmaTPC) { - return false; - } - } - if (std::abs(sigmaCand.dcaMothPv()) > cutDCAtoPVSigma) { - return false; - } - return true; - } - - template - void fillTreeAndHistograms(aod::KinkCands const& kinkCands, Ttrack const& tracksDauSigma, Ttrack const& tracks, Tcollision const& collision) - { - for (const auto& sigmaCand : kinkCands) { - if (selectSigma(sigmaCand, tracksDauSigma)) { - if (doSigmaMinus) { - rSigmaProton.fill(HIST("h2PtMassSigma"), sigmaCand.mothSign() * sigmaCand.ptMoth(), sigmaCand.mSigmaMinus()); - } else { - rSigmaProton.fill(HIST("h2PtMassSigma"), sigmaCand.mothSign() * sigmaCand.ptMoth(), sigmaCand.mSigmaPlus()); - } - - for (const auto& prTrack : tracks) { - if (!selectPrTrack(prTrack)) { - continue; - } - - sigmaProtonCand candidate; - candidate.sigmaCharge = sigmaCand.mothSign(); - candidate.sigmaPx = sigmaCand.pxMoth(); - candidate.sigmaPy = sigmaCand.pyMoth(); - candidate.sigmaPz = sigmaCand.pzMoth(); - candidate.sigmaDauPx = sigmaCand.pxDaug(); - candidate.sigmaDauPy = sigmaCand.pyDaug(); - candidate.sigmaDauPz = sigmaCand.pzDaug(); - candidate.sigmaDecRadius = std::hypot(sigmaCand.xDecVtx(), sigmaCand.yDecVtx()); - - std::array momMoth = {sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; - std::array decayVtx = {sigmaCand.xDecVtx(), sigmaCand.yDecVtx(), sigmaCand.zDecVtx()}; - std::array primaryVtx = {collision.posX(), collision.posY(), collision.posZ()}; - candidate.sigmaCosPA = getCosPA(momMoth, decayVtx, primaryVtx); - - candidate.chargePr = prTrack.sign(); - candidate.pxPr = prTrack.px(); - candidate.pyPr = prTrack.py(); - candidate.pzPr = prTrack.pz(); - candidate.nSigmaTPCPr = prTrack.tpcNSigmaPr(); - candidate.nSigmaTOFPr = prTrack.tofNSigmaPr(); - candidate.sigmaMass = doSigmaMinus ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); - - candidate.sigmaID = sigmaCand.trackMothId(); - candidate.kinkDauID = sigmaCand.trackDaugId(); - candidate.prID = prTrack.globalIndex(); - - if (getKStar(candidate) > cutMaxKStar) { - continue; - } - - rSigmaProton.fill(HIST("h2PtPrNSigma"), candidate.ptPr(), candidate.nSigmaTPCPr); - if (prTrack.hasTOF()) { - rSigmaProton.fill(HIST("h2PtPrNSigmaTOF"), candidate.ptPr(), candidate.nSigmaTOFPr); - } - sigmaProtonCandidates.push_back(candidate); - } - } - } - } - - void processSameEvent(CollisionsFull const& collisions, aod::KinkCands const& kinkCands, TracksFull const& tracks) - { - for (auto const& collision : collisions) { - - sigmaProtonCandidates.clear(); - auto kinkCands_c = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); - auto tracks_c = tracks.sliceBy(tracksPerCollisionPreslice, collision.globalIndex()); - if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { - continue; - } - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - fillTreeAndHistograms(kinkCands_c, tracks_c, tracks_c, collision); - if (fillOutputTree) { - // Fill output table - for (const auto& candidate : sigmaProtonCandidates) { - outputDataTable(candidate.sigmaCharge, - candidate.sigmaPx, - candidate.sigmaPy, - candidate.sigmaPz, - candidate.sigmaDauPx, - candidate.sigmaDauPy, - candidate.sigmaDauPz, - candidate.sigmaDecRadius, - candidate.sigmaCosPA, - candidate.chargePr, - candidate.pxPr, - candidate.pyPr, - candidate.pzPr, - candidate.nSigmaTPCPr, - candidate.nSigmaTOFPr); - } - } - } - } - PROCESS_SWITCH(sigmaProtonCorrTask, processSameEvent, "Process Same event", true); - - // Processing Event Mixing - SliceCache cache; - using BinningType = ColumnBinningPolicy; - BinningType colBinning{{CfgVtxBins, CfgMultBins}, true}; - - void processMixedEvent(const CollisionsFull& collisions, const aod::KinkCands& kinkCands, const TracksFull& tracks) - { - for (auto const& [collision1, collision2] : - selfCombinations(colBinning, nEvtMixingBkg, -1, collisions, collisions)) { - if (collision1.index() == collision2.index()) - continue; - - sigmaProtonCandidates.clear(); - if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) { - continue; - } - if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) { - continue; - } - auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c1 = tracks.sliceBy(tracksPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); - fillTreeAndHistograms(kinkCands_c1, tracks_c1, tracks_c2, collision1); - - if (fillOutputTree) { - // Fill output table - for (const auto& candidate : sigmaProtonCandidates) { - outputDataTable(candidate.sigmaCharge, - candidate.sigmaPx, - candidate.sigmaPy, - candidate.sigmaPz, - candidate.sigmaDauPx, - candidate.sigmaDauPy, - candidate.sigmaDauPz, - candidate.sigmaDecRadius, - candidate.sigmaCosPA, - candidate.chargePr, - candidate.pxPr, - candidate.pyPr, - candidate.pzPr, - candidate.nSigmaTPCPr, - candidate.nSigmaTOFPr); - } - } - } - LOG(debug) << "Processing mixed event"; - } - PROCESS_SWITCH(sigmaProtonCorrTask, processMixedEvent, "Process Mixed event", false); - - void processSameEventMC(CollisionsFullMC const& collisions, aod::KinkCands const& kinkCands, TracksFullMC const& tracks, aod::McParticles const&) - { - for (auto const& collision : collisions) { - - sigmaProtonCandidates.clear(); - auto kinkCands_c = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); - auto tracks_c = tracks.sliceBy(tracksMCPerCollisionPreslice, collision.globalIndex()); - - if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { - continue; - } - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - fillTreeAndHistograms(kinkCands_c, tracks_c, tracks_c, collision); - if (fillOutputTree) { - // Fill output table - for (const auto& candidate : sigmaProtonCandidates) { - auto mcLabelSigma = tracks.rawIteratorAt(candidate.sigmaID); - auto mcLabelSigmaDau = tracks.rawIteratorAt(candidate.kinkDauID); - auto mcLabelPr = tracks.rawIteratorAt(candidate.prID); - - if (!mcLabelSigma.has_mcParticle() || !mcLabelSigmaDau.has_mcParticle() || !mcLabelPr.has_mcParticle()) { - continue; // Skip candidates where MC truth is not available - } - - auto mcPartSigma = mcLabelSigma.mcParticle_as(); - auto mcPartSigmaDau = mcLabelSigmaDau.mcParticle_as(); - auto mcPartPr = mcLabelPr.mcParticle_as(); - auto pdgSigma = mcPartSigma.pdgCode(); - auto pdgSigmaDau = mcLabelSigmaDau.has_mcParticle() ? mcPartSigmaDau.pdgCode() : -999; - auto pdgPr = mcLabelPr.has_mcParticle() ? mcPartPr.pdgCode() : -999; - - float sigmaPtGen = std::hypot(mcPartSigma.px(), mcPartSigma.py()); - float prPtGen = std::hypot(mcPartPr.px(), mcPartPr.py()); - float kStarGen = getKStar(mcPartSigma.px(), mcPartSigma.py(), mcPartSigma.pz(), mcPartPr.px(), mcPartPr.py(), mcPartPr.pz()); - - outputDataTableMC(candidate.sigmaCharge, - candidate.sigmaPx, - candidate.sigmaPy, - candidate.sigmaPz, - candidate.sigmaDauPx, - candidate.sigmaDauPy, - candidate.sigmaDauPz, - candidate.sigmaDecRadius, - candidate.sigmaCosPA, - candidate.chargePr, - candidate.pxPr, - candidate.pyPr, - candidate.pzPr, - candidate.nSigmaTPCPr, - candidate.nSigmaTOFPr, - pdgSigma, - pdgSigmaDau, - pdgPr, - sigmaPtGen, - prPtGen, - kStarGen); - } - } - } - } - PROCESS_SWITCH(sigmaProtonCorrTask, processSameEventMC, "Process Same event MC", false); - - void processMixedEventMC(const CollisionsFullMC& collisions, const aod::KinkCands& kinkCands, const TracksFullMC& tracks, const aod::McParticles&) - { - for (auto const& [collision1, collision2] : - selfCombinations(colBinning, nEvtMixingBkg, -1, collisions, collisions)) { - if (collision1.index() == collision2.index()) - continue; - - sigmaProtonCandidates.clear(); - if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) { - continue; - } - if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) { - continue; - } - auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c1 = tracks.sliceBy(tracksPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); - fillTreeAndHistograms(kinkCands_c1, tracks_c1, tracks_c2, collision1); - - if (fillOutputTree) { - // Fill output table - for (const auto& candidate : sigmaProtonCandidates) { - auto mcLabelSigma = tracks.rawIteratorAt(candidate.sigmaID); - auto mcLabelSigmaDau = tracks.rawIteratorAt(candidate.kinkDauID); - auto mcLabelPr = tracks.rawIteratorAt(candidate.prID); - - if (!mcLabelSigma.has_mcParticle() || !mcLabelSigmaDau.has_mcParticle() || !mcLabelPr.has_mcParticle()) { - continue; // Skip candidates where MC truth is not available - } - - auto mcPartSigma = mcLabelSigma.mcParticle_as(); - auto mcPartSigmaDau = mcLabelSigmaDau.mcParticle_as(); - auto mcPartPr = mcLabelPr.mcParticle_as(); - auto pdgSigma = mcPartSigma.pdgCode(); - auto pdgSigmaDau = mcLabelSigmaDau.has_mcParticle() ? mcPartSigmaDau.pdgCode() : -999; - auto pdgPr = mcLabelPr.has_mcParticle() ? mcPartPr.pdgCode() : -999; - float sigmaPtGen = std::hypot(mcPartSigma.px(), mcPartSigma.py()); - float prPtGen = std::hypot(mcPartPr.px(), mcPartPr.py()); - float kStarGen = getKStar(mcPartSigma.px(), mcPartSigma.py(), mcPartSigma.pz(), mcPartPr.px(), mcPartPr.py(), mcPartPr.pz()); - outputDataTableMC(candidate.sigmaCharge, - candidate.sigmaPx, - candidate.sigmaPy, - candidate.sigmaPz, - candidate.sigmaDauPx, - candidate.sigmaDauPy, - candidate.sigmaDauPz, - candidate.sigmaDecRadius, - candidate.sigmaCosPA, - candidate.chargePr, - candidate.pxPr, - candidate.pyPr, - candidate.pzPr, - candidate.nSigmaTPCPr, - candidate.nSigmaTOFPr, - pdgSigma, - pdgSigmaDau, - pdgPr, - sigmaPtGen, - prPtGen, - kStarGen); - } - } - } - LOG(debug) << "Processing mixed event MC"; - } - PROCESS_SWITCH(sigmaProtonCorrTask, processMixedEventMC, "Process Mixed event MC", false); -}; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx index 5c820ca6676..d6f8a6df09f 100644 --- a/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx @@ -343,6 +343,10 @@ struct HeavyionMultiplicity { histos.add("hMultEta05vsCentrRec", "multiplicity in eta<0.5 of selected MC events vs centrality", kTH2F, {axisCent, multAxis}); histos.add("hgendndetaVsMultEta05BeforeEvtSel", "hgendndetaBeforeEvtSel vs multiplicity in eta<0.5", kTH2F, {axisEta, multAxis}); histos.add("hgendndetaVsMultEta05AfterEvtSel", "hgendndetaAfterEvtSel vs multiplicity in eta<0.5", kTH2F, {axisEta, multAxis}); + histos.add("hImpactParameterSplit", "Impact parameter of selected and split MC events", kTH1F, {impactParAxis}); + histos.add("hMultEta05Split", "multiplicity in eta<0.5 of selected and split MC events", kTH1F, {multAxis}); + histos.add("hMultSplit", "multiplicity of selected and split MC events", kTH1F, {axisFt0cMult}); + histos.add("hMultvsCentrSplit", "multiplicity of selected and split MC events vs centrality ", kTH2F, {axisCent, axisFt0cMult}); histos.add("hMultGen", "multiplicity of generated MC events", kTH1F, {axisFt0cMult}); histos.add("hMultRec", "multiplicity of selected MC events", kTH1F, {axisFt0cMult}); @@ -462,8 +466,9 @@ struct HeavyionMultiplicity { auto cent = -1; if (isApplyCentFT0C) { cent = col.multMCFT0C(); - } - if (isApplyCentFV0A) { + } else if (isApplyCentFT0M) { + cent = (col.multMCFT0C() + col.multMCFT0A()) / 2.; + } else if (isApplyCentFV0A) { cent = col.multMCFV0A(); } return cent; @@ -990,6 +995,12 @@ struct HeavyionMultiplicity { if (std::abs(RecCol.posZ()) >= vtxRange) { continue; } + + histos.fill(HIST("hImpactParameterSplit"), mcCollision.impactParameter()); + histos.fill(HIST("hMultEta05Split"), mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hMultSplit"), selColMultMC(mcCollision)); + histos.fill(HIST("hMultvsCentrSplit"), selColCent(RecCol), selColMultMC(mcCollision)); + if (RecCol.numContrib() <= numcontributors) { continue; } else { diff --git a/PWGLF/Tasks/GlobalEventProperties/studyPnch.cxx b/PWGLF/Tasks/GlobalEventProperties/studyPnch.cxx index 394c54b74d5..d4ab4f132ac 100644 --- a/PWGLF/Tasks/GlobalEventProperties/studyPnch.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/studyPnch.cxx @@ -102,6 +102,7 @@ struct StudyPnch { Configurable isApplySameBunchPileup{"isApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; Configurable isApplyInelgt0{"isApplyInelgt0", false, "Enable INEL > 0 condition"}; Configurable isApplyExtraPhiCut{"isApplyExtraPhiCut", false, "Enable extra phi cut"}; + Configurable isApplyTVX{"isApplyTVX", false, "Enable TVX trigger sel"}; void init(InitContext const&) { @@ -125,7 +126,7 @@ struct StudyPnch { x->SetBinLabel(6, "INEL > 0"); x->SetBinLabel(7, "|vz| < 10"); - if (doprocessData || doprocessCorrelation || doprocessMonteCarlo || doprocessTreatedMonteCarlo) { + if (doprocessData || doprocessCorrelation || doprocessMonteCarlo) { histos.add("PhiVsEtaHist", "PhiVsEtaHist", kTH2F, {axisPhi, axisEta}, false); } if (doprocessData) { @@ -143,11 +144,6 @@ struct StudyPnch { histos.add("hMultiplicityMCgen", "hMultiplicityMCgen", kTH1F, {axisMult}, true); histos.add("hResponseMatrix", "hResponseMatrix", kTH2F, {axisMult, axisMult}, true); } - if (doprocessTreatedMonteCarlo) { - histos.add("hMultiplicityTreatMCrec", "hMultiplicityTreatMCrec", kTH1F, {axisMult}, true); - histos.add("hMultiplicityTreatMCgen", "hMultiplicityTreatMCgen", kTH1F, {axisMult}, true); - histos.add("hResponseMatrixTreat", "hResponseMatrixTreat", kTH2F, {axisMult, axisMult}, true); - } if (doprocessEvtLossSigLossMC) { histos.add("MCEventHist", "MCEventHist", kTH1F, {axisEvent}, false); auto hstat = histos.get(HIST("MCEventHist")); @@ -163,7 +159,7 @@ struct StudyPnch { bool isEventSelected(CheckCol const& col) { histos.fill(HIST("EventHist"), 1); - if (!col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + if (isApplyTVX && !col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { return false; } histos.fill(HIST("EventHist"), 2); @@ -282,6 +278,11 @@ struct StudyPnch { return nTrk; } + bool isINELgt0(auto nTrk) + { + return nTrk > 0; + } + Filter fTrackSelectionITS = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && ncheckbit(aod::track::trackCutFlag, TrackSelectionIts); Filter fTrackSelectionTPC = ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), @@ -295,7 +296,9 @@ struct StudyPnch { return; } auto mult = countNTracks(tracks); - histos.fill(HIST("hMultiplicityData"), mult); + if (isINELgt0(mult)) { + histos.fill(HIST("hMultiplicityData"), mult); + } } void processCorrelation(ColDataTable::iterator const& cols, FilTrackDataTable const& tracks) @@ -319,30 +322,14 @@ struct StudyPnch { } auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); auto multrec = countNTracksMcCol(recTracksPart, RecCol); - histos.fill(HIST("hMultiplicityMCrec"), multrec); - auto multgen = countGenTracks(GenParticles, mcCollision); - histos.fill(HIST("hMultiplicityMCgen"), multgen); - histos.fill(HIST("hResponseMatrix"), multrec, multgen); - } - } - - void processTreatedMonteCarlo(ColMCTrueTable::iterator const& mcCollision, ColMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) - { - // Count generated tracks at each iterator - auto multgen = countGenTracks(GenParticles, mcCollision); - histos.fill(HIST("hMultiplicityTreatMCgen"), multgen); - for (const auto& RecCol : RecCols) { - if (!isEventSelected(RecCol)) { - continue; + if (multrec > 0) { + histos.fill(HIST("hMultiplicityMCrec"), multrec); } - // Verify that the reconstructed collision corresponds to the given MC collision - if (RecCol.mcCollisionId() != mcCollision.globalIndex()) { - continue; + auto multgen = countGenTracks(GenParticles, mcCollision); + if (multgen > 0 && multrec > 0) { + histos.fill(HIST("hMultiplicityMCgen"), multgen); + histos.fill(HIST("hResponseMatrix"), multrec, multgen); } - auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); - auto multrec = countNTracksMcCol(recTracksPart, RecCol); - histos.fill(HIST("hMultiplicityTreatMCrec"), multrec); - histos.fill(HIST("hResponseMatrixTreat"), multrec, multgen); } } @@ -351,13 +338,18 @@ struct StudyPnch { if (isApplyInelgt0 && !mcCollision.isInelGt0()) { return; } + if (isApplyTVX && !(mcCollision.multMCFT0C() > 0 && mcCollision.multMCFT0A() > 0)) { + return; + } if (std::abs(mcCollision.posZ()) >= vtxRange) { return; } // All generated events histos.fill(HIST("MCEventHist"), 1); auto multAll = countGenTracks(GenParticles, mcCollision); - histos.fill(HIST("hMultiplicityMCgenAll"), multAll); + if (multAll > 0) { + histos.fill(HIST("hMultiplicityMCgenAll"), multAll); + } bool atLeastOne = false; auto numcontributors = -999; @@ -376,14 +368,15 @@ struct StudyPnch { if (atLeastOne) { histos.fill(HIST("MCEventHist"), 2); auto multSel = countGenTracks(GenParticles, mcCollision); - histos.fill(HIST("hMultiplicityMCgenSel"), multSel); + if (multSel > 0) { + histos.fill(HIST("hMultiplicityMCgenSel"), multSel); + } } } PROCESS_SWITCH(StudyPnch, processData, "process data CentFT0C", false); PROCESS_SWITCH(StudyPnch, processCorrelation, "do correlation study in data", false); PROCESS_SWITCH(StudyPnch, processMonteCarlo, "process MC CentFT0C", false); - PROCESS_SWITCH(StudyPnch, processTreatedMonteCarlo, "process Treated MC CentFT0C", false); PROCESS_SWITCH(StudyPnch, processEvtLossSigLossMC, "process Signal Loss, Event Loss", false); }; diff --git a/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx index c055f5c2e2c..b2576226bce 100644 --- a/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx +++ b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx @@ -128,8 +128,19 @@ struct ReducedParticle { } }; +// Jet Matching +struct JetMatching { + double distance; + double ptTrue; + double ptDiff; +}; + struct AntinucleiInJets { + // Random engine + std::mt19937 rng; + std::uniform_int_distribution generateRandomNr{0, 1}; + // Histogram registries for data, MC, quality control, multiplicity and correlations HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -144,7 +155,8 @@ struct AntinucleiInJets { Configurable isppRefAnalysis{"isppRefAnalysis", false, "Is ppRef analysis"}; Configurable cfgAreaFrac{"cfgAreaFrac", 0.6, "fraction of jet area"}; Configurable cfgEtaJetMax{"cfgEtaJetMax", 0.5, "max jet eta"}; - Configurable cfgMinPtTrack{"cfgMinPtTrack", 0.15, "minimum pt of tracks for jet reconstruction"}; + Configurable cfgMinPtTrack{"cfgMinPtTrack", 0.1, "minimum pt of tracks for jet reconstruction"}; + Configurable alpha{"alpha", 0.3, "parameter to control jet matching"}; // Event selection criteria Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "Reject events near the ITS ROF border"}; @@ -160,7 +172,7 @@ struct AntinucleiInJets { // Jet selection and event filtering parameters Configurable minJetPt{"minJetPt", 10.0, "Minimum pt of the jet after bkg subtraction"}; - Configurable maxJetPt{"maxJetPt", 1000.0, "Maximum pt of the jet after bkg subtraction"}; + Configurable maxJetPt{"maxJetPt", 1e+06, "Maximum pt of the jet after bkg subtraction"}; Configurable ptLeadingMin{"ptLeadingMin", 5.0, "pt Leading Min"}; Configurable rJet{"rJet", 0.4, "Jet resolution parameter R"}; Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; @@ -268,6 +280,9 @@ struct AntinucleiInJets { auto timeSeed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); mRand.SetSeed(timeSeed); + // Set seed of random engine + rng.seed(12345); + // Load reweighting histograms from CCDB if antinuclei efficiency processing is enabled if (doprocessAntinucleiEfficiency || doprocessJetsMCgen || doprocessJetsMCrec) { ccdb->setURL(urlToCcdb.value); @@ -381,6 +396,12 @@ struct AntinucleiInJets { registryMC.add("antiproton_gen_ue", "antiproton_gen_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); registryMC.add("antiproton_gen_full", "antiproton_gen_full", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + // Generated spectra of antiprotons for closure test + registryMC.add("antiproton_gen_jet_data", "antiproton_gen_jet_data", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_gen_ue_data", "antiproton_gen_ue_data", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_gen_jet_mc", "antiproton_gen_jet_mc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_gen_ue_mc", "antiproton_gen_ue_mc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + // Normalization histogram registryMC.add("antiproton_deltay_deltaphi_jet", "antiproton_deltay_deltaphi_jet", HistType::kTH2F, {{2000, -1.0, 1.0, "#Delta#it{y}"}, {2000, 0.0, 2.0, "#Delta#phi"}}); registryMC.add("antiproton_deltay_deltaphi_ue", "antiproton_deltay_deltaphi_ue", HistType::kTH2F, {{2000, -1.0, 1.0, "#Delta#it{y}"}, {2000, 0.0, 2.0, "#Delta#phi"}}); @@ -408,6 +429,16 @@ struct AntinucleiInJets { registryMC.add("antiproton_rec_tpc_full", "antiproton_rec_tpc_full", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); registryMC.add("antiproton_rec_tof_full", "antiproton_rec_tof_full", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + // Reconstructed spectra of antiprotons for closure test + registryMC.add("antiproton_rec_tpc_jet_data", "antiproton_rec_tpc_jet_data", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_jet_data", "antiproton_rec_tof_jet_data", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tpc_ue_data", "antiproton_rec_tpc_ue_data", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_ue_data", "antiproton_rec_tof_ue_data", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tpc_jet_mc", "antiproton_rec_tpc_jet_mc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_jet_mc", "antiproton_rec_tof_jet_mc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tpc_ue_mc", "antiproton_rec_tpc_ue_mc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_ue_mc", "antiproton_rec_tof_ue_mc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + // Fraction of primary antiprotons registryMC.add("antiproton_prim_jet", "antiproton_prim_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); registryMC.add("antiproton_incl_jet", "antiproton_incl_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); @@ -501,6 +532,11 @@ struct AntinucleiInJets { registryMC.add("antiproton_coal_ue", "antiproton_coal_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); } + // jet pt resolution + if (doprocessJetPtResolution) { + registryMC.add("jetPtResolution", "jet Pt Resolution", HistType::kTH2F, {{1000, 0, 100, "#it{p}^{jet}_{T,true} (GeV/#it{c})"}, {1000, -20, 20, "#Delta #it{p}^{jet}_{T} (GeV/#it{c})"}}); + } + // Coalescence and Correlation analysis if (doprocessCoalescenceCorr) { @@ -2031,6 +2067,10 @@ struct AntinucleiInJets { // Get particles in this MC collision const auto mcParticlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, collision.globalIndex()); + // Generate random number to decide if simulated event has to be considered as data or MC in the closure test + int sample = generateRandomNr(rng); + bool isPseudoData = (sample == 0); + // Loop over MC particles for (const auto& particle : mcParticlesThisMcColl) { @@ -2121,6 +2161,13 @@ struct AntinucleiInJets { // Fill histogram for generated antiprotons registryMC.fill(HIST("antiproton_gen_jet"), particle.pt(), weightJet); + // Fill histograms for generated antiprotons for closure test + if (isPseudoData) { + registryMC.fill(HIST("antiproton_gen_jet_data"), particle.pt()); + } else { + registryMC.fill(HIST("antiproton_gen_jet_mc"), particle.pt()); + } + // Fill 2d (pt,eta) distribution of antiprotons registryMC.fill(HIST("antiproton_eta_pt_jet"), particle.pt(), particle.eta(), weightJet); } @@ -2169,12 +2216,24 @@ struct AntinucleiInJets { // Fill histogram for antiprotons in the UE registryMC.fill(HIST("antiproton_gen_ue"), protonVec.Pt(), weightUe); + // Fill histograms for generated antiprotons for closure test + if (sample == 0) { + registryMC.fill(HIST("antiproton_gen_ue_data"), protonVec.Pt()); + } else { + registryMC.fill(HIST("antiproton_gen_ue_mc"), protonVec.Pt()); + } + // Fill 2d (pt,eta) distribution of antiprotons registryMC.fill(HIST("antiproton_eta_pt_ue"), protonVec.Pt(), protonVec.Eta(), weightUe); } } if (isAtLeastOneJetSelected) { registryMC.fill(HIST("genEvents"), 3.5); + if (isPseudoData) { + registryMC.fill(HIST("genEvents"), 4.5); + } else { + registryMC.fill(HIST("genEvents"), 5.5); + } } // Shrink large vectors @@ -2256,6 +2315,10 @@ struct AntinucleiInJets { // Get tracks in this MC collision const auto mcTracksThisMcColl = mcTracks.sliceBy(mcTracksPerMcCollision, collision.globalIndex()); + // Generate random number to decide if simulated event has to be considered as data or MC in the closure test + int sample = generateRandomNr(rng); + bool isPseudoData = (sample == 0); + // Loop over reconstructed tracks int id(-1); for (auto const& track : mcTracksThisMcColl) { @@ -2420,8 +2483,23 @@ struct AntinucleiInJets { // Fill histograms (TPC and TOF) only for selected candidates if (passedItsPidProt && nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { registryMC.fill(HIST("antiproton_rec_tpc_jet"), pt, weightJet); + + // Fill histograms for reconstructed antiprotons for closure test + if (isPseudoData) { + registryMC.fill(HIST("antiproton_rec_tpc_jet_data"), pt); + } else { + registryMC.fill(HIST("antiproton_rec_tpc_jet_mc"), pt); + } + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) { registryMC.fill(HIST("antiproton_rec_tof_jet"), pt, weightJet); + + // Fill histograms for reconstructed antiprotons for closure test + if (isPseudoData) { + registryMC.fill(HIST("antiproton_rec_tof_jet_data"), pt); + } else { + registryMC.fill(HIST("antiproton_rec_tof_jet_mc"), pt); + } } } } @@ -2502,14 +2580,34 @@ struct AntinucleiInJets { // Fill histograms (TPC and TOF) only for selected candidates if (passedItsPidProt && nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { registryMC.fill(HIST("antiproton_rec_tpc_ue"), pt, weightUe); + + // Fill histograms for reconstructed antiprotons for closure test + if (isPseudoData) { + registryMC.fill(HIST("antiproton_rec_tpc_ue_data"), pt); + } else { + registryMC.fill(HIST("antiproton_rec_tpc_ue_mc"), pt); + } + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) { registryMC.fill(HIST("antiproton_rec_tof_ue"), pt, weightUe); + + // Fill histograms for reconstructed antiprotons for closure test + if (isPseudoData) { + registryMC.fill(HIST("antiproton_rec_tof_ue_data"), pt); + } else { + registryMC.fill(HIST("antiproton_rec_tof_ue_mc"), pt); + } } } } } if (isAtLeastOneJetSelected) { registryMC.fill(HIST("recEvents"), 9.5); + if (isPseudoData) { + registryMC.fill(HIST("recEvents"), 10.5); + } else { + registryMC.fill(HIST("recEvents"), 11.5); + } } // Shrink large vectors @@ -3912,6 +4010,153 @@ struct AntinucleiInJets { } } PROCESS_SWITCH(AntinucleiInJets, processCoalescenceCorr, "process coalescence correlation", false); + + // Jet Pt resolution + void processJetPtResolution(RecCollisionsMc const& collisions, AntiNucleiTracksMc const& mcTracks, aod::McParticles const& mcParticles) + { + // Define per-event particle containers + std::vector fjParticles; + std::vector fjTracks; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over all reconstructed collisions + for (const auto& collision : collisions) { + + // Clear containers at the start of the event loop + fjParticles.clear(); + fjTracks.clear(); + + // Reject reconstructed collisions with no simulated collision + if (!collision.has_mcCollision()) + continue; + + // Apply event selection: require sel8 and vertex position to be within the allowed z range + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + + // Reject events near the ITS Read-Out Frame border + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + continue; + + // Reject events at the Time Frame border + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + continue; + + // Require at least one ITS-TPC matched track + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + continue; + + // Reject events with same-bunch pileup + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + continue; + + // Require consistent FT0 vs PV z-vertex + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + + // Require TOF match for at least one vertex track + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + continue; + + // Get tracks and particles in this MC collision + const auto mcTracksThisMcColl = mcTracks.sliceBy(mcTracksPerMcCollision, collision.globalIndex()); + const auto mcParticlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, collision.globalIndex()); + + // Loop over reconstructed tracks + for (auto const& track : mcTracksThisMcColl) { + + // Apply track selection for jet reconstruction + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(MassPionCharged)); + fjTracks.emplace_back(fourMomentum); + } + + // Loop over MC particles + for (const auto& particle : mcParticlesThisMcColl) { + + // Select physical primary particles or HF decay products + if (!isPhysicalPrimaryOrFromHF(particle, mcParticles)) + continue; + + // Select particles within acceptance + if (particle.eta() < minEta || particle.eta() > maxEta || particle.pt() < cfgMinPtTrack) + continue; + + // 4-momentum representation of a particle + double energy = std::sqrt(particle.p() * particle.p() + MassPionCharged * MassPionCharged); + fastjet::PseudoJet fourMomentum(particle.px(), particle.py(), particle.pz(), energy); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjTracks.empty() || fjParticles.empty()) + continue; + + // Cluster particles using the anti-kt algorithm + fastjet::ClusterSequenceArea csRec(fjTracks, jetDef, areaDef); + std::vector jetsRec = fastjet::sorted_by_pt(csRec.inclusive_jets()); + + fastjet::ClusterSequenceArea csGen(fjParticles, jetDef, areaDef); + std::vector jetsGen = fastjet::sorted_by_pt(csGen.inclusive_jets()); + + // Loop over reconstructed jets + std::vector jetGenRec; + for (const auto& jetRec : jetsRec) { + + // Jet must be fully contained in the acceptance + if ((std::fabs(jetRec.eta()) + rJet) > (maxEta - deltaEtaEdge)) + continue; + + // Apply area cut if required + if (applyAreaCut && (jetRec.area() / (PI * rJet * rJet)) > maxNormalizedJetArea) + continue; + + // Clear jet-pair container + jetGenRec.clear(); + + for (const auto& jetGen : jetsGen) { + + // Jet must be fully contained in the acceptance + if ((std::fabs(jetGen.eta()) + rJet) > (maxEta - deltaEtaEdge)) + continue; + + // Apply area cut if required + if (applyAreaCut && (jetGen.area() / (PI * rJet * rJet)) > maxNormalizedJetArea) + continue; + + double deltaEta = jetGen.eta() - jetRec.eta(); + double deltaPhi = getDeltaPhi(jetGen.phi(), jetRec.phi()); + double deltaR = std::sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi); + if (deltaR < rJet) + jetGenRec.push_back({deltaR, jetGen.pt(), jetGen.pt() - jetRec.pt()}); + } + if (jetGenRec.empty()) + continue; + + double distanceMin(1e+06); + double diffPt(0); + double ptJetTrue(0); + for (const auto& jetPair : jetGenRec) { + if (jetPair.distance < distanceMin) { + distanceMin = jetPair.distance; + diffPt = jetPair.ptDiff; + ptJetTrue = jetPair.ptTrue; + } + } + + if (distanceMin < alpha * rJet) { + registryMC.fill(HIST("jetPtResolution"), ptJetTrue, diffPt); + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processJetPtResolution, "process jet pt resolution", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx index 5ff943f2348..0966ad1a97d 100644 --- a/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx +++ b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx @@ -134,27 +134,37 @@ struct DedxPidAnalysis { // Track secondary lebel enum TrkSecCutLabel { AllSec = 1, - V0Type, V0CosPA, V0DecayRadius, V0Daughters, - TPCRefit, PhiVarCutSec, NClTPCFoundCutSec, NClTPCPIDCutSec, AllK0s, + SingleTrackSelectionK0s, + V0TypeK0s, + DCAtoVtxK0s, + Armenteros, V0RapidityK0s, V0ProperLifetimeK0s, MassCutK0s, AllLambda, + SingleTrackSelectionLambda, + V0TypeLambda, + DCAtoVtxLambda, V0RapidityLambda, V0ProperLifetimeLambda, MassCutLambda, AllAntiLambda, + SingleTrackSelectionAntiLambda, + V0TypeAntiLambda, + DCAtoVtxAntiLambda, V0RapidityAntiLambda, V0ProperLifetimeAntiLambda, MassCutAntiLambda, AllGamma, + SingleTrackSelectionGamma, + V0TypeGamma, V0RapidityGamma, MassCutGamma }; @@ -176,20 +186,26 @@ struct DedxPidAnalysis { Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; Configurable maxDCAz{"maxDCAz", 0.1f, "maxDCAz"}; // v0 cuts - Configurable v0cospaMin{"v0cospaMin", 0.998f, "Minimum V0 CosPA"}; - Configurable minimumV0Radius{"minimumV0Radius", 0.5f, + Configurable v0cospaMin{"v0cospaMin", 0.999f, "Minimum V0 CosPA"}; + Configurable minimumV0Radius{"minimumV0Radius", 1.2f, "Minimum V0 Radius"}; Configurable maximumV0Radius{"maximumV0Radius", 100.0f, "Maximum V0 Radius"}; Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum DCA Daughters"}; + Configurable dcaProtonsFromLambda{"dcaProtonsFromLambda", 0.05f, + "Minimum DCA of protons to vtx for Lambda"}; + Configurable dcaPionsFromLambda{"dcaPionsFromLambda", 0.2f, + "Minimum DCA of pions to vtx for Lambda"}; + Configurable dcaPionsFromK0s{"dcaPionsFromK0s", 0.1f, + "Minimum DCA of pions to vtx for K0s"}; Configurable v0rapidityCut{"v0rapidityCut", 0.5f, "V0 rapidity cut"}; Configurable v0ProperLifetimeCutK0s{"v0ProperLifetimeCutK0s", 20.f, "V0 proper lifetime cut for K0s"}; Configurable v0ProperLifetimeCutLambda{"v0ProperLifetimeCutLambda", 30.f, "V0 proper lifetime cut for Lambda"}; Configurable nsigmaTOFmax{"nsigmaTOFmax", 3.0f, "Maximum nsigma TOF"}; - Configurable invMassCutK0s{"invMassCutK0s", 0.2f, "invariant Mass Cut for K0s"}; - Configurable invMassCutLambda{"invMassCutLambda", 0.1f, "invariant Mass Cut for Lambda"}; - Configurable invMassCutGamma{"invMassCutGamma", 0.1f, "invariant Mass Cut for Gamma"}; + Configurable invMassCutK0s{"invMassCutK0s", 0.015f, "invariant Mass Cut for K0s"}; + Configurable invMassCutLambda{"invMassCutLambda", 0.015f, "invariant Mass Cut for Lambda"}; + Configurable invMassCutGamma{"invMassCutGamma", 0.015f, "invariant Mass Cut for Gamma"}; Configurable calibrationMode{"calibrationMode", false, "calibration mode"}; Configurable phiVarCut{"phiVarCut", true, "phi var cut"}; Configurable nClTPCFoundCut{"nClTPCFoundCut", false, "number of found clusters in TPC cut"}; @@ -200,11 +216,13 @@ struct DedxPidAnalysis { Configurable v0SelectionMode{"v0SelectionMode", 3, "V0 Selection base on TPC: 1, TOF:2 ,Both:3"}; Configurable momentumMode{"momentumMode", 2, "1: TPC inner param, 2: Total momentum p"}; Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable v0TypeSelectionGamma{"v0TypeSelectionGamma", 7, "select on a certain V0 type (leave negative if no selection desired)"}; Configurable multiplicityEstimator{"multiplicityEstimator", 9, "Flag to use a multiplicity estimator; No multiplicity: 0, MultFV0A: 1, MultFT0M: 2, MultFDDM: 3 ,MultTracklets: 4,MultTPC: 5,MultNTracksPV: 6 ,MultNTracksPVeta1: 7,CentralityFT0C: 8 ,CentralityFT0M: 9, CentralityFV0A: 10"}; Configurable lowParam1{"lowParam1", 0.119297, "First parameter for low phi cut"}; Configurable lowParam2{"lowParam2", 0.000379693, "Second parameter for low phi cut"}; Configurable highParam1{"highParam1", 0.16685, "First parameter for high phi cut"}; Configurable highParam2{"highParam2", 0.00981942, "Second parameter for high phi cut"}; + Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|"}; // Histograms names static constexpr std::string_view DedxvsMomentumPos[ParticlesType] = {"dEdx_vs_Momentum_all_Pos", "dEdx_vs_Momentum_Pi_v0_Pos", "dEdx_vs_Momentum_Pr_v0_Pos", "dEdx_vs_Momentum_El_v0_Pos"}; static constexpr std::string_view DedxvsMomentumNeg[ParticlesType] = {"dEdx_vs_Momentum_all_Neg", "dEdx_vs_Momentum_Pi_v0_Neg", "dEdx_vs_Momentum_Pr_v0_Neg", "dEdx_vs_Momentum_El_v0_Neg"}; @@ -648,34 +666,43 @@ struct DedxPidAnalysis { xAll->SetBinLabel(NClTPCPIDCutPri, "NClTPCPIDCutPri"); xAll->SetBinLabel(NClTPCFoundCutPri, "NClTPCFoundCutPri"); - registryDeDx.add("trackselSec", "track selected sec particles", HistType::kTH1F, {{24, 0.5, 24.5, ""}}); + registryDeDx.add("trackselSec", "track selected sec particles", HistType::kTH1F, {{34, 0.5, 34.5, ""}}); auto htrackSec = registryDeDx.get(HIST("trackselSec")); auto* xSec = htrackSec->GetXaxis(); xSec->SetBinLabel(AllSec, "AllSec"); - xSec->SetBinLabel(V0Type, "V0Type"); xSec->SetBinLabel(V0CosPA, "V0CosPA"); xSec->SetBinLabel(V0DecayRadius, "V0DecayRadius"); xSec->SetBinLabel(V0Daughters, "V0Daughters"); - xSec->SetBinLabel(TPCRefit, "TPCRefit"); xSec->SetBinLabel(PhiVarCutSec, "PhiVarCutSec"); xSec->SetBinLabel(NClTPCFoundCutSec, "NClTPCFoundCutSec"); xSec->SetBinLabel(NClTPCPIDCutSec, "NClTPCPIDCutSec"); xSec->SetBinLabel(AllK0s, "AllK0s"); + xSec->SetBinLabel(SingleTrackSelectionK0s, "SingleTrackSelectionK0s"); + xSec->SetBinLabel(V0TypeK0s, "V0TypeK0s"); + xSec->SetBinLabel(DCAtoVtxK0s, "DCAtoVtxK0s"); + xSec->SetBinLabel(Armenteros, "Armenteros"); xSec->SetBinLabel(V0RapidityK0s, "V0RapidityK0s"); xSec->SetBinLabel(V0ProperLifetimeK0s, "V0ProperLifetimeK0s"); xSec->SetBinLabel(MassCutK0s, "MassCutK0s"); xSec->SetBinLabel(AllLambda, "AllLambda"); + xSec->SetBinLabel(SingleTrackSelectionLambda, "SingleTrackSelectionLambda"); + xSec->SetBinLabel(V0TypeLambda, "V0TypeLambda"); + xSec->SetBinLabel(DCAtoVtxLambda, "DCAtoVtxLambda"); xSec->SetBinLabel(V0RapidityLambda, "V0RapidityLambda"); xSec->SetBinLabel(V0ProperLifetimeLambda, "V0ProperLifetimeLambda"); xSec->SetBinLabel(MassCutLambda, "MassCutLambda"); xSec->SetBinLabel(AllAntiLambda, "AllAntiLambda"); + xSec->SetBinLabel(SingleTrackSelectionAntiLambda, "SingleTrackSelectionAntiLambda"); + xSec->SetBinLabel(V0TypeAntiLambda, "V0TypeAntiLambda"); + xSec->SetBinLabel(DCAtoVtxAntiLambda, "DCAtoVtxAntiLambda"); xSec->SetBinLabel(V0RapidityAntiLambda, "V0RapidityAntiLambda"); xSec->SetBinLabel(V0ProperLifetimeAntiLambda, "V0ProperLifetimeAntiLambda"); xSec->SetBinLabel(MassCutAntiLambda, "MassCutAntiLambda"); xSec->SetBinLabel(AllGamma, "AllGamma"); + xSec->SetBinLabel(SingleTrackSelectionGamma, "SingleTrackSelectionGamma"); + xSec->SetBinLabel(V0TypeGamma, "V0TypeGamma"); xSec->SetBinLabel(V0RapidityGamma, "V0RapidityGamma"); xSec->SetBinLabel(MassCutGamma, "MassCutGamma"); - mySelectionPrim = myTrackSelection(); } @@ -684,12 +711,12 @@ struct DedxPidAnalysis { bool passedSingleTrackSelection(const T1& track, const C& /*collision*/) { // Single-Track Selections - if (!track.hasTPC()) - return false; + // if (!track.hasTPC()) + // return false; if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) return false; - if (track.tpcChi2NCl() > maxChi2TPC) - return false; + // if (track.tpcChi2NCl() > maxChi2TPC) + // return false; if (track.eta() < etaMin || track.eta() > etaMax) return false; @@ -727,12 +754,15 @@ struct DedxPidAnalysis { bool passedK0Selection(const T1& v0, const T2& ntrack, const T2& ptrack, const C& collision) { + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllK0s); // Single-Track Selections if (!passedSingleTrackSelection(ptrack, collision)) return false; if (!passedSingleTrackSelection(ntrack, collision)) return false; - double sigmap = 0.0; + /*double sigmap = 0.0; double sigman = 0.0; if (v0SelectionMode == V0TPC) { @@ -758,23 +788,39 @@ struct DedxPidAnalysis { return false; if (std::abs(sigman) > nsigmaTOFmax) return false; - } + }*/ if (fillHist) - registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllK0s); + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::SingleTrackSelectionK0s); + + if (v0.v0Type() != v0TypeSelection) // V0 type selection + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0TypeK0s); + + if (std::fabs(v0.dcapostopv()) < dcaPionsFromK0s) // DCA selection + return false; + if (std::fabs(v0.dcanegtopv()) < dcaPionsFromK0s) // DCA selection + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::DCAtoVtxK0s); + + if (armPodCut * v0.qtarm() < std::abs(v0.alpha())) // Armenteros-Podolanski cut + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::Armenteros); - if (std::abs(v0.yK0Short()) > v0rapidityCut) + if (std::abs(v0.yK0Short()) > v0rapidityCut) // Rapidity selection return false; if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityK0s); float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; - - if (properLifetime > v0ProperLifetimeCutK0s) + if (properLifetime > v0ProperLifetimeCutK0s) // Proper lifetime return false; if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeK0s); - if (std::abs(v0.mK0Short() - MassK0Short) > invMassCutK0s) + if (std::abs(v0.mK0Short() - MassK0Short) > invMassCutK0s) // Invarian mass return false; if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutK0s); @@ -787,13 +833,16 @@ struct DedxPidAnalysis { bool passedLambdaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, const C& collision) { + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllLambda); // Single-Track Selections if (!passedSingleTrackSelection(ptrack, collision)) return false; if (!passedSingleTrackSelection(ntrack, collision)) return false; - double sigmap = 0.0; + /*double sigmap = 0.0; double sigman = 0.0; if (v0SelectionMode == V0TPC) { @@ -819,26 +868,36 @@ struct DedxPidAnalysis { return false; if (std::abs(sigman) > nsigmaTOFmax) return false; - } + }*/ + if (fillHist) - registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllLambda); + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::SingleTrackSelectionLambda); - if (std::abs(v0.yLambda()) > v0rapidityCut) + if (v0.v0Type() != v0TypeSelection) // V0 type selection return false; if (fillHist) - registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityLambda); + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0TypeLambda); - float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda; + if (std::fabs(v0.dcapostopv()) < dcaProtonsFromLambda) // DCA selection + return false; + if (std::fabs(v0.dcanegtopv()) < dcaPionsFromLambda) // DCA selection + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::DCAtoVtxLambda); - if (properLifetime > v0ProperLifetimeCutLambda) + if (std::abs(v0.yLambda()) > v0rapidityCut) // Rapidity selection return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityLambda); + float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda; + if (properLifetime > v0ProperLifetimeCutLambda) // Proper lifetime + return false; if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeLambda); - if (std::abs(v0.mLambda() - MassLambda) > invMassCutLambda) { + if (std::abs(v0.mLambda() - MassLambda) > invMassCutLambda) // Invarian mass return false; - } if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutLambda); @@ -850,13 +909,15 @@ struct DedxPidAnalysis { bool passedAntiLambdaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, const C& collision) { + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllAntiLambda); // Single-Track Selections if (!passedSingleTrackSelection(ptrack, collision)) return false; if (!passedSingleTrackSelection(ntrack, collision)) return false; - double sigmap = 0.0; + /*double sigmap = 0.0; double sigman = 0.0; if (v0SelectionMode == V0TPC) { @@ -881,27 +942,37 @@ struct DedxPidAnalysis { return false; if (std::abs(sigman) > nsigmaTOFmax) return false; - } + }*/ + if (fillHist) - registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllAntiLambda); + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::SingleTrackSelectionAntiLambda); - if (std::abs(v0.yLambda()) > v0rapidityCut) + // Select V0 type + if (v0.v0Type() != v0TypeSelection) // V0 type selection return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0TypeAntiLambda); + + if (std::fabs(v0.dcapostopv()) < dcaPionsFromLambda) // DCA selection + return false; + if (std::fabs(v0.dcanegtopv()) < dcaProtonsFromLambda) // DCA selection + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::DCAtoVtxAntiLambda); + if (std::abs(v0.yLambda()) > v0rapidityCut) // Rapidity selection + return false; if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityAntiLambda); float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda; - - if (properLifetime > v0ProperLifetimeCutLambda) + if (properLifetime > v0ProperLifetimeCutLambda) // Proper lifetime return false; - if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeAntiLambda); - if (std::abs(v0.mAntiLambda() - MassLambda) > invMassCutLambda) + if (std::abs(v0.mAntiLambda() - MassLambda) > invMassCutLambda) // Invarian mass return false; - if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutAntiLambda); @@ -913,13 +984,16 @@ struct DedxPidAnalysis { bool passedGammaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, const C& collision) { + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllGamma); + // Single-Track Selections if (!passedSingleTrackSelection(ptrack, collision)) return false; if (!passedSingleTrackSelection(ntrack, collision)) return false; - double sigmap = 0.0; + /*double sigmap = 0.0; double sigman = 0.0; if (v0SelectionMode == V0TPC) { @@ -945,23 +1019,25 @@ struct DedxPidAnalysis { return false; if (std::abs(sigman) > nsigmaTOFmax) return false; - } + }*/ const float gammaMass = 2 * MassElectron; // GeV/c^2 if (fillHist) - registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllGamma); - - const float yGamma = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, MassGamma); + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::SingleTrackSelectionGamma); - if (std::abs(yGamma) > v0rapidityCut) + if (v0.v0Type() != v0TypeSelectionGamma) // V0 type selection return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0TypeGamma); + const float yGamma = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, MassGamma); + if (std::abs(yGamma) > v0rapidityCut) // Rapidity selection + return false; if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityGamma); - if (std::abs(v0.mGamma() - gammaMass) > invMassCutGamma) + if (std::abs(v0.mGamma() - gammaMass) > invMassCutGamma) // Invarian mass return false; - if (fillHist) registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutGamma); @@ -1539,12 +1615,6 @@ struct DedxPidAnalysis { // Standard V0 Selections registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllSec); - // Select V0 type - if (v0.v0Type() != v0TypeSelection) - continue; - - registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0Type); - if (!passedV0Selection(v0, collision)) { continue; } @@ -1553,13 +1623,13 @@ struct DedxPidAnalysis { const auto& posTrack = v0.posTrack_as(); const auto& negTrack = v0.negTrack_as(); - if (!posTrack.passedTPCRefit()) + /*if (!posTrack.passedTPCRefit()) continue; if (!negTrack.passedTPCRefit()) - continue; + continue;*/ - registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::TPCRefit); - // phi and Ncl cut + // registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::TPCRefit); + // phi and Ncl cut if (phiVarCut) { if (!passedPhiCutSecondaries(posTrack, magField, *fphiCutLow, *fphiCutHigh)) continue; diff --git a/PWGLF/Tasks/Nuspex/piKpRAA.cxx b/PWGLF/Tasks/Nuspex/piKpRAA.cxx index 9d046f974db..6dcabaea755 100644 --- a/PWGLF/Tasks/Nuspex/piKpRAA.cxx +++ b/PWGLF/Tasks/Nuspex/piKpRAA.cxx @@ -210,8 +210,14 @@ struct PiKpRAA { Configurable isNoCollInTimeRangeNarrow{"isNoCollInTimeRangeNarrow", false, "use isNoCollInTimeRangeNarrow?"}; Configurable isOccupancyCut{"isOccupancyCut", true, "Occupancy cut?"}; Configurable isCentSel{"isCentSel", true, "Centrality selection?"}; + Configurable selHasBC{"selHasBC", true, "Has BC?"}; Configurable selHasFT0{"selHasFT0", true, "Has FT0?"}; Configurable isT0Ccent{"isT0Ccent", true, "Use T0C-based centrality?"}; + + Configurable useSel8{"useSel8", false, "Use sel8?"}; + Configurable selTriggerTVX{"selTriggerTVX", true, "selTriggerTVX?"}; + Configurable selNoITSROFrameBorder{"selNoITSROFrameBorder", true, "selNoITSROFrameBorder?"}; + Configurable selNoTimeFrameBorder{"selNoTimeFrameBorder", true, "selNoTimeFrameBorder?"}; Configurable isZvtxPosSel{"isZvtxPosSel", true, "Zvtx position selection?"}; Configurable isZvtxPosSelMC{"isZvtxPosSelMC", true, "Zvtx position selection for MC events?"}; Configurable selTVXMC{"selTVXMC", true, "apply TVX selection in MC?"}; @@ -263,16 +269,22 @@ struct PiKpRAA { Configurable rctCheckZDC{"rctCheckZDC", false, "RCT flag to check whether the ZDC is present or not"}; Configurable rctTreatLimitedAcceptanceAsBad{"rctTreatLimitedAcceptanceAsBad", false, "RCT flag to reject events with limited acceptance for selected detectors"}; Configurable requireGoodRct{"requireGoodRct", true, "RCT flag to reject events with limited acceptance for selected detectors"}; - Configurable requireGoodPIDRct{"requireGoodPIDRct", true, "RCT flag to reject events with limited acceptance for selected detectors"}; + Configurable requireBCRct{"requireBCRct", true, "RCT flag to reject events with limited acceptance for selected detectors"}; // RCT Checker instance RCTFlagsChecker rctChecker; enum EvCutLabel { All = 1, + HasBC, + HasFT0, SelEigth, - NoSameBunchPileup, + SelTriggerTVX, + SelNoITSROFrameBorder, + SelNoTimeFrameBorder, + VtxZ, IsGoodZvtxFT0vsPV, + NoSameBunchPileup, NoCollInTimeRangeStrict, NoCollInTimeRangeStandard, NoCollInRofStrict, @@ -280,9 +292,7 @@ struct PiKpRAA { NoHighMultCollInPrevRof, NoCollInTimeRangeNarrow, OccuCut, - HasFT0, Centrality, - VtxZ, NchSel, INELgt0 }; @@ -379,7 +389,7 @@ struct PiKpRAA { // define axes you want to use const std::string titlePorPt{v0Selections.usePinPhiSelection ? "#it{p} (GeV/#it{c})" : "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec axisZpos{binsZpos, "Vtx_{z} (cm)"}; - const AxisSpec axisEvent{17, 0.5, 17.5, ""}; + const AxisSpec axisEvent{22, 0.5, 22.5, ""}; const AxisSpec axisNcl{161, -0.5, 160.5, "#it{N}_{cl} TPC"}; const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec axisPtV0s{binsPtV0s, "#it{p}_{T} (GeV/#it{c})"}; @@ -390,9 +400,13 @@ struct PiKpRAA { const char* latexEta[kNEtaHists] = {"-0.8<#eta<-0.6", "-0.6<#eta<-0.4", "-0.4<#eta<-0.2", "-0.2<#eta<0", "0<#eta<0.2", "0.2<#eta<0.4", "0.4<#eta<0.6", "0.6<#eta<0.8"}; registry.add("EventCounter", ";;Events", kTH1F, {axisEvent}); + registry.add("HasBCVsFT0VsTVXVsEvSel", "Alls=1 | BC=2 | FT0=3 | TVX=4 | EvSel=5;;", kTH1F, {{5, 0.5, 5.5}}); registry.add("zPos", "With Event Selection;;Entries;", kTH1F, {axisZpos}); registry.add("T0Ccent", ";;Entries", kTH1F, {axisCent}); + registry.add("RCTSel", "Event accepted if flag=false: All=1 | RTC sel=2;;;", kTH1F, {{2, 0.5, 2.5}}); + registry.add("T0CcentVsRCTSel", "Event accepted if flag=false;;RCT Status;", kTH2F, {{{axisCent}, {9, 0.5, 9.5}}}); registry.add("T0CcentVsFoundFT0", "Found(=1.5) NOT Found(=0.5);;Status;", kTH2F, {{{axisCent}, {2, 0, 2}}}); + registry.add("T0CcentVsBCVsFT0VsTVXVsEvSel", "All=1 | BC=2 | FT0=3 | TVX=4 | EvSel=5;;Status;", kTH2F, {{axisCent}, {5, 0.5, 5.5}}); registry.add("NchVsCent", "Measured Nch v.s. Centrality (At least Once Rec. Coll. + Sel. criteria);;Nch", kTH2F, {{axisCent, {nBinsNch, minNch, maxNch}}}); registry.add("NclVsEtaPID", ";#eta;Ncl used for PID", kTH2F, {{{axisEta}, {161, -0.5, 160.5}}}); registry.add("NclVsEtaPIDp", ";#eta;#LTNcl#GT used for PID", kTProfile, {axisEta}); @@ -402,24 +416,39 @@ struct PiKpRAA { auto hstat = registry.get(HIST("EventCounter")); auto* x = hstat->GetXaxis(); x->SetBinLabel(1, "All"); - x->SetBinLabel(2, "SelEigth"); - x->SetBinLabel(3, "NoSameBunchPileup"); - x->SetBinLabel(4, "GoodZvtxFT0vsPV"); - x->SetBinLabel(5, "NoCollInTimeRangeStrict"); - x->SetBinLabel(6, "NoCollInTimeRangeStandard"); - x->SetBinLabel(7, "NoCollInRofStrict"); - x->SetBinLabel(8, "NoCollInRofStandard"); - x->SetBinLabel(9, "NoHighMultCollInPrevRof"); - x->SetBinLabel(10, "NoCollInTimeRangeNarrow"); - x->SetBinLabel(11, "Occupancy Cut"); - x->SetBinLabel(12, "Has FT0?"); - x->SetBinLabel(13, "Cent. Sel."); - x->SetBinLabel(14, "VtxZ Sel."); - x->SetBinLabel(15, "Nch Sel."); - x->SetBinLabel(16, "INEL > 0"); + x->SetBinLabel(2, "Has BC?"); + x->SetBinLabel(3, "Has FT0?"); + x->SetBinLabel(4, "SelEigth"); + x->SetBinLabel(5, "SelTriggerTVX"); + x->SetBinLabel(6, "SelNoITSROFrameBorder"); + x->SetBinLabel(7, "SelNoTimeFrameBorder"); + x->SetBinLabel(8, "VtxZ Sel."); + x->SetBinLabel(9, "GoodZvtxFT0vsPV"); + x->SetBinLabel(10, "NoSameBunchPileup"); + x->SetBinLabel(11, "NoCollInTimeRangeStrict"); + x->SetBinLabel(12, "NoCollInTimeRangeStandard"); + x->SetBinLabel(13, "NoCollInRofStrict"); + x->SetBinLabel(14, "NoCollInRofStandard"); + x->SetBinLabel(15, "NoHighMultCollInPrevRof"); + x->SetBinLabel(16, "NoCollInTimeRangeNarrow"); + x->SetBinLabel(17, "Occupancy Cut"); + x->SetBinLabel(18, "Cent. Sel."); + x->SetBinLabel(19, "Nch Sel."); + x->SetBinLabel(20, "INEL > 0"); + + auto hrct = registry.get(HIST("T0CcentVsRCTSel")); + auto* y = hrct->GetYaxis(); + y->SetBinLabel(1, "All"); + y->SetBinLabel(2, "kFT0Bad"); + y->SetBinLabel(3, "kITSBad"); + y->SetBinLabel(4, "kITSLimAccMCRepr"); + y->SetBinLabel(5, "kTOFBad"); + y->SetBinLabel(6, "kTOFLimAccMCRepr"); + y->SetBinLabel(7, "kTPCBadTracking"); + y->SetBinLabel(8, "kTPCBadPID"); + y->SetBinLabel(9, "kTPCLimAccMCRepr"); if (doprocessCalibrationAndV0s) { - registry.add("T0CcentVsRCTSel", "Bad RCT(=0.5) Good RCT(=1.5) Good RCT & Good PID RCT(=2.5);;RCT Status;", kTH2F, {{{axisCent}, {3, 0, 3}}}); registry.add("NchVsNPV", ";Nch; NPV;", kTH2F, {{{nBinsNPV, minNpv, maxNpv}, {nBinsNch, minNch, maxNch}}}); registry.add("ExcludedEvtVsNch", ";Nch;Entries;", kTH1F, {{nBinsNch, minNch, maxNch}}); registry.add("ExcludedEvtVsNPV", ";NPV;Entries;", kTH1F, {{nBinsNPV, minNpv, maxNpv}}); @@ -574,6 +603,10 @@ struct PiKpRAA { registry.add("PtKaVsNchMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;Gen. Nch (|#eta|<0.8);", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); registry.add("PtPrVsNchMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;Gen. Nch (|#eta|<0.8);", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + registry.add("PtPiVsNchMC_WithRecoEvt_has_FT0_and_TVX", "Generated Events With at least One Rec. Collision;;Gen. Nch (|#eta|<0.8);", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + registry.add("PtKaVsNchMC_WithRecoEvt_has_FT0_and_TVX", "Generated Events With at least One Rec. Collision;;Gen. Nch (|#eta|<0.8);", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + registry.add("PtPrVsNchMC_WithRecoEvt_has_FT0_and_TVX", "Generated Events With at least One Rec. Collision;;Gen. Nch (|#eta|<0.8);", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + // Needed to calculate the denominator of the Signal Loss correction registry.add("PtPiVsNchMC_AllGen", "All Generated Events;;Gen. Nch (|#eta|<0.8);", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); registry.add("PtKaVsNchMC_AllGen", "All Generated Events;;Gen. Nch (|#eta|<0.8);", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); @@ -652,16 +685,52 @@ struct PiKpRAA { // Table's size: " << collisions.tableSize() << "\n"; // LOG(info) << "Run number: " << foundBC.runNumber() << "\n"; - if (!isEventSelected(collision)) { - return; - } - const auto& foundBC = collision.foundBC_as(); const uint64_t timeStamp{foundBC.timestamp()}; const int magField{getMagneticField(timeStamp)}; const double nPV{collision.multNTracksPVeta1() / 1.}; const float centrality{isT0Ccent ? collision.centFT0C() : collision.centFT0M()}; + // Apply RCT selection? + if (requireGoodRct) { + // Checks if collisions passes RCT selection + const bool isFT0Bad{requireBCRct ? foundBC.rct_bit(kFT0Bad) : collision.rct_bit(kFT0Bad)}; + const bool isITSBad{requireBCRct ? foundBC.rct_bit(kITSBad) : collision.rct_bit(kITSBad)}; + const bool isITSLimAcc{requireBCRct ? foundBC.rct_bit(kITSLimAccMCRepr) : collision.rct_bit(kITSLimAccMCRepr)}; + const bool isTOFBad{requireBCRct ? foundBC.rct_bit(kTOFBad) : collision.rct_bit(kTOFBad)}; + const bool isTOFLimAcc{requireBCRct ? foundBC.rct_bit(kTOFLimAccMCRepr) : collision.rct_bit(kTOFLimAccMCRepr)}; + const bool isTPCTrackingBad{requireBCRct ? foundBC.rct_bit(kTPCBadTracking) : collision.rct_bit(kTPCBadTracking)}; + const bool isTPCPIDBad{requireBCRct ? foundBC.rct_bit(kTPCBadPID) : collision.rct_bit(kTPCBadPID)}; + const bool isTPCLimAcc{requireBCRct ? foundBC.rct_bit(kTPCLimAccMCRepr) : collision.rct_bit(kTPCLimAccMCRepr)}; + + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 1.0); + if (!isFT0Bad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 2.0); + if (!isITSBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 3.0); + if (!isITSLimAcc) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 4.0); + if (!isTOFBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 5.0); + if (!isTOFLimAcc) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 6.0); + if (!isTPCTrackingBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 7.0); + if (!isTPCPIDBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 8.0); + if (!isTPCLimAcc) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 9.0); + + registry.fill(HIST("RCTSel"), 1.0); + if (!rctChecker(collision)) + return; + + registry.fill(HIST("RCTSel"), 2.0); + } + + if (!isEventSelected(collision)) + return; + //--------------------------- // Control histogram //--------------------------- @@ -670,23 +739,6 @@ struct PiKpRAA { } registry.fill(HIST("T0CcentVsFoundFT0"), centrality, 1.5); - // Apply RCT selection? - if (requireGoodRct) { - - // Checks if collisions passes RCT selection - if (!rctChecker(*collision)) { - registry.fill(HIST("T0CcentVsRCTSel"), centrality, 0.5); - return; - } - - registry.fill(HIST("T0CcentVsRCTSel"), centrality, 1.5); - // Checks if collisions passes good PID RCT status - if (requireGoodPIDRct && collision.rct_bit(kTPCBadPID)) { - return; - } - registry.fill(HIST("T0CcentVsRCTSel"), centrality, 2.5); - } - if (applyNchSel) { const int nextRunNumber{foundBC.runNumber()}; if (currentRunNumberNchSel != nextRunNumber) { @@ -1215,12 +1267,65 @@ struct PiKpRAA { } } - const auto& nRecColls{collisions.size()}; - registry.fill(HIST("NumberOfRecoCollisions"), nRecColls); + //--------------------------- + // All Generated events irrespective of whether there is an associated reconstructed collision + // Consequently, the centrality being a reconstructed quantity, might not always be available + // Therefore it is expressed as a function of the generated pT and the generated Nch in ∣eta∣ < 0.8 + // This is used for the denominator of the signal loss correction + // Also for MC closure: True Pt vs Generated Nch + //--------------------------- + for (const auto& particle : mcParticles) { + if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) + continue; + + if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) + continue; + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + bool isPrimary{true}; + if (!particle.isPhysicalPrimary()) + isPrimary = false; + + if (isPrimary) { + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMCEta08); + registry.fill(HIST("MCclosure_PtMCPiVsNchMC"), particle.pt(), nChMCEta08); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMCEta08); + registry.fill(HIST("MCclosure_PtMCKaVsNchMC"), particle.pt(), nChMCEta08); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMCEta08); + registry.fill(HIST("MCclosure_PtMCPrVsNchMC"), particle.pt(), nChMCEta08); + } else { + continue; + } + } + } // Loop over Generated Particles + + //--------------------------- + // This is used for the denominator of the event loss correction + //--------------------------- + registry.fill(HIST("NchMC_AllGen"), nChMCEta08); //--------------------------- // Only Generated evets with at least one reconstrued collision //--------------------------- + const auto& nRecColls{collisions.size()}; + registry.fill(HIST("NumberOfRecoCollisions"), nRecColls); + if (nRecColls > kZeroInt) { // Finds the collisions with the largest number of contributors @@ -1239,10 +1344,39 @@ struct PiKpRAA { bestCollisionIndex = collision.globalIndex(); } + if (selHasBC && !collision.has_foundBC()) + continue; + + if (selHasFT0 && !collision.has_foundFT0()) + continue; + + if (useSel8 && !collision.sel8()) + continue; + + // kIsTriggerTVX + if (selTriggerTVX && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) + continue; + + // kNoITSROFrameBorder + if (selNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + continue; + + // kNoTimeFrameBorder + if (selNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + continue; + + // Zvtx + if (isZvtxPosSel && std::fabs(collision.posZ()) > posZcut) + continue; + + if (selIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + + if (selNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + continue; + // Needed to calculate denominator of the Event Splitting correction - if (isEventSelected(collision)) { - registry.fill(HIST("Centrality_AllRecoEvt"), centrality); - } + registry.fill(HIST("Centrality_AllRecoEvt"), centrality); } //--------------------------- @@ -1253,21 +1387,11 @@ struct PiKpRAA { const float centrality{isT0Ccent ? collision.centFT0C() : collision.centFT0M()}; - //--------------------------- - // Reject collisions if has_foundFT0() returns false - //--------------------------- - if (selHasFT0 && !collision.has_foundFT0()) { - registry.fill(HIST("T0CcentVsFoundFT0"), centrality, 0.5); - continue; - } - registry.fill(HIST("T0CcentVsFoundFT0"), centrality, 1.5); - //--------------------------- // Pick the collisions with the largest number of contributors //--------------------------- - if (bestCollisionIndex != collision.globalIndex()) { + if (bestCollisionIndex != collision.globalIndex()) continue; - } // Needed to load the Phi selection from the CCDB const auto& foundBC = collision.foundBC_as(); @@ -1290,24 +1414,92 @@ struct PiKpRAA { //--------------------------- // Needed to construct the correlation between MC Nch v.s. centrality //--------------------------- - registry.fill(HIST("Centrality_WRecoEvt"), centrality); registry.fill(HIST("zPosMC"), mccollision.posZ()); + registry.fill(HIST("T0CcentVsBCVsFT0VsTVXVsEvSel"), centrality, 1.0); + registry.fill(HIST("HasBCVsFT0VsTVXVsEvSel"), 1.0); + + if (collision.has_foundBC()) { + registry.fill(HIST("T0CcentVsBCVsFT0VsTVXVsEvSel"), centrality, 2.0); + registry.fill(HIST("HasBCVsFT0VsTVXVsEvSel"), 2.0); + } + + if (collision.has_foundBC() && collision.has_foundFT0()) { + registry.fill(HIST("T0CcentVsBCVsFT0VsTVXVsEvSel"), centrality, 3.0); + registry.fill(HIST("HasBCVsFT0VsTVXVsEvSel"), 3.0); + } + + if (collision.has_foundBC() && collision.has_foundFT0() && collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST("T0CcentVsBCVsFT0VsTVXVsEvSel"), centrality, 4.0); + registry.fill(HIST("HasBCVsFT0VsTVXVsEvSel"), 4.0); + } + //--------------------------- - // Event selection - // for reconstructed collisions + // RCT Selection //--------------------------- - if (!isEventSelected(collision)) { - continue; + if (requireGoodRct) { + // Checks if collisions passes RCT selection + const bool isFT0Bad{requireBCRct ? foundBC.rct_bit(kFT0Bad) : collision.rct_bit(kFT0Bad)}; + const bool isITSBad{requireBCRct ? foundBC.rct_bit(kITSBad) : collision.rct_bit(kITSBad)}; + const bool isITSLimAcc{requireBCRct ? foundBC.rct_bit(kITSLimAccMCRepr) : collision.rct_bit(kITSLimAccMCRepr)}; + const bool isTOFBad{requireBCRct ? foundBC.rct_bit(kTOFBad) : collision.rct_bit(kTOFBad)}; + const bool isTOFLimAcc{requireBCRct ? foundBC.rct_bit(kTOFLimAccMCRepr) : collision.rct_bit(kTOFLimAccMCRepr)}; + const bool isTPCTrackingBad{requireBCRct ? foundBC.rct_bit(kTPCBadTracking) : collision.rct_bit(kTPCBadTracking)}; + const bool isTPCPIDBad{requireBCRct ? foundBC.rct_bit(kTPCBadPID) : collision.rct_bit(kTPCBadPID)}; + const bool isTPCLimAcc{requireBCRct ? foundBC.rct_bit(kTPCLimAccMCRepr) : collision.rct_bit(kTPCLimAccMCRepr)}; + + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 1.0); + if (!isFT0Bad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 2.0); + if (!isITSBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 3.0); + if (!isITSLimAcc) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 4.0); + if (!isTOFBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 5.0); + if (!isTOFLimAcc) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 6.0); + if (!isTPCTrackingBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 7.0); + if (!isTPCPIDBad) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 8.0); + if (!isTPCLimAcc) + registry.fill(HIST("T0CcentVsRCTSel"), centrality, 9.0); + + registry.fill(HIST("RCTSel"), 1.0); + if (!rctChecker(collision)) + return; + + registry.fill(HIST("RCTSel"), 2.0); } + //--------------------------- + // Event Selection + //--------------------------- + if (!isEventSelected(collision)) + return; + registry.fill(HIST("Centrality_WRecoEvtWSelCri"), centrality); registry.fill(HIST("NchMCVsCent"), centrality, nChMCEta08); registry.fill(HIST("NchMC_WithRecoEvt"), nChMCEta08); // Numerator of event loss correction registry.fill(HIST("zPos"), collision.posZ()); registry.fill(HIST("T0Ccent"), centrality); + //--------------------------- + // has_foundFT0() ? + //--------------------------- + + if (collision.has_foundBC() && collision.has_foundFT0() && collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST("T0CcentVsBCVsFT0VsTVXVsEvSel"), centrality, 5.0); + registry.fill(HIST("HasBCVsFT0VsTVXVsEvSel"), 5.0); + } + + if (collision.has_foundFT0()) + registry.fill(HIST("T0CcentVsFoundFT0"), centrality, 1.5); + else + registry.fill(HIST("T0CcentVsFoundFT0"), centrality, 0.5); + //--------------------------- // All Generated events with at least one associated reconstructed collision // The Generated events are not subjected to any selection criteria @@ -1355,6 +1547,47 @@ struct PiKpRAA { } } // Loop over generated particles per generated collision + // Generated events with FT0 information but not TVX triggered + if (selHasFT0 && collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + for (const auto& particle : mcParticles) { + if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) + continue; + + if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) + continue; + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + bool isPrimary{true}; + if (!particle.isPhysicalPrimary()) + isPrimary = false; + + if (isPrimary) { + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsNchMC_WithRecoEvt_has_FT0_and_TVX"), particle.pt(), nChMCEta08); // Numerator of signal loss + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsNchMC_WithRecoEvt_has_FT0_and_TVX"), particle.pt(), nChMCEta08); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsNchMC_WithRecoEvt_has_FT0_and_TVX"), particle.pt(), nChMCEta08); + } else { + continue; + } + } + } // Loop over generated particles per generated collision + } + const auto& groupedTracks{tracksMC.sliceBy(perCollision, collision.globalIndex())}; //--------------------------- @@ -1554,59 +1787,6 @@ struct PiKpRAA { registry.fill(HIST("NchVsCent"), centrality, nCh); } // Loop over Reco. Collisions: Only the collisions with the largest number of contributors } // If condition: Only simulated evets with at least one reconstrued collision - - //--------------------------- - // All Generated events irrespective of whether there is an associated reconstructed collision - // Consequently, the centrality being a reconstructed quantity, might not always be available - // Therefore it is expressed as a function of the generated pT and the generated Nch in ∣eta∣ < 0.8 - // This is used for the denominator of the signal loss correction - // Also for MC closure: True Pt vs Generated Nch - //--------------------------- - for (const auto& particle : mcParticles) { - if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) - continue; - - if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) - continue; - - auto charge{0.}; - // Get the MC particle - auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); - if (pdgParticle != nullptr) { - charge = pdgParticle->Charge(); - } else { - continue; - } - - // Is it a charged particle? - if (std::abs(charge) < kMinCharge) - continue; - - // Is it a primary particle? - bool isPrimary{true}; - if (!particle.isPhysicalPrimary()) - isPrimary = false; - - if (isPrimary) { - if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { - registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMCEta08); - registry.fill(HIST("MCclosure_PtMCPiVsNchMC"), particle.pt(), nChMCEta08); - } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { - registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMCEta08); - registry.fill(HIST("MCclosure_PtMCKaVsNchMC"), particle.pt(), nChMCEta08); - } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { - registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMCEta08); - registry.fill(HIST("MCclosure_PtMCPrVsNchMC"), particle.pt(), nChMCEta08); - } else { - continue; - } - } - } // Loop over Generated Particles - - //--------------------------- - // This is used for the denominator of the event loss correction - //--------------------------- - registry.fill(HIST("NchMC_AllGen"), nChMCEta08); } PROCESS_SWITCH(PiKpRAA, processSim, "Process Sim", false); @@ -1979,16 +2159,60 @@ struct PiKpRAA { bool isEventSelected(CheckCol const& col) { registry.fill(HIST("EventCounter"), EvCutLabel::All); - if (!col.sel8()) { - return false; + + // Has BC? + if (selHasBC) { + if (!col.has_foundBC()) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::HasBC); } - registry.fill(HIST("EventCounter"), EvCutLabel::SelEigth); - if (selNoSameBunchPileup) { - if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // Has FT0 information? + if (selHasFT0) { + if (!col.has_foundFT0()) { return false; } - registry.fill(HIST("EventCounter"), EvCutLabel::NoSameBunchPileup); + registry.fill(HIST("EventCounter"), EvCutLabel::HasFT0); + } + + if (useSel8) { + if (!col.sel8()) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::SelEigth); + } + + // kIsTriggerTVX + if (selTriggerTVX) { + if (!col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::SelTriggerTVX); + } + + // kNoITSROFrameBorder + if (selNoITSROFrameBorder) { + if (!col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::SelNoITSROFrameBorder); + } + + // kNoTimeFrameBorder + if (selNoTimeFrameBorder) { + if (!col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::SelNoTimeFrameBorder); + } + + // Zvtx + if (isZvtxPosSel) { + if (std::fabs(col.posZ()) > posZcut) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::VtxZ); } if (selIsGoodZvtxFT0vsPV) { @@ -1998,6 +2222,13 @@ struct PiKpRAA { registry.fill(HIST("EventCounter"), EvCutLabel::IsGoodZvtxFT0vsPV); } + if (selNoSameBunchPileup) { + if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::NoSameBunchPileup); + } + if (isNoCollInTimeRangeStrict) { if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { return false; @@ -2050,13 +2281,6 @@ struct PiKpRAA { registry.fill(HIST("EventCounter"), EvCutLabel::OccuCut); } - if (selHasFT0) { - if (!col.has_foundFT0()) { - return false; - } - registry.fill(HIST("EventCounter"), EvCutLabel::HasFT0); - } - if (isCentSel) { if (col.centFT0C() < minT0CcentCut || col.centFT0C() > maxT0CcentCut) { return false; @@ -2064,13 +2288,6 @@ struct PiKpRAA { registry.fill(HIST("EventCounter"), EvCutLabel::Centrality); } - if (isZvtxPosSel) { - if (std::fabs(col.posZ()) > posZcut) { - return false; - } - registry.fill(HIST("EventCounter"), EvCutLabel::VtxZ); - } - if (selINELgt0) { if (!col.isInelGt0()) { return false; diff --git a/PWGLF/Tasks/Nuspex/spectraTOF.cxx b/PWGLF/Tasks/Nuspex/spectraTOF.cxx index b2ff348c7a7..8c49a9595dd 100644 --- a/PWGLF/Tasks/Nuspex/spectraTOF.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTOF.cxx @@ -96,7 +96,7 @@ static constexpr float DcaPhiPtMax = 1.1f; static constexpr int kD0 = 421; // Spectra task -struct SpectraTOF { +struct tofSpectra { struct : ConfigurableGroup { Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; Configurable cfgINELCut{"cfgINELCut", 0, "INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1"}; @@ -877,7 +877,7 @@ struct SpectraTOF { histos.fill(HIST("Mult/PerBC/sel8/FT0AvsFT0C"), ft0.sumAmpA(), ft0.sumAmpC()); } // end of the process function - PROCESS_SWITCH(SpectraTOF, processBC, "Processor of BCs for the FT0 calibration", true); + PROCESS_SWITCH(tofSpectra, processBC, "Processor of BCs for the FT0 calibration", true); template void fillParticleHistos(const T& track, const C& collision) @@ -1619,7 +1619,7 @@ struct SpectraTOF { } } } - PROCESS_SWITCH(SpectraTOF, processMCclosure, "MC closure test", false); + PROCESS_SWITCH(tofSpectra, processMCclosure, "MC closure test", false); void processOccupancy(CollisionCandidates::iterator const& collision, soa::Join spPerCol = aod::spectra::collisionId; SliceCache cacheTrk; @@ -1759,7 +1759,7 @@ struct SpectraTOF { } } } // end of the process function - PROCESS_SWITCH(SpectraTOF, processDerived, "Derived data processor", false); + PROCESS_SWITCH(tofSpectra, processDerived, "Derived data processor", false); #define MAKE_PROCESS_FUNCTION(processorName, inputPid, particleId, isFull, tofTable, tpcTable) \ void process##processorName##inputPid(CollisionCandidates::iterator const& collision, \ @@ -1777,7 +1777,7 @@ struct SpectraTOF { fillParticleHistos(track, collision); \ } \ } \ - PROCESS_SWITCH(SpectraTOF, process##processorName##inputPid, Form("Process for the %s hypothesis from %s tables", #particleId, #processorName), false); + PROCESS_SWITCH(tofSpectra, process##processorName##inputPid, Form("Process for the %s hypothesis from %s tables", #particleId, #processorName), false); // Full tables #define MAKE_PROCESS_FUNCTION_FULL(inputPid, particleId) MAKE_PROCESS_FUNCTION(Full, inputPid, particleId, true, TOFFull, TPCFull) @@ -2700,7 +2700,7 @@ struct SpectraTOF { } } } - PROCESS_SWITCH(SpectraTOF, processMC, "Process MC", false); + PROCESS_SWITCH(tofSpectra, processMC, "Process MC", false); void processMCgen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { @@ -2732,7 +2732,7 @@ struct SpectraTOF { } } } - PROCESS_SWITCH(SpectraTOF, processMCgen, "process generated MC", false); + PROCESS_SWITCH(tofSpectra, processMCgen, "process generated MC", false); void processMCgenRecoEvs(soa::Join const& tracks, @@ -2831,7 +2831,7 @@ struct SpectraTOF { } } } - PROCESS_SWITCH(SpectraTOF, processMCgenRecoEvs, "process generated MC (reconstructed events)", false); + PROCESS_SWITCH(tofSpectra, processMCgenRecoEvs, "process generated MC (reconstructed events)", false); void processTrackMCLabels(CollisionCandidates::iterator const& collisions, soa::Join(cfgc)}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/CMakeLists.txt b/PWGLF/Tasks/Resonances/CMakeLists.txt index e4bc31fc311..e129ce85dcf 100644 --- a/PWGLF/Tasks/Resonances/CMakeLists.txt +++ b/PWGLF/Tasks/Resonances/CMakeLists.txt @@ -254,8 +254,13 @@ o2physics_add_dpl_workflow(kstarinoo PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phioo - SOURCES phiOO.cxx +o2physics_add_dpl_workflow(kstar0analysis + SOURCES kstar0analysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(phi1020analysis + SOURCES phi1020analysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -268,30 +273,37 @@ o2physics_add_dpl_workflow(phispectrapbpbqa SOURCES phispectrapbpbqa.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phi-1020-spherocity-analysis SOURCES phi1020SpherocityAnalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phitutorial SOURCES phitutorial.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(phitutorial-step0 + +o2physics_add_dpl_workflow(phitutorial-step0 SOURCES phitutorial_step0.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phitutorial-step1 SOURCES phitutorial_step1.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phitutorial-step2 SOURCES phitutorial_step2.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phitutorial-step3 SOURCES phitutorial_step3.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(k892hadronphoton SOURCES k892hadronphoton.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB diff --git a/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx b/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx index e09cdfde1a4..eb563fd9970 100644 --- a/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx +++ b/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx @@ -44,6 +44,7 @@ #include #include #include +#include #include using namespace o2; @@ -140,86 +141,94 @@ struct f1protoncorrelation { // ------------------------- void buildSystematicCuts() { - // choices from your table/picture - const std::array optDcaxy{0.01f, 0.03f}; - const std::array optDcaz{0.01f, 0.03f}; - const std::array optNcrs{90, 100}; - const std::array optNcls{90, 100}; - - const std::array optCPA{0.99f, 0.995f}; - const std::array optRad{0.8f, 1.0f}; - const std::array optDcaDD{0.9f, 0.8f}; - const std::array optDcaV0{0.2f, 0.15f}; - const std::array optLife{16.f, 18.f}; - const std::array optDcaD1{0.06f, 0.08f}; - const std::array optDcaD2{0.06f, 0.08f}; - - // bit layout: - // primary: 4 bits (0..3) - // v0: 7 bits (4..10) - // pid: 3 bits (11..13) - // total: 14 bits -> 16384 combos - auto buildFromMask = [&](uint32_t m) -> SysCuts { + // 3 options per cut: index 0 = DEFAULT, index 1/2 = variations + // Fill these with the exact values you want (I used your def as index 0 + your old options as 1/2) + const std::array optDcaxy{0.05f, 0.01f, 0.03f}; + const std::array optDcaz{0.05f, 0.01f, 0.03f}; + const std::array optNcrs{80, 90, 100}; + const std::array optNcls{80, 90, 100}; + + const std::array optCPA{0.985f, 0.99f, 0.995f}; + const std::array optRad{0.50f, 0.80f, 1.00f}; + const std::array optDcaDD{1.00f, 0.90f, 0.80f}; + const std::array optDcaV0{0.30f, 0.20f, 0.15f}; + const std::array optLife{20.f, 16.f, 18.f}; + const std::array optDcaD1{0.05f, 0.06f, 0.08f}; + const std::array optDcaD2{0.05f, 0.06f, 0.08f}; + + // PID modes: also allow default (0) to appear in random variations + const std::array optPidPi{0, 1, 2}; + const std::array optPidK{0, 1, 2}; + const std::array optPidP{0, 1, 2}; + + // Helper: build SysCuts from chosen indices (0..2) + auto buildFromIdx = [&](int i0, int i1, int i2, int i3, + int i4, int i5, int i6, int i7, int i8, int i9, int i10, + int i11, int i12, int i13) -> SysCuts { SysCuts c{}; - c.maxDcaxy = optDcaxy[(m >> 0) & 1u]; - c.maxDcaz = optDcaz[(m >> 1) & 1u]; - c.minTPCCrossedRows = optNcrs[(m >> 2) & 1u]; - c.minTPCClusters = optNcls[(m >> 3) & 1u]; - - c.minCPA = optCPA[(m >> 4) & 1u]; - c.minRadius = optRad[(m >> 5) & 1u]; - c.maxDcaDaughters = optDcaDD[(m >> 6) & 1u]; - c.maxDcaV0 = optDcaV0[(m >> 7) & 1u]; - c.maxLifetime = optLife[(m >> 8) & 1u]; - c.minDcaD1 = optDcaD1[(m >> 9) & 1u]; - c.minDcaD2 = optDcaD2[(m >> 10) & 1u]; - - c.pidPi = (m >> 11) & 1u; - c.pidK = (m >> 12) & 1u; - c.pidP = (m >> 13) & 1u; + c.maxDcaxy = optDcaxy[i0]; + c.maxDcaz = optDcaz[i1]; + c.minTPCCrossedRows = optNcrs[i2]; + c.minTPCClusters = optNcls[i3]; + + c.minCPA = optCPA[i4]; + c.minRadius = optRad[i5]; + c.maxDcaDaughters = optDcaDD[i6]; + c.maxDcaV0 = optDcaV0[i7]; + c.maxLifetime = optLife[i8]; + c.minDcaD1 = optDcaD1[i9]; + c.minDcaD2 = optDcaD2[i10]; + + c.pidPi = optPidPi[i11]; + c.pidK = optPidK[i12]; + c.pidP = optPidP[i13]; return c; }; - // DEFAULT (sysId=0): set to your baseline - SysCuts def{}; - def.maxDcaxy = 0.05f; - def.maxDcaz = 0.05f; - def.minTPCCrossedRows = 80; - def.minTPCClusters = 80; - - def.minCPA = 0.985f; - def.minRadius = 0.5f; - def.maxDcaDaughters = 1.0f; - def.maxDcaV0 = 0.3f; - def.maxLifetime = 20.f; - def.minDcaD1 = 0.05f; - def.minDcaD2 = 0.05f; - - def.pidPi = 0; - def.pidK = 0; - def.pidP = 0; - - std::vector masks; - masks.reserve(16384); - for (uint32_t m = 0; m < 16384; ++m) { - masks.push_back(m); - } + // sysId=0 must be strict default (all indices = 0) + SysCuts def = buildFromIdx(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); std::mt19937 rng(sysSeed); - std::shuffle(masks.begin(), masks.end(), rng); + std::uniform_int_distribution pick012(0, 2); + + // Optional: keep unique combinations (by packing indices in 2 bits each) + auto packCode = [&](const std::array& idx) -> uint32_t { + uint32_t code = 0u; + for (int k = 0; k < 14; ++k) { + code |= (uint32_t(idx[k] & 0x3) << (2 * k)); + } + return code; + }; sysCuts.clear(); - sysCuts.reserve(1 + nSysRand); - sysCuts.push_back(def); + sysCuts.reserve(1 + (size_t)nSysRand); + sysCuts.push_back(def); // sysId=0 + + std::unordered_set used; + used.reserve((size_t)nSysRand * 2); + used.insert(0u); // all-default code + + const int nPick = std::max(0, (int)nSysRand); + while ((int)sysCuts.size() < 1 + nPick) { - const int nPick = std::min(nSysRand, (int)masks.size()); - for (int i = 0, picked = 0; picked < nPick && i < (int)masks.size(); ++i) { - if (masks[i] == 0u) { // avoid trivial mask that can reproduce default + std::array idx{}; + for (int k = 0; k < 14; ++k) + idx[k] = pick012(rng); + + uint32_t code = packCode(idx); + if (!used.insert(code).second) + continue; // already have this combination + + // (optional) avoid generating exactly default again + if (code == 0u) continue; - } - sysCuts.push_back(buildFromMask(masks[i])); - ++picked; + + sysCuts.push_back(buildFromIdx( + idx[0], idx[1], idx[2], idx[3], + idx[4], idx[5], idx[6], idx[7], idx[8], idx[9], idx[10], + idx[11], idx[12], idx[13])); } + nSysTotal = (int)sysCuts.size(); } @@ -283,9 +292,9 @@ struct f1protoncorrelation { if (f1track.f1d1TOFHit() != 1) { return (std::abs(nsTPC) < cutNoTOF); } - - const float comb = std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF); - return (comb < cutWithTOF); + return (std::abs(nsTPC) < cutNoTOF && std::abs(nsTOF) < cutWithTOF); + // const float comb = std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF); + // return (comb < cutWithTOF); } inline bool passKaonPID(int pidMode, const aod::F1Tracks::iterator& f1track, @@ -331,10 +340,10 @@ struct f1protoncorrelation { } return true; } - + return (std::abs(nsTPC) < cutNoTOFBase && std::abs(nsTOF) < cutWithTOF); // --- TOF available: circular cut in (TPC,TOF) nσ plane - const float comb = std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF); - return (comb < cutWithTOF); + // const float comb = std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF); + // return (comb < cutWithTOF); } inline bool passProtonPID(int pidMode, const aod::ProtonTracks::iterator& ptrack, @@ -370,8 +379,9 @@ struct f1protoncorrelation { // circular cut in (TPC,TOF) const float nsTPC = ptrack.protonNsigmaTPC(); const float nsTOF = ptrack.protonNsigmaTOF(); - const float comb = std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF); - return (comb < cutCircle); + return (std::abs(nsTPC) < cutTPC && std::abs(nsTOF) < cutCircle); + // const float comb = std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF); + // return (comb < cutCircle); } // Initialize the ananlysis task @@ -598,10 +608,10 @@ struct f1protoncorrelation { } auto relative_momentum = getkstar(F1, Proton); if (relative_momentum <= 0.5) { - histos.fill(HIST("hNsigmaProtonTPC"), protontrack.protonNsigmaTPC(), Proton.Pt()); + histos.fill(HIST("hNsigmaProtonTPC"), protontrack.protonNsigmaTPC(), protontrack.protonNsigmaTOF(), Proton.Pt()); } histos.fill(HIST("h2SameEventPtCorrelation"), relative_momentum, F1.Pt(), Proton.Pt()); - + auto mT = getmT(F1, Proton); if (f1track.f1SignalStat() > 0) { // check charge float pairCharge = f1track.f1SignalStat() * protontrack.protonCharge(); @@ -616,7 +626,9 @@ struct f1protoncorrelation { histos.fill(HIST("hPhaseSpaceProtonKaonSame"), Proton.Eta() - Kaon.Eta(), PhiAtSpecificRadiiTPC(Proton, Kaon, protontrack.protonCharge(), kaonCharge, bz, bz), relative_momentum); // Phase Space Proton kaon if (pionCharge == protontrack.protonCharge()) histos.fill(HIST("hPhaseSpaceProtonPionSame"), Proton.Eta() - Pion.Eta(), PhiAtSpecificRadiiTPC(Proton, Pion, protontrack.protonCharge(), pionCharge, bz, bz), relative_momentum); // Phase Space Proton Pionsyst - histos.fill(HIST("h2SameEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M(), pairCharge, collision.numContrib()); // F1 sign = 1 unlike, F1 sign = -1 like + + histos.fill(HIST("h2SameEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M(), pairCharge, collision.numContrib()); // F1 sign = 1 unlike, F1 sign = -1 like + histos.fill(HIST("h2SameEventInvariantMassUnlike_mass_SYS"), 0, relative_momentum, mT, F1.M(), collision.numContrib()); if (fillSparse) { histos.fill(HIST("SEMassUnlike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC, pairCharge); } @@ -642,6 +654,7 @@ struct f1protoncorrelation { } } if (f1track.f1SignalStat() == -1) { + histos.fill(HIST("h2SameEventInvariantMassLike_mass_SYS"), 0, relative_momentum, mT, F1.M(), collision.numContrib()); histos.fill(HIST("h2SameEventInvariantMassLike_mass"), relative_momentum, F1.Pt(), F1.M(), protontrack.protonCharge(), collision.numContrib()); if (fillSparse) { histos.fill(HIST("SEMassLike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC, protontrack.protonCharge()); @@ -887,6 +900,7 @@ struct f1protoncorrelation { continue; } auto relative_momentum = getkstar(F1, Proton); + auto mT = getmT(F1, Proton); if (t1.f1SignalStat() > 0) { float pairCharge = t1.f1SignalStat() * t2.protonCharge(); int f1Charge = t1.f1SignalStat(); @@ -896,6 +910,7 @@ struct f1protoncorrelation { pionCharge = 1; kaonCharge = -1; } + histos.fill(HIST("h2MixEventInvariantMassUnlike_mass_SYS"), 0, relative_momentum, mT, F1.M(), collision1.numContrib()); histos.fill(HIST("h2MixEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M(), pairCharge, collision1.numContrib()); // F1 sign = 1 unlike, F1 sign = -1 like histos.fill(HIST("hPhaseSpaceProtonKaonMix"), Proton.Eta() - Kaon.Eta(), PhiAtSpecificRadiiTPC(Proton, Kaon, t2.protonCharge(), kaonCharge, bz, bz2), relative_momentum); // Phase Space Proton kaon histos.fill(HIST("hPhaseSpaceProtonPionMix"), Proton.Eta() - Pion.Eta(), PhiAtSpecificRadiiTPC(Proton, Pion, t2.protonCharge(), pionCharge, bz, bz2), relative_momentum); // Phase Space Proton Pion @@ -927,6 +942,7 @@ struct f1protoncorrelation { } } if (t1.f1SignalStat() == -1) { + histos.fill(HIST("h2MixEventInvariantMassLike_mass_SYS"), 0, relative_momentum, mT, F1.M(), collision1.numContrib()); histos.fill(HIST("h2MixEventInvariantMassLike_mass"), relative_momentum, F1.Pt(), F1.M(), t2.protonCharge(), collision1.numContrib()); if (fillSparse) { histos.fill(HIST("MEMassLike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC, t2.protonCharge()); @@ -968,7 +984,8 @@ struct f1protoncorrelation { Kaon.SetXYZM(f1track.f1d2Px(), f1track.f1d2Py(), f1track.f1d2Pz(), 0.493); Kshort.SetXYZM(f1track.f1d3Px(), f1track.f1d3Py(), f1track.f1d3Pz(), 0.497); KaonKshortPair = Kaon + Kshort; - + if (F1.Pt() < lowPtF1 || F1.Pt() > 50.0) + continue; std::vector activeSys; activeSys.reserve((size_t)nSysTotal); @@ -1014,7 +1031,7 @@ struct f1protoncorrelation { const auto& sc0 = sysCuts[0]; - if (countf1 && passPrimary(protontrack.protonDcaxy(), protontrack.protonDcaz(), protontrack.protonTPCNcrs(), protontrack.protonTPCNcls(), sc0)) { + if (countf1 && passPrimary(protontrack.protonDcaxy(), protontrack.protonDcaz(), protontrack.protonTPCNcrs(), protontrack.protonTPCNcls(), sc0) && passProtonPID(0, protontrack, Proton, pMinP, pMaxP, pTofP)) { histos.fill(HIST("hNsigmaProtonTPC"), protontrack.protonNsigmaTPC(), protontrack.protonNsigmaTOF(), Proton.Pt()); } @@ -1110,6 +1127,8 @@ struct f1protoncorrelation { Kshort.SetXYZM(t1.f1d3Px(), t1.f1d3Py(), t1.f1d3Pz(), 0.497); KaonKshortPair = Kaon + Kshort; Proton.SetXYZM(t2.protonPx(), t2.protonPy(), t2.protonPz(), 0.938); + if (F1.Pt() < lowPtF1 || F1.Pt() > 50.0) + continue; auto relative_momentum = getkstar(F1, Proton); auto mT = getmT(F1, Proton); // sys list for this (F1, p) pair diff --git a/PWGLF/Tasks/Resonances/heptaquark.cxx b/PWGLF/Tasks/Resonances/heptaquark.cxx index f7c30a46ddf..824c39601ac 100644 --- a/PWGLF/Tasks/Resonances/heptaquark.cxx +++ b/PWGLF/Tasks/Resonances/heptaquark.cxx @@ -68,6 +68,7 @@ struct heptaquark { Configurable cfgSoftFraction{"cfgSoftFraction", 0.01, "Minimum allowed softest fraction"}; Configurable cfgCollinear{"cfgCollinear", 0.98, "Maximum allowed collinear selection"}; + Configurable cfgCosPoint{"cfgCosPoint", 0.95, "Minimum pointing angle selection"}; ConfigurableAxis massAxis{"massAxis", {600, 2.8, 3.4}, "Invariant mass axis"}; ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "Transverse momentum bins"}; @@ -97,6 +98,18 @@ struct heptaquark { histos.add("hDalitzRot", "hDalitzRot", {HistType::kTHnSparseF, {massPPAxis, massPLAxis, massAxis, ptAxis, {2, -0.5f, 1.5f}, centAxis}}); } + template + static inline TLorentzVector makeP4FromHQRow(HQRow const& hq) + { + const double px = hq.hqPx(); + const double py = hq.hqPy(); + const double pz = hq.hqPz(); + const double m = hq.hqMass(); + TLorentzVector v; + v.SetXYZM(px, py, pz, m); + return v; + } + double massLambda = o2::constants::physics::MassLambda; double massPr = o2::constants::physics::MassProton; double massPi = o2::constants::physics::MassPionCharged; @@ -185,37 +198,52 @@ struct heptaquark { return false; } - template - int selectHQ(HQ1 const& hq1, HQ2 const& hq2, HQ3 const& hq3) + template + int selectHQ(HQRow1 const& hq1r, HQRow2 const& hq2r, HQRow3 const& hq3r, ColRow const& col) { int selection = 0; - if (hq1.Pt() < cfgMinPhiPt || hq2.Pt() < cfgMinPhiPt || hq3.Pt() < cfgMinLambdaPt) + + auto hq1 = makeP4FromHQRow(hq1r); + auto hq2 = makeP4FromHQRow(hq2r); + auto hq3 = makeP4FromHQRow(hq3r); + + if (hq1.Pt() < cfgMinPhiPt || hq2.Pt() < cfgMinPhiPt || hq3.Pt() < cfgMinLambdaPt) { selection += 1; + } - double sumE = hq1.E() + hq2.E() + hq3.E(); - double emin = std::min({hq1.E(), hq2.E(), hq3.E()}); - double fmin = emin / std::max(1e-9, sumE); - if (fmin < cfgSoftFraction) + const double sumE = hq1.E() + hq2.E() + hq3.E(); + const double emin = std::min({hq1.E(), hq2.E(), hq3.E()}); + const double fmin = emin / std::max(1e-9, sumE); + if (fmin < cfgSoftFraction) { selection += 2; + } auto ex = hq1 + hq2 + hq3; TVector3 boost = -ex.BoostVector(); + auto hqphipair_boost = hq1 + hq2; auto hqlambda_boost = hq3; hqphipair_boost.Boost(boost); hqlambda_boost.Boost(boost); - double cosHel = hqlambda_boost.Vect().Dot(hqphipair_boost.Vect()) / (hqlambda_boost.Vect().Mag() * hqphipair_boost.Vect().Mag()); - if (std::abs(cosHel) > cfgCollinear) + + const double denom = (hqlambda_boost.Vect().Mag() * hqphipair_boost.Vect().Mag()); + const double cosHel = (denom > 0.) ? (hqlambda_boost.Vect().Dot(hqphipair_boost.Vect()) / denom) : 1.0; + if (std::abs(cosHel) > cfgCollinear) { selection += 4; - /* - ROOT::Math::XYZVector rPV(col.posX(), col.posY(), col.posZ()); - ROOT::Math::XYZVector rSV(hq3.hqx(), hq3.hqy(), hq3.hqz()); - ROOT::Math::XYZVector L = rSV - rPV; - ROOT::Math::XYZVector exMom(ex.Px(), ex.Py(), ex.Pz()); - double cosPoint = L.Dot(exMom) / (L.R() * pEx.R() + 1e-9); - if (cosPoint < cfgCosPoint) - return 8; - */ + } + + ROOT::Math::XYZVector rPV(col.posX(), col.posY(), col.posZ()); + ROOT::Math::XYZVector rSV(hq3r.hqx(), hq3r.hqy(), hq3r.hqz()); + + ROOT::Math::XYZVector L = rSV - rPV; + ROOT::Math::XYZVector exMom(ex.Px(), ex.Py(), ex.Pz()); + + const double denom2 = (L.R() * exMom.R() + 1e-9); + const double cosPoint = L.Dot(exMom) / denom2; + if (cosPoint < cfgCosPoint) { + selection += 8; + } + return selection; } @@ -344,7 +372,7 @@ struct heptaquark { HQ12 = HQ1 + HQ2; HQ13 = HQ1 + HQ3; - if (cfgSelectHQ && selectHQ(HQ1, HQ2, HQ3)) + if (cfgSelectHQ && selectHQ(hqtrackd1, hqtrackd2, hqtrackd3, collision)) continue; histos.fill(HIST("h_InvMass_same"), exotic.M(), exotic.Pt(), collision.centrality()); diff --git a/PWGLF/Tasks/Resonances/k1analysis.cxx b/PWGLF/Tasks/Resonances/k1analysis.cxx index a743c349c51..02ac98be89b 100644 --- a/PWGLF/Tasks/Resonances/k1analysis.cxx +++ b/PWGLF/Tasks/Resonances/k1analysis.cxx @@ -13,23 +13,67 @@ /// \brief Reconstruction of track-track decay resonance candidates /// /// -/// \author Bong-Hwi Lim - -#include "PWGLF/DataModel/LFResonanceTables.h" - +/// \author Su-Jeong Ji , Bong-Hwi Lim + +#include +#include +#include +#include +#include +#include +#include +#include +// #include // FIXME +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/collisionCuts.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" - +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" #include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" #include "Framework/runDataProcessing.h" - -#include // FIXME -#include +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/RotationZ.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TParticlePDG.h" +#include "TRandom3.h" +#include "TVector2.h" +#include #include // FIXME +#include +#include +#include +#include +#include +#include +#include #include using namespace o2; @@ -37,693 +81,1019 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::constants::physics; +using namespace o2::constants::math; +using namespace o2::aod::rctsel; -struct k1analysis { - enum binAnti : unsigned int { - kNormal = 0, - kAnti, - kNAEnd - }; - enum binType : unsigned int { +struct K1analysis { + enum BinType : unsigned int { kK1P = 0, - kK1N, - kK1P_Mix, - kK1N_Mix, - kK1P_GenINEL10, - kK1N_GenINEL10, - kK1P_GenINELgt10, - kK1N_GenINELgt10, - kK1P_GenTrig10, - kK1N_GenTrig10, - kK1P_GenEvtSel, - kK1N_GenEvtSel, - kK1P_Rec, - kK1N_Rec, + kK1A, + kK1P_Like, + kK1A_Like, + kK1P_Rot, + kK1A_Rot, kTYEnd }; + + enum EvtStep { + kAll = 0, + kZvtx, + kINELgt0, + kAssocReco, + kNSteps + }; + + enum class K1MassRegion : uint8_t { + Outside = 0, + Signal, + SBLeft, + SBRight + }; + + const int nSteps = static_cast(EvtStep::kNSteps); + SliceCache cache; - Preslice perRCol = aod::resodaughter::resoCollisionId; Preslice perCollision = aod::track::collisionId; + // Preslice perCollisionV0 = aod::v0data::collisionId; + Preslice perCollisionV0 = aod::v0data::collisionId; + Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; + + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0Candidates = aod::V0Datas; + + // for MC reco + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Join; //, aod::McParticles>; + using MCV0Candidates = soa::Join; + + // for MC truth + using MCTrueEventCandidates = aod::McCollisions; + using MCTrueTrackCandidates = aod::McParticles; + + using LorentzVectorSetXYZM = ROOT::Math::LorentzVector>; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - using ResoMCCols = soa::Join; - - ///// Configurables - Configurable cNbinsDiv{"cNbinsDiv", 1, "Integer to divide the number of bins"}; - /// Event Mixing - Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; - ConfigurableAxis CfgVtxBins{"CfgVtxBins", {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 CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; - /// Pre-selection cuts - Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; - - /// DCA Selections - // DCAr to PV - Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.1, "Track DCAr cut to PV Maximum"}; - // DCAz to PV - Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 0.1, "Track DCAz cut to PV Maximum"}; - Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; - - /// PID Selections - Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC - Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF - Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; // Combined - Configurable cTOFVeto{"cTOFVeto", true, "TOF Veto, if false, TOF is nessessary for PID selection"}; // TOF Veto - Configurable cUseOnlyTOFTrackPi{"cUseOnlyTOFTrackPi", false, "Use only TOF track for PID selection"}; // Use only TOF track for Pion PID selection - // Kaon - Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC - Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF - Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", -999, "Combined nSigma cut for Kaon"}; // Combined - Configurable cUseOnlyTOFTrackKa{"cUseOnlyTOFTrackKa", false, "Use only TOF track for PID selection"}; // Use only TOF track for Kaon PID selection + + Service ccdb; + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + } CCDBConfig; + // Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + + // Configurables + struct : ConfigurableGroup { + ConfigurableAxis cfgBinsPt{"cfgBinsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsPtQA{"cfgBinsPtQA", {VARIABLE_WIDTH, 0.0, 0.3, 0.6, 1.2, 1.8, 2.4, 3.0, 3.6, 4.2, 4.8, 5.4, 6.0, 7.0, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsCent{"cfgBinsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 70.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis cfgBinsVtxZ{"cfgBinsVtxZ", {VARIABLE_WIDTH, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "Binning of the z-vertex axis"}; + Configurable cNbinsDiv{"cNbinsDiv", 1, "Integer to divide the number of bins"}; + Configurable cNbinsDivQA{"cNbinsDivQA", 1, "Integer to divide the number of bins for QA"}; + } AxisConfig; + + /// Event cuts + o2::analysis::CollisonCuts colCuts; + struct : ConfigurableGroup { + Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable cfgEvtOccupancyInTimeRangeMax{"cfgEvtOccupancyInTimeRangeMax", -1, "Evt sel: maximum track occupancy"}; + Configurable cfgEvtOccupancyInTimeRangeMin{"cfgEvtOccupancyInTimeRangeMin", -1, "Evt sel: minimum track occupancy"}; + Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; + Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", false, "Evt sel: check for offline selection"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", true, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", true, "Evt sel: apply TF border cut"}; + Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", false, "Evt sel: apply Z-vertex time difference"}; + Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", false, "Evt sel: apply pileup rejection"}; + Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", true, "Evt sel: apply NoITSRO border cut"}; + Configurable cfgincludeCentralityMC{"cfgincludeCentralityMC", false, "Include centrality in MC"}; + Configurable cfgEvtCollInTimeRangeStandard{"cfgEvtCollInTimeRangeStandard", false, "Evt sel: apply NoCollInTimeRangeStandard"}; + Configurable cfgEventCentralityMin{"cfgEventCentralityMin", 0.0f, "Event sel: minimum centrality"}; + Configurable cfgEventCentralityMax{"cfgEventCentralityMax", 100.0f, "Event sel: maximum centrality"}; + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } EventCuts; + RCTFlagsChecker rctChecker; + + Configurable cfgFillQAPlots{"cfgFillQAPlots", true, "Fill QA plots"}; + Configurable cfgCentEst{"cfgCentEst", 2, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + /// PID Selections, pion + struct : ConfigurableGroup { + Configurable cfgTPConly{"cfgTPConly", true, "Use only TPC for PID"}; // bool + Configurable cfgMaxTPCnSigmaPion{"cfgMaxTPCnSigmaPion", 5.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cfgMaxTOFnSigmaPion{"cfgMaxTOFnSigmaPion", 5.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cfgNsigmaCutCombinedPion{"cfgNsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; // Combined + Configurable cfgTOFVeto{"cfgTOFVeto", false, "TOF Veto, if false, TOF is nessessary for PID selection"}; // TOF Veto + Configurable cfgTOFMinPt{"cfgTOFMinPt", 0.6, "Minimum TOF pT cut for Pion"}; // TOF pT cut + } PIDCuts; + // Track selections - Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz - Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) - Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz - Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor - Configurable additionalQAplots{"additionalQAplots", true, "Additional QA plots"}; - Configurable tof_at_high_pt{"tof_at_high_pt", false, "Use TOF at high pT"}; - Configurable additionalEvsel{"additionalEvsel", true, "Additional event selcection"}; - Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; - Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; - Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; - Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; - - // Secondary selection - Configurable cfgModeK892orRho{"cfgModeK892orRho", true, "Secondary scenario for K892 (true) or Rho (false)"}; - Configurable cSecondaryMasswindow{"cSecondaryMasswindow", 0.1, "Secondary inv mass selection window"}; - Configurable cMinAnotherSecondaryMassCut{"cMinAnotherSecondaryMassCut", 0, "Min inv. mass selection of another secondary scenario"}; - Configurable cMaxAnotherSecondaryMassCut{"cMaxAnotherSecondaryMassCut", 999, "MAx inv. mass selection of another secondary scenario"}; - Configurable cMinPiKaMassCut{"cMinPiKaMassCut", 0, "bPion-Kaon pair inv mass selection minimum"}; - Configurable cMaxPiKaMassCut{"cMaxPiKaMassCut", 999, "bPion-Kaon pair inv mass selection maximum"}; - Configurable cMinAngle{"cMinAngle", 0, "Minimum angle between K(892)0 and bachelor pion"}; - Configurable cMaxAngle{"cMaxAngle", 4, "Maximum angle between K(892)0 and bachelor pion"}; - Configurable cMinPairAsym{"cMinPairAsym", -1, "Minimum pair asymmetry"}; - Configurable cMaxPairAsym{"cMaxPairAsym", 1, "Maximum pair asymmetry"}; + struct : ConfigurableGroup { + Configurable cfgMinPtcut{"cfgMinPtcut", 0.15, "Track minium pt cut"}; + Configurable cfgMaxEtacut{"cfgMaxEtacut", 0.8, "Track maximum eta cut"}; + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + + Configurable cfgpTdepDCAxyCut{"cfgpTdepDCAxyCut", true, "pT-dependent DCAxy cut"}; + Configurable cfgpTdepDCAzCut{"cfgpTdepDCAzCut", true, "pT-dependent DCAz cut"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.0f, "TPC Crossed Rows to Findable Clusters"}; + Configurable cfgITSChi2NCl{"cfgITSChi2NCl", 999.0, "ITS Chi2/NCl"}; + Configurable cfgTPCChi2NCl{"cfgTPCChi2NCl", 999.0, "TPC Chi2/NCl"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasITS{"cfgHasITS", false, "Require ITS"}; + Configurable cfgHasTPC{"cfgHasTPC", false, "Require TPC"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + // DCAr to PV + Configurable cfgMaxbDCArToPVcut{"cfgMaxbDCArToPVcut", 0.1, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cfgMaxbDCAzToPVcut{"cfgMaxbDCAzToPVcut", 0.1, "Track DCAz cut to PV Maximum"}; + } TrackCuts; + + // Secondary Selection + struct : ConfigurableGroup { + Configurable cfgReturnFlag{"cfgReturnFlag", false, "Return Flag for debugging"}; + Configurable cfgSecondaryRequire{"cfgSecondaryRequire", true, "Secondary cuts on/off"}; + Configurable cfgSecondaryArmenterosCut{"cfgSecondaryArmenterosCut", true, "cut on Armenteros-Podolanski graph"}; + Configurable cfgSecondaryCrossMassHypothesisCut{"cfgSecondaryCrossMassHypothesisCut", false, "Apply cut based on the lambda mass hypothesis"}; + + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass Daughters PID selection"}; + Configurable cfgSecondaryDauDCAMax{"cfgSecondaryDauDCAMax", 1., "Maximum DCA Secondary daughters to PV"}; + Configurable cfgSecondaryDauPosDCAtoPVMin{"cfgSecondaryDauPosDCAtoPVMin", 0.1, "Minimum DCA Secondary positive daughters to PV"}; + Configurable cfgSecondaryDauNegDCAtoPVMin{"cfgSecondaryDauNegDCAtoPVMin", 0.1, "Minimum DCA Secondary negative daughters to PV"}; + + Configurable cfgSecondaryPtMin{"cfgSecondaryPtMin", 0.f, "Minimum transverse momentum of Secondary"}; + Configurable cfgSecondaryRapidityMax{"cfgSecondaryRapidityMax", 0.8, "Maximum rapidity of Secondary"}; + Configurable cfgSecondaryRadiusMin{"cfgSecondaryRadiusMin", 0, "Minimum transverse radius of Secondary"}; + Configurable cfgSecondaryRadiusMax{"cfgSecondaryRadiusMax", 999.9, "Maximum transverse radius of Secondary"}; + Configurable cfgSecondaryCosPAMin{"cfgSecondaryCosPAMin", 0.995, "Mininum cosine pointing angle of Secondary"}; + Configurable cfgSecondaryDCAtoPVMax{"cfgSecondaryDCAtoPVMax", 0.4, "Maximum DCA Secondary to PV"}; + Configurable cfgSecondaryProperLifetimeMax{"cfgSecondaryProperLifetimeMax", 20, "Maximum Secondary Lifetime"}; + Configurable cfgSecondaryparamArmenterosCut{"cfgSecondaryparamArmenterosCut", 0.2, "parameter for Armenteros Cut"}; + Configurable cfgSecondaryMassWindow{"cfgSecondaryMassWindow", 0.03, "Secondary inv mass selciton window"}; + Configurable cfgSecondaryCrossMassCutWindow{"cfgSecondaryCrossMassCutWindow", 0.05, "Secondary inv mass selection window with (anti)lambda hypothesis"}; + } SecondaryCuts; + + // K* selection + struct : ConfigurableGroup { + Configurable cfgKstarMinPt{"cfgKstarMinPt", 0.0, "Kstar minimum pT"}; + Configurable cfgKstarMaxRap{"cfgKstarMaxRap", 0.5, "Kstar maximum rapidity"}; + Configurable cfgKstarMinRap{"cfgKstarMinRap", -0.5, "Kstar minimum rapidity"}; + Configurable cfgKstarMassWindow{"cfgKstarMassWindow", 0.05, "Kstar inv mass selection window"}; + } KstarCuts; // K1 selection - Configurable cK1MaxRap{"cK1MaxRap", 0.5, "K1 maximum rapidity"}; - Configurable cK1MinRap{"cK1MinRap", -0.5, "K1 minimum rapidity"}; + struct : ConfigurableGroup { + Configurable cfgK1MinPt{"cfgK1MinPt", 0.0, "K1 minimum pT"}; + Configurable cfgK1MaxRap{"cfgK1MaxRap", 0.5, "K1 maximum rapidity"}; + Configurable cfgK1MinRap{"cfgK1MinRap", -0.5, "K1 minimum rapidity"}; + } K1Cuts; + + // Bkg estimation + struct : ConfigurableGroup { + Configurable cfgFillRotBkg{"cfgFillRotBkg", true, "Fill rotated background"}; + Configurable cfgMinRot{"cfgMinRot", 5.0 * constants::math::PI / 6.0, "Minimum of rotation"}; + Configurable cfgMaxRot{"cfgMaxRot", 7.0 * constants::math::PI / 6.0, "Maximum of rotation"}; + Configurable cfgRotPion{"cfgRotPion", true, "Rotate pion"}; + Configurable cfgNrotBkg{"cfgNrotBkg", 4, "Number of rotated copies (background) per each original candidate"}; + } BkgEstimationConfig; + + Configurable cfgTruthUseInelGt0{"cfgTruthUseInelGt0", true, "Truth denominator: require INEL>0"}; + Configurable cfgTruthIncludeZvtx{"cfgTruthIncludeZvtx", true, "Truth denominator: also require |vtxz| cfgHasPair{"cfgHasPair", true, "Check the existence of pairs"}; + Configurable cfgPiPiMinPt{"cfgPiPiMinPt", 0.5, "bachelor pion and secondary pion minimum pT cut"}; + + float lCentrality; + + // PDG code + int kPDGK0s = kK0Short; + int kPDGK0 = kK0; + int kPDGKstarPlus = o2::constants::physics::Pdg::kKPlusStar892; + int kPDGPiPlus = kPiPlus; + int kPDGK10 = 10313; + double fMaxPosPV = 1e-2; void init(o2::framework::InitContext&) { - std::vector centBinning = {0., 1., 5., 10., 15., 20., 25., 30., 35., 40., 45., 50., 55., 60., 65., 70., 80., 90., 100., 200.}; - AxisSpec centAxis = {centBinning, "T0M (%)"}; - AxisSpec ptAxis = {150, 0, 15, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec dcaxyAxis = {300, 0, 3, "DCA_{#it{xy}} (cm)"}; - AxisSpec dcazAxis = {500, 0, 5, "DCA_{#it{xy}} (cm)"}; - AxisSpec invMassAxisK892 = {1400 / cNbinsDiv, 0.6, 2.0, "Invariant Mass (GeV/#it{c}^2)"}; // K(892)0 - AxisSpec invMassAxisRho = {2000 / cNbinsDiv, 0.0, 2.0, "Invariant Mass (GeV/#it{c}^2)"}; // rho - AxisSpec invMassAxisReso = {1600 / cNbinsDiv, 0.9f, 2.5f, "Invariant Mass (GeV/#it{c}^2)"}; // K1 - AxisSpec invMassAxisScan = {250, 0, 2.5, "Invariant Mass (GeV/#it{c}^2)"}; // For selection - AxisSpec pidQAAxis = {130, -6.5, 6.5}; - AxisSpec dataTypeAxis = {9, 0, 9, "Histogram types"}; - AxisSpec mcTypeAxis = {4, 0, 4, "Histogram types"}; + lCentrality = -999; + + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, /*checkRun3*/ true, EventCuts.cfgEvtTriggerTVXSel, EventCuts.cfgEvtOccupancyInTimeRangeMax, EventCuts.cfgEvtOccupancyInTimeRangeMin); + colCuts.init(&histos); + colCuts.setTriggerTVX(EventCuts.cfgEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(EventCuts.cfgEvtTFBorderCut); + colCuts.setApplyNoITSROBorderCut(EventCuts.cfgEvtNoITSROBorderCut); + colCuts.setApplyITSTPCvertex(EventCuts.cfgEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(EventCuts.cfgEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(EventCuts.cfgEvtPileupRejection); + colCuts.setApplyCollInTimeRangeStandard(EventCuts.cfgEvtCollInTimeRangeStandard); + colCuts.printCuts(); + + rctChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, EventCuts.cfgEvtRCTFlagCheckerZDCCheck, EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + AxisSpec centAxis = {AxisConfig.cfgBinsCent, "T0M (%)"}; + AxisSpec vtxzAxis = {AxisConfig.cfgBinsVtxZ, "Z Vertex (cm)"}; + AxisSpec ptAxis = {AxisConfig.cfgBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {AxisConfig.cfgBinsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec radiusAxis = {50, 0, 5, "Radius (cm)"}; + AxisSpec cpaAxis = {50, 0.95, 1.0, "CPA"}; + AxisSpec tauAxis = {250, 0, 25, "Lifetime (cm)"}; + AxisSpec dcaAxis = {200, 0, 2, "DCA (cm)"}; + AxisSpec dcaxyAxis = {200, 0, 2, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {200, 0, 2, "DCA_{#it{z}} (cm)"}; + AxisSpec yAxis = {100, -1, 1, "Rapidity"}; + AxisSpec invMassAxisK0s = {800 / AxisConfig.cNbinsDiv, 0.46, 0.54, "Invariant Mass (GeV/#it{c}^2)"}; // K0s ~497.611 + AxisSpec invMassAxisChk892 = {900 / AxisConfig.cNbinsDiv, 0.5f, 1.4f, "Invariant Mass (GeV/#it{c}^2)"}; // chK(892) ~892 + AxisSpec invMassAxisReso = {1600 / AxisConfig.cNbinsDiv, 0.9f, 2.5f, "Invariant Mass (GeV/#it{c}^2)"}; // K1 + AxisSpec pidQAAxis = {130 / AxisConfig.cNbinsDivQA, -6.5, 6.5}; + AxisSpec cutAxis{14, 0.5, 14.5, "Check"}; // 1..14 // THnSparse - AxisSpec axisAnti = {binAnti::kNAEnd, 0, binAnti::kNAEnd, "Type of bin: Normal or Anti"}; - AxisSpec axisType = {binType::kTYEnd, 0, binType::kTYEnd, "Type of bin with charge and mix"}; + AxisSpec axisType = {BinType::kTYEnd, 0, BinType::kTYEnd, "Type of bin with charge and mix"}; AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; - // DCA QA - // Primary pion - histos.add("QA/trkppionDCAxy", "DCAxy distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkppionDCAz", "DCAz distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkppionpT", "pT distribution of primary pion candidates", HistType::kTH1F, {ptAxis}); - histos.add("QA/trkppionTPCPID", "TPC PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QA/trkppionTOFPID", "TOF PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QA/trkppionTPCTOFPID", "TPC-TOF PID map of primary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); - - histos.add("QAcut/trkppionDCAxy", "DCAxy distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAcut/trkppionDCAz", "DCAz distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAcut/trkppionpT", "pT distribution of primary pion candidates", HistType::kTH1F, {ptAxis}); - histos.add("QAcut/trkppionTPCPID", "TPC PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAcut/trkppionTOFPID", "TOF PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAcut/trkppionTPCTOFPID", "TPC-TOF PID map of primary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + histos.add("QA/K0sCutCheck", "Check K0s cut", HistType::kTH1D, {AxisSpec{13, -0.5, 12.5, "Check"}}); + histos.add("QA/K0sCutFlow", "Check K0s cut (first-fail or pass)", HistType::kTH1F, {cutAxis}); + auto hcut = histos.get(HIST("QA/K0sCutFlow")); + hcut->GetXaxis()->SetBinLabel(1, "TOTAL"); + hcut->GetXaxis()->SetBinLabel(2, "PASS"); + hcut->GetXaxis()->SetBinLabel(3, "DauDCA>max"); + hcut->GetXaxis()->SetBinLabel(4, "PosDCAtoPVGetXaxis()->SetBinLabel(5, "NegDCAtoPVGetXaxis()->SetBinLabel(6, "pTGetXaxis()->SetBinLabel(7, "|y|>max"); + hcut->GetXaxis()->SetBinLabel(8, "Rmax"); + hcut->GetXaxis()->SetBinLabel(9, "DCAtoPV>max"); + hcut->GetXaxis()->SetBinLabel(10, "cosPAGetXaxis()->SetBinLabel(11, "ctau>max"); + hcut->GetXaxis()->SetBinLabel(12, "qtarmGetXaxis()->SetBinLabel(13, "|M(K0s)-m0|>win"); + hcut->GetXaxis()->SetBinLabel(14, "cross-mass veto"); + + histos.add("QA/before/CentDist", "Centrality distribution", {HistType::kTH1D, {centAxis}}); + histos.add("QA/before/VtxZ", "Centrality distribution", {HistType::kTH1D, {vtxzAxis}}); + histos.add("QA/before/hEvent", "Number of Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + + if (BkgEstimationConfig.cfgFillRotBkg) { + histos.add("QA/RotBkg/hRotBkg", "Rotated angle of rotated background", HistType::kTH1F, {{360, 0.0, o2::constants::math::TwoPI}}); + } + + // Bachelor pion + histos.add("QA/before/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/before/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + histos.add("QA/after/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/after/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); // Secondary pion - histos.add("QA/trkspionDCAxy", "DCAxy distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkspionDCAz", "DCAz distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkspionpT", "pT distribution of secondary pion candidates", HistType::kTH1F, {ptAxis}); - histos.add("QA/trkspionTPCPID", "TPC PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QA/trkspionTOFPID", "TOF PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QA/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); - - histos.add("QAcut/trkspionDCAxy", "DCAxy distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAcut/trkspionDCAz", "DCAz distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAcut/trkspionpT", "pT distribution of secondary pion candidates", HistType::kTH1F, {ptAxis}); - histos.add("QAcut/trkspionTPCPID", "TPC PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAcut/trkspionTOFPID", "TOF PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAcut/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); - - // Kaon - histos.add("QA/trkkaonDCAxy", "DCAxy distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkkaonDCAz", "DCAz distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkkaonpT", "pT distribution of kaon candidates", HistType::kTH1F, {ptAxis}); - histos.add("QA/trkkaonTPCPID", "TPC PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QA/trkkaonTOFPID", "TOF PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QA/trkkaonTPCTOFPID", "TPC-TOF PID map of kaon candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); - - histos.add("QAcut/trkkaonDCAxy", "DCAxy distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAcut/trkkaonDCAz", "DCAz distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAcut/trkkaonpT", "pT distribution of kaon candidates", HistType::kTH1F, {ptAxis}); - histos.add("QAcut/trkkaonTPCPID", "TPC PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAcut/trkkaonTOFPID", "TOF PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAcut/trkkaonTPCTOFPID", "TPC-TOF PID map of kaon candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trkspionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkspionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trkspionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkspionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkspionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trkspionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkspionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trkspionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkspionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkspionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + // K0s pion 1 + histos.add("QA/before/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + // K0s pion 2 + histos.add("QA/before/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // K0s + histos.add("QA/before/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/before/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QA/before/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/before/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/before/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/before/hArmSecondary", "Armenteros distribution of secondary resonance", HistType::kTH2D, {AxisSpec{100, -1, 1, "alpha"}, {200, 0, 0.5, "qtArm"}}); + histos.add("QA/before/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + histos.add("QA/after/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/after/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QA/after/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/after/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/after/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/after/hArmSecondary", "Armenteros distribution of secondary resonance", HistType::kTH2D, {AxisSpec{100, -1, 1, "alpha"}, {200, 0, 0.5, "qtArm"}}); + histos.add("QA/after/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // charged Kstar + histos.add("QA/before/hpT_Kstar", "pT distribution of chK(892)", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/hy_Kstar", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("QA/before/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisChk892}); + + histos.add("QA/after/hpT_Kstar", "pT distribution of chK(892)", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/hy_Kstar", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("QA/after/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisChk892}); // K1 - histos.add("QA/K1OA", "Opening angle of K1(1270)", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle"}}); - histos.add("QA/K1PairAssym", "Pair asymmetry of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); - histos.add("QA/hInvmassK892_Rho", "Invariant mass of K(892)0 vs Rho(770)", HistType::kTH2F, {invMassAxisK892, invMassAxisRho}); - histos.add("QA/hInvmassSecon_PiKa", "Invariant mass of secondary resonance vs pion-kaon", HistType::kTH2F, {invMassAxisK892, invMassAxisK892}); - histos.add("QA/hInvmassSecon", "Invariant mass of secondary resonance", HistType::kTH1F, {invMassAxisRho}); - histos.add("QA/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1F, {ptAxis}); - - histos.add("QAcut/K1OA", "Opening angle of K1(1270)", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle"}}); - histos.add("QAcut/K1PairAssym", "Pair asymmetry of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); - histos.add("QAcut/hInvmassK892_Rho", "Invariant mass of K(892)0 vs Rho(770)", HistType::kTH2F, {invMassAxisK892, invMassAxisRho}); - histos.add("QAcut/hInvmassSecon_PiKa", "Invariant mass of secondary resonance vs pion-kaon", HistType::kTH2F, {invMassAxisK892, invMassAxisK892}); - histos.add("QAcut/hInvmassSecon", "Invariant mass of secondary resonance", HistType::kTH1F, {invMassAxisRho}); - histos.add("QAcut/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1F, {ptAxis}); + histos.add("QA/before/hpT_K1", "pT distribution of K1(1270)", HistType::kTH1F, {ptAxisQA}); + histos.add("QA/before/hy_K1", "Rapidity distribution of K1(1270)", HistType::kTH1F, {yAxis}); + histos.add("QA/before/K1CPA", "Cosine pointing angle distribution of K1(1270)", HistType::kTH1F, {cpaAxis}); + histos.add("QA/before/K1PtAsym", "pT asymmetry distribution of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/before/K1DalitzOS", "Dalitz plot of opposite-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/before/K1DalitzLS", "Dalitz plot of like-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/before/K1invmass", "Invariant mass of K1(1270) (US)", HistType::kTH1F, {invMassAxisReso}); + histos.add("QA/before/K1invmassLS", "Invariant mass of K1(1270) (LS)", HistType::kTH1F, {invMassAxisReso}); + + histos.add("QA/after/hpT_K1", "pT distribution of K1(1270)", HistType::kTH1F, {ptAxisQA}); + histos.add("QA/after/hy_K1", "Rapidity distribution of K1(1270)", HistType::kTH1F, {yAxis}); + histos.add("QA/after/K1CPA", "Cosine pointing angle of K1(1270)", HistType::kTH1F, {cpaAxis}); + histos.add("QA/after/K1PtAsym", "pT asymmetry distribution of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/after/K1DalitzOS_Signal", "(Signal region) Dalitz plot of opposite-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/after/K1DalitzOS_SBLeft", "(SB left) Dalitz plot of opposite-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/after/K1DalitzOS_SBRight", "(SB right) Dalitz plot of opposite-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/after/K1DalitzLS_Signal", "(Signal region) Dalitz plot of like-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/after/K1DalitzLS_SBLeft", "(SB left) Dalitz plot of like-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/after/K1DalitzLS_SBRight", "(SB right) Dalitz plot of like-sign combination of K1(1270)", HistType::kTH2F, {AxisSpec{300, 0.0, 3.0, "#it{M}^{2}_{K_{s}^{0}#pi_{sec}}"}, {300, 0.0, 3.0, "#it{M}^{2}_{#pi_{sec}#pi_{bach}}"}}); + histos.add("QA/after/K1invmass", "Invariant mass of K1(1270) (US)", HistType::kTH1F, {invMassAxisReso}); + histos.add("QA/after/K1invmassLS", "Invariant mass of K1(1270) (LS)", HistType::kTH1F, {invMassAxisReso}); // Invariant mass - histos.add("hInvmass_K1", "Invariant mass of K1(1270)", HistType::kTHnSparseD, {axisAnti, axisType, centAxis, ptAxis, invMassAxisReso}); - // Mass QA (quick check) - histos.add("k1invmass", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); - histos.add("k1invmass_Mix", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); - - // MC - if (doprocessMC) { - histos.add("k1invmass_MC", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); - histos.add("k1invmass_MC_noK1", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); - - histos.add("QAMC/trkppionDCAxy", "DCAxy distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAMC/trkppionDCAz", "DCAz distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAMC/trkppionpT", "pT distribution of primary pion candidates", HistType::kTH1F, {ptAxis}); - histos.add("QAMC/trkppionTPCPID", "TPC PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAMC/trkppionTOFPID", "TOF PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAMC/trkppionTPCTOFPID", "TPC-TOF PID map of primary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); - - histos.add("QAMC/trkspionDCAxy", "DCAxy distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAMC/trkspionDCAz", "DCAz distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAMC/trkspionpT", "pT distribution of secondary pion candidates", HistType::kTH1F, {ptAxis}); - histos.add("QAMC/trkspionTPCPID", "TPC PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAMC/trkspionTOFPID", "TOF PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAMC/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); - - histos.add("QAMC/trkkaonDCAxy", "DCAxy distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAMC/trkkaonDCAz", "DCAz distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAMC/trkkaonpT", "pT distribution of kaon candidates", HistType::kTH1F, {ptAxis}); - histos.add("QAMC/trkkaonTPCPID", "TPC PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAMC/trkkaonTOFPID", "TOF PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); - histos.add("QAMC/trkkaonTPCTOFPID", "TPC-TOF PID map of kaon candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); - - histos.add("QAMC/K1OA", "Opening angle of K1(1270)", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle"}}); - histos.add("QAMC/K1PairAssym", "Pair asymmetry of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); - histos.add("QAMC/hInvmassK892_Rho", "Invariant mass of K(892)0 vs Rho(770)", HistType::kTH2F, {invMassAxisK892, invMassAxisRho}); - histos.add("QAMC/hInvmassSecon_PiKa", "Invariant mass of secondary resonance vs pion-kaon", HistType::kTH2F, {invMassAxisK892, invMassAxisK892}); - histos.add("QAMC/hInvmassSecon", "Invariant mass of secondary resonance", HistType::kTH1F, {invMassAxisRho}); - histos.add("QAMC/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1F, {ptAxis}); - } + histos.add("hInvmass_K1", "Invariant mass of K1(1270)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso}); + histos.add("hInvmass_Kstar", "Invariant mass of unlike-sign chK(892)", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisChk892}); + histos.add("hInvmass_K0s", "Invariant mass of unlike-sign K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisK0s}); + + ccdb->setURL(CCDBConfig.cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // Print output histograms statistics LOG(info) << "Size of the histograms in K1 Analysis Task"; histos.print(); - } + } // init - double massKa = MassKaonCharged; - double massPi = MassPionCharged; - // double massRho770 = MassRho770; - // double massK892 = MassKStar892; - double massRho770 = 0.77526; - double massK892 = 0.892; + const int kCentFT0C = 1; + const int kCentFT0M = 2; + const float kInvalidCentrality = -999.f; - // PDG code - int kPDGRho770 = 113; - int kK1Plus = 10323; + template + float getCentrality(CollisionType const& collision) + { + if (cfgCentEst == kCentFT0C) { + return collision.centFT0C(); + } else if (cfgCentEst == kCentFT0M) { + return collision.centFT0M(); + } else { + return kInvalidCentrality; + } + } + // Track selection template - bool trackCut(const TrackType track) + bool trackCut(TrackType const& track) { - // basic track cuts - if (std::abs(track.pt()) < cMinPtcut) + if (std::abs(track.pt()) < TrackCuts.cfgMinPtcut) return false; - if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + if (std::abs(track.eta()) > TrackCuts.cfgMaxEtacut) return false; - if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + if (track.itsNCls() < TrackCuts.cfgITScluster) return false; - if (track.tpcNClsFound() < cfgTPCcluster) + if (track.tpcNClsFound() < TrackCuts.cfgTPCcluster) return false; - if (cfgHasTOF && !track.hasTOF()) + if (track.tpcCrossedRowsOverFindableCls() < TrackCuts.cfgRatioTPCRowsOverFindableCls) return false; - if (cfgUseITSRefit && !track.passedITSRefit()) + if (track.itsChi2NCl() >= TrackCuts.cfgITSChi2NCl) return false; - if (cfgUseTPCRefit && !track.passedTPCRefit()) + if (track.tpcChi2NCl() >= TrackCuts.cfgTPCChi2NCl) return false; - if (cfgPVContributor && !track.isPVContributor()) + if (TrackCuts.cfgHasITS && !track.hasITS()) return false; - if (cfgPrimaryTrack && !track.isPrimaryTrack()) + if (TrackCuts.cfgHasTPC && !track.hasTPC()) return false; - if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + if (TrackCuts.cfgHasTOF && !track.hasTOF()) return false; - if (cfgGlobalTrack && !track.isGlobalTrack()) + if (TrackCuts.cfgUseITSRefit && !track.passedITSRefit()) return false; - - return true; - } - - // PID selection tools - template - bool selectionPIDPion(const T& candidate) - { - bool tpcPIDPassed{false}, tofPIDPassed{false}; - if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { - tpcPIDPassed = true; - } else { + if (TrackCuts.cfgUseTPCRefit && !track.passedTPCRefit()) return false; - } - if (candidate.hasTOF()) { - if (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion) { - tofPIDPassed = true; - } - if ((nsigmaCutCombinedPion > 0) && (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < nsigmaCutCombinedPion * nsigmaCutCombinedPion)) { - tofPIDPassed = true; - } + if (TrackCuts.cfgPVContributor && !track.isPVContributor()) + return false; + if (TrackCuts.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (TrackCuts.cfgGlobalTrack && !track.isGlobalTrack()) + return false; + if (TrackCuts.cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (TrackCuts.cfgpTdepDCAxyCut) { + // Tuned on the LHC22f anchored MC LHC23d1d on primary pions. 7 Sigmas of the resolution + if (std::abs(track.dcaXY()) > (0.004 + (0.013 / track.pt()))) + return false; } else { - if (!cTOFVeto) { + if (std::abs(track.dcaXY()) > TrackCuts.cfgMaxbDCArToPVcut) return false; - } - tofPIDPassed = true; } - if (tpcPIDPassed && tofPIDPassed) { - return true; + if (TrackCuts.cfgpTdepDCAzCut) { + // Tuned on the LHC22f anchored MC LHC23d1d on primary pions. 7 Sigmas of the resolution + if (std::abs(track.dcaZ()) > (0.004 + (0.013 / track.pt()))) + return false; + } else { + if (std::abs(track.dcaZ()) > TrackCuts.cfgMaxbDCAzToPVcut) + return false; } - return false; + return true; } - template - bool selectionPIDKaon(const T& candidate) + + // PID selection tools + template + bool selectionPIDPion(TrackType const& candidate) { - bool tpcPIDPassed{false}, tofPIDPassed{false}; - if (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon) { - tpcPIDPassed = true; - } else { + if (std::abs(candidate.tpcNSigmaPi()) >= PIDCuts.cfgMaxTPCnSigmaPion) return false; - } + if (PIDCuts.cfgTPConly) + return true; + // if (candidate.pt() <= PIDCuts.cfgTOFMinPt) + // return true; + if (candidate.hasTOF()) { - if (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon) { - tofPIDPassed = true; - } - if ((nsigmaCutCombinedKaon > 0) && (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa() < nsigmaCutCombinedKaon * nsigmaCutCombinedKaon)) { - tofPIDPassed = true; - } + const bool tofPIDPassed = std::abs(candidate.tofNSigmaPi()) < PIDCuts.cfgMaxTOFnSigmaPion; + const bool combo = (PIDCuts.cfgNsigmaCutCombinedPion > 0) && + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < + PIDCuts.cfgNsigmaCutCombinedPion * PIDCuts.cfgNsigmaCutCombinedPion); + return tofPIDPassed || combo; } else { - if (!cTOFVeto) { - return false; - } - tofPIDPassed = true; + return PIDCuts.cfgTOFVeto; } - if (tpcPIDPassed && tofPIDPassed) { - return true; - } - return false; } - template - bool isTrueK1(const T& trk1, const T& trk2, const T2& bTrack) + // selection K0s + template + bool selectionK0s(CollisionType const& collision, K0sType const& candidate) { - if (abs(trk1.pdgCode()) != kPiPlus || abs(trk2.pdgCode()) != kKPlus) - return false; - if (abs(bTrack.pdgCode()) != kPiPlus) - return false; - if (cfgModeK892orRho) { // K892 mode - auto mother1 = trk1.motherId(); - auto mother2 = trk2.motherId(); - if (mother1 != mother2) + auto lDauDCA = std::fabs(candidate.dcaV0daughters()); + auto lDauPosDCAtoPV = std::fabs(candidate.dcapostopv()); + auto lDauNegDCAtoPV = std::fabs(candidate.dcanegtopv()); + auto lPt = candidate.pt(); + auto lRapidity = candidate.yK0Short(); + auto lRadius = candidate.v0radius(); + auto lDCAtoPV = std::fabs(candidate.dcav0topv()); + auto lCPA = candidate.v0cosPA(); + auto lPropTauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto lMk0s = candidate.mK0Short(); + auto lMLambda = candidate.mLambda(); + auto lMALambda = candidate.mAntiLambda(); + + auto checkCommonCuts = [&]() { + if (std::fabs(lDauDCA) > SecondaryCuts.cfgSecondaryDauDCAMax) return false; - if (abs(trk1.motherPDG()) != kK0Star892) + if (std::fabs(lDauPosDCAtoPV) < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin) return false; - if (abs(bTrack.motherPDG()) != kK1Plus) + if (std::fabs(lDauNegDCAtoPV) < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin) return false; - auto siblings = bTrack.siblingIds(); - if (siblings[0] != mother1 && siblings[1] != mother1) + if (lPt < SecondaryCuts.cfgSecondaryPtMin) return false; - return true; - } else { // Rho mode - auto mother1 = trk1.motherId(); - auto motherb = bTrack.motherId(); - if (mother1 != motherb) + if (std::fabs(lRapidity) > SecondaryCuts.cfgSecondaryRapidityMax) + return false; + if (lRadius < SecondaryCuts.cfgSecondaryRadiusMin || lRadius > SecondaryCuts.cfgSecondaryRadiusMax) return false; - if (abs(trk1.motherPDG()) != kPDGRho770) + if (std::fabs(lDCAtoPV) > SecondaryCuts.cfgSecondaryDCAtoPVMax) return false; - if (abs(trk2.motherPDG()) != kK1Plus) + if (lCPA < SecondaryCuts.cfgSecondaryCosPAMin) return false; - auto siblings = trk2.siblingIds(); - if (siblings[0] != mother1 && siblings[1] != mother1) + if (lPropTauK0s > SecondaryCuts.cfgSecondaryProperLifetimeMax) + return false; + if (candidate.qtarm() < SecondaryCuts.cfgSecondaryparamArmenterosCut * std::fabs(candidate.alpha())) + return false; + if (std::fabs(lMk0s - MassK0Short) > SecondaryCuts.cfgSecondaryMassWindow) + return false; + if (SecondaryCuts.cfgSecondaryCrossMassHypothesisCut && + ((std::fabs(lMLambda - MassLambda0) < SecondaryCuts.cfgSecondaryCrossMassCutWindow) || (std::fabs(lMALambda - MassLambda0Bar) < SecondaryCuts.cfgSecondaryCrossMassCutWindow))) return false; return true; + }; + + if (SecondaryCuts.cfgReturnFlag) { // For cut study + bool returnFlag = true; + histos.fill(HIST("QA/K0sCutCheck"), 0); + if (lDauDCA > SecondaryCuts.cfgSecondaryDauDCAMax) { + histos.fill(HIST("QA/K0sCutCheck"), 1); + returnFlag = false; + } + if (lDauPosDCAtoPV < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 2); + returnFlag = false; + } + if (lDauNegDCAtoPV < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 3); + returnFlag = false; + } + if (lPt < SecondaryCuts.cfgSecondaryPtMin) { + histos.fill(HIST("QA/K0sCutCheck"), 4); + returnFlag = false; + } + if (std::fabs(lRapidity) > SecondaryCuts.cfgSecondaryRapidityMax) { + histos.fill(HIST("QA/K0sCutCheck"), 5); + returnFlag = false; + } + if (lRadius < SecondaryCuts.cfgSecondaryRadiusMin || lRadius > SecondaryCuts.cfgSecondaryRadiusMax) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + returnFlag = false; + } + if (lDCAtoPV > SecondaryCuts.cfgSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + returnFlag = false; + } + if (lCPA < SecondaryCuts.cfgSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + returnFlag = false; + } + if (lPropTauK0s > SecondaryCuts.cfgSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + returnFlag = false; + } + if (candidate.qtarm() < SecondaryCuts.cfgSecondaryparamArmenterosCut * std::fabs(candidate.alpha())) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } + if (std::fabs(lMk0s - MassK0Short) > SecondaryCuts.cfgSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 11); + returnFlag = false; + } + if (SecondaryCuts.cfgSecondaryCrossMassHypothesisCut && + ((std::fabs(lMLambda - MassLambda0) < SecondaryCuts.cfgSecondaryCrossMassCutWindow) || (std::fabs(lMALambda - MassLambda0Bar) < SecondaryCuts.cfgSecondaryCrossMassCutWindow))) { + histos.fill(HIST("QA/K0sCutCheck"), 12); + returnFlag = false; + } + return returnFlag; + } else { // normal usage + if (SecondaryCuts.cfgSecondaryRequire) { + return checkCommonCuts(); + } else { + return std::fabs(lMk0s - MassK0Short) <= SecondaryCuts.cfgSecondaryMassWindow; // always apply mass window cut + } } - } + } // selectionK0s - template - bool isTrueK892(const T& trk1, const T& trk2) + K1MassRegion getK1MassRegion(float mass) { - if (abs(trk1.pdgCode()) != kPiPlus || abs(trk2.pdgCode()) != kKPlus) - return false; - auto mother1 = trk1.motherId(); - auto mother2 = trk2.motherId(); - if (mother1 != mother2) - return false; - if (abs(trk1.motherPDG()) != kK0Star892) - return false; - return true; - } + constexpr float SigMin = 1.22f; + constexpr float SigMax = 1.32f; - template - bool isTrueRho(const T& trk1, const T& trk2) - { - if (abs(trk1.pdgCode()) != kPiPlus || abs(trk2.pdgCode()) != kPiPlus) - return false; - auto mother1 = trk1.motherId(); - auto mother2 = trk2.motherId(); - if (mother1 != mother2) - return false; - if (abs(trk1.motherPDG()) != kPDGRho770) - return false; - return true; + constexpr float SBLMin = 1.10f; + constexpr float SBLMax = 1.18f; + + constexpr float SBRMin = 1.36f; + constexpr float SBRMax = 1.44f; + + if (mass > SigMin && mass < SigMax) + return K1MassRegion::Signal; + if (mass > SBLMin && mass < SBLMax) + return K1MassRegion::SBLeft; + if (mass > SBRMin && mass < SBRMax) + return K1MassRegion::SBRight; + + return K1MassRegion::Outside; } - template - void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + int count = 0; + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2, const TracksTypeK0s& dTracks3) { - auto multiplicity = collision.cent(); - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonanceSecondary, lDecayDaughter_bach, lResonanceK1; - for (auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks2, dTracks2))) { - // Full index policy is needed to consider all possible combinations - if (trk1.index() == trk2.index()) - continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. - // Trk1: Pion, Trk2: Kaon - // apply the track cut - if (!trackCut(trk1) || !trackCut(trk2)) - continue; - auto isTrk1hasTOF = trk1.hasTOF(); - auto isTrk2hasTOF = trk2.hasTOF(); - auto trk1pt = trk1.pt(); - auto trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); - auto trk1NSigmaPiTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPi() : -999.; - auto trk2pt = trk2.pt(); - auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); - auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.; - // for rho mode - auto trk2NSigmaPiTPC = trk2.tpcNSigmaPi(); - auto trk2NSigmaPiTOF = (isTrk2hasTOF) ? trk2.tofNSigmaPi() : -999.; - - //// PID selections - if (cUseOnlyTOFTrackPi && !isTrk1hasTOF) - continue; - if (cUseOnlyTOFTrackKa && !isTrk2hasTOF) - continue; + using TrackTarget = std::decay_t; - if (cfgModeK892orRho) { // K892 mode - if (!selectionPIDPion(trk1) || !selectionPIDKaon(trk2)) - continue; - } else { // Rho mode - if (!selectionPIDPion(trk1) || !selectionPIDPion(trk2)) - continue; - } + histos.fill(HIST("QA/before/CentDist"), lCentrality); + + LorentzVectorSetXYZM lBachelor_pi, lDecayDaughter_K0s, lDecayDaughter_pi, lResoKstar, lResonanceK1, lDaughterRot, lResonanceRot; + LorentzVectorSetXYZM lPairK0sPiSec, lPairK0sPiBach, lPairPiPi; + + std::vector btrackIndices = {}; + std::vector strackIndices = {}; + std::vector k0sIndices = {}; + std::vector chK892Indices = {}; + + // check the existence of the pairs + if (cfgHasPair && (dTracks1.size() < 1 || dTracks2.size() < 1 || dTracks3.size() < 1)) + return; + + for (const auto& bTrack : dTracks1) { + auto trkbpt = bTrack.pt(); + auto istrkbhasTOF = bTrack.hasTOF(); + auto trkbNSigmaPiTPC = bTrack.tpcNSigmaPi(); + auto trkbNSigmaPiTOF = (istrkbhasTOF) ? bTrack.tofNSigmaPi() : -999.; - //// QA plots after the selection if constexpr (!IsMix) { - // --- PID QA Pion - histos.fill(HIST("QA/trkspionTPCPID"), trk1pt, trk1NSigmaPiTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QA/trkspionTOFPID"), trk1pt, trk1NSigmaPiTOF); - histos.fill(HIST("QA/trkspionTPCTOFPID"), trk1NSigmaPiTPC, trk1NSigmaPiTOF); - } - histos.fill(HIST("QA/trkspionpT"), trk1pt); - histos.fill(HIST("QA/trkspionDCAxy"), trk1.dcaXY()); - histos.fill(HIST("QA/trkspionDCAz"), trk1.dcaZ()); - - if (cfgModeK892orRho) { // K892 mode - // --- PID QA Kaon - histos.fill(HIST("QA/trkkaonTPCPID"), trk2pt, trk2NSigmaKaTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QA/trkkaonTOFPID"), trk2pt, trk2NSigmaKaTOF); - histos.fill(HIST("QA/trkkaonTPCTOFPID"), trk2NSigmaKaTPC, trk2NSigmaKaTOF); - } - histos.fill(HIST("QA/trkkaonpT"), trk2pt); - histos.fill(HIST("QA/trkkaonDCAxy"), trk2.dcaXY()); - histos.fill(HIST("QA/trkkaonDCAz"), trk2.dcaZ()); - } else { // Rho mode - // --- PID QA Pion - histos.fill(HIST("QA/trkppionTPCPID"), trk2pt, trk2NSigmaPiTPC); - if (isTrk2hasTOF) { - histos.fill(HIST("QA/trkppionTOFPID"), trk2pt, trk2NSigmaPiTOF); - histos.fill(HIST("QA/trkppionTPCTOFPID"), trk2NSigmaPiTPC, trk2NSigmaPiTOF); + if (cfgFillQAPlots) { + // Bachelor pion QA plots + histos.fill(HIST("QA/before/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/before/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/before/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); } - histos.fill(HIST("QA/trkppionpT"), trk2pt); - histos.fill(HIST("QA/trkppionDCAxy"), trk2.dcaXY()); - histos.fill(HIST("QA/trkppionDCAz"), trk2.dcaZ()); + histos.fill(HIST("QA/before/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/before/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/before/trkbpionDCAz"), bTrack.dcaZ()); } } - //// Resonance reconstruction - lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); - lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), (cfgModeK892orRho) ? massKa : massPi); - lResonanceSecondary = lDecayDaughter1 + lDecayDaughter2; + if (!trackCut(bTrack)) + continue; + if (!selectionPIDPion(bTrack)) + continue; if constexpr (!IsMix) { - histos.fill(HIST("QA/hInvmassSecon"), lResonanceSecondary.M()); + if (cfgFillQAPlots) { + // Bachelor pion QA plots after applying cuts + histos.fill(HIST("QA/after/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/after/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/after/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/after/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/after/trkbpionDCAz"), bTrack.dcaZ()); + } } + btrackIndices.push_back(bTrack.index()); + } // bTrack + + for (const auto& sTrack : dTracks2) { + auto trkspt = sTrack.pt(); + auto istrkshasTOF = sTrack.hasTOF(); + auto trksNSigmaPiTPC = sTrack.tpcNSigmaPi(); + auto trksNSigmaPiTOF = (istrkshasTOF) ? sTrack.tofNSigmaPi() : -999.; - if constexpr (IsMC) { // MC Check - if (cfgModeK892orRho) { - if (isTrueK892(trk1, trk2)) - histos.fill(HIST("QAMC/hpT_Secondary"), lResonanceSecondary.Pt()); - } else { - if (isTrueRho(trk1, trk2)) - histos.fill(HIST("QAMC/hpT_Secondary"), lResonanceSecondary.Pt()); + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + // Secondary pion QA plots + histos.fill(HIST("QA/before/trkspionTPCPID"), trkspt, trksNSigmaPiTPC); + if (istrkshasTOF) { + histos.fill(HIST("QA/before/trkspionTOFPID"), trkspt, trksNSigmaPiTOF); + histos.fill(HIST("QA/before/trkspionTPCTOFPID"), trksNSigmaPiTPC, trksNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkspionpT"), trkspt); + histos.fill(HIST("QA/before/trkspionDCAxy"), sTrack.dcaXY()); + histos.fill(HIST("QA/before/trkspionDCAz"), sTrack.dcaZ()); } } - // Mass window cut - double massCut = cfgModeK892orRho ? massK892 : massRho770; - if (std::abs(lResonanceSecondary.M() - massCut) > cSecondaryMasswindow) + if (!trackCut(sTrack)) + continue; + if (!selectionPIDPion(sTrack)) continue; - // bTrack loop for K1 reconstruction - for (auto bTrack : dTracks1) { - if (bTrack.index() == trk1.index() || bTrack.index() == trk2.index()) - continue; - if (!trackCut(bTrack)) - continue; - - // Kaon or Pion - if (cfgModeK892orRho && !selectionPIDPion(bTrack)) - continue; - if (!cfgModeK892orRho && !selectionPIDKaon(bTrack)) - continue; - - // K1 reconstruction - lDecayDaughter_bach.SetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), cfgModeK892orRho ? massPi : massKa); - lResonanceK1 = lResonanceSecondary + lDecayDaughter_bach; + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + // Secondary pion QA plots after applying cuts + histos.fill(HIST("QA/after/trkspionTPCPID"), trkspt, trksNSigmaPiTPC); + if (istrkshasTOF) { + histos.fill(HIST("QA/after/trkspionTOFPID"), trkspt, trksNSigmaPiTOF); + histos.fill(HIST("QA/after/trkspionTPCTOFPID"), trksNSigmaPiTPC, trksNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkspionpT"), trkspt); + histos.fill(HIST("QA/after/trkspionDCAxy"), sTrack.dcaXY()); + histos.fill(HIST("QA/after/trkspionDCAz"), sTrack.dcaZ()); + } + } + strackIndices.push_back(sTrack.index()); + } // sTrack + + for (const auto& k0sCand : dTracks3) { + + auto posDauTrack = k0sCand.template posTrack_as(); + auto negDauTrack = k0sCand.template negTrack_as(); + + /// Daughters + // Positve pion + auto trkppt = posDauTrack.pt(); + auto istrkphasTOF = posDauTrack.hasTOF(); + auto trkpNSigmaPiTPC = posDauTrack.tpcNSigmaPi(); + auto trkpNSigmaPiTOF = (istrkphasTOF) ? posDauTrack.tofNSigmaPi() : -999.; + // Negative pion + auto trknpt = negDauTrack.pt(); + auto istrknhasTOF = negDauTrack.hasTOF(); + auto trknNSigmaPiTPC = negDauTrack.tpcNSigmaPi(); + auto trknNSigmaPiTOF = (istrknhasTOF) ? negDauTrack.tofNSigmaPi() : -999.; + + /// K0s + auto trkkDauDCA = k0sCand.dcaV0daughters(); + auto trkky = k0sCand.yK0Short(); + auto trkkDCAtoPV = k0sCand.dcav0topv(); + auto trkkCPA = k0sCand.v0cosPA(); + auto trkkPropTau = k0sCand.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto trkkMass = k0sCand.mK0Short(); + auto trkkDauDCAPostoPV = k0sCand.dcapostopv(); + auto trkkDauDCANegtoPV = k0sCand.dcanegtopv(); + auto trkkpt = k0sCand.pt(); + auto trkkRadius = k0sCand.v0radius(); - // Cuts - if (lResonanceK1.Rapidity() > cK1MaxRap || lResonanceK1.Rapidity() < cK1MinRap) - continue; + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + // Seconddary QA plots + histos.fill(HIST("QA/before/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/before/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/before/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkppionpT"), trkppt); + histos.fill(HIST("QA/before/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/before/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/before/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/before/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trknpionpT"), trknpt); + histos.fill(HIST("QA/before/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trknpionDCAz"), negDauTrack.dcaZ()); + + histos.fill(HIST("QA/before/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/before/hDauPosDCAtoPVSecondary"), trkkDauDCAPostoPV); + histos.fill(HIST("QA/before/hDauNegDCAtoPVSecondary"), trkkDauDCANegtoPV); + + histos.fill(HIST("QA/before/hpT_Secondary"), trkkpt); + histos.fill(HIST("QA/before/hy_Secondary"), trkky); + histos.fill(HIST("QA/before/hRadiusSecondary"), trkkRadius); + histos.fill(HIST("QA/before/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/before/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/before/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/before/hArmSecondary"), k0sCand.alpha(), k0sCand.qtarm()); + histos.fill(HIST("QA/before/hInvmassSecondary"), trkkMass); + } + } - auto lK1Angle = lResonanceSecondary.Angle(lDecayDaughter_bach.Vect()); - auto lPairAsym = (lResonanceSecondary.E() - lDecayDaughter_bach.E()) / (lResonanceSecondary.E() + lDecayDaughter_bach.E()); + if (!SecondaryCuts.cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) + continue; + if (!SecondaryCuts.cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) + continue; + if (!selectionK0s(collision, k0sCand)) + continue; - TLorentzVector temp13 = lDecayDaughter1 + lDecayDaughter_bach; - TLorentzVector temp23 = lDecayDaughter2 + lDecayDaughter_bach; + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + // Seconddary QA plots after applying cuts - // QA histograms - if constexpr (!IsMix) { - histos.fill(HIST("QA/K1OA"), lK1Angle); - histos.fill(HIST("QA/K1PairAssym"), lPairAsym); - if (cfgModeK892orRho) { - histos.fill(HIST("QA/hInvmassK892_Rho"), lResonanceSecondary.M(), temp13.M()); - } else { - histos.fill(HIST("QA/hInvmassK892_Rho"), temp13.M(), lResonanceSecondary.M()); + histos.fill(HIST("QA/after/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/after/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/after/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkppionpT"), trkppt); + histos.fill(HIST("QA/after/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/after/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/after/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); } - histos.fill(HIST("QA/hInvmassSecon_PiKa"), lResonanceSecondary.M(), temp23.M()); - histos.fill(HIST("QA/hpT_Secondary"), lResonanceSecondary.Pt()); + histos.fill(HIST("QA/after/trknpionpT"), trknpt); + histos.fill(HIST("QA/after/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trknpionDCAz"), negDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/after/hDauPosDCAtoPVSecondary"), trkkDauDCAPostoPV); + histos.fill(HIST("QA/after/hDauNegDCAtoPVSecondary"), trkkDauDCANegtoPV); + + histos.fill(HIST("QA/after/hpT_Secondary"), trkkpt); + histos.fill(HIST("QA/after/hy_Secondary"), trkky); + histos.fill(HIST("QA/after/hRadiusSecondary"), trkkRadius); + histos.fill(HIST("QA/after/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/after/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/after/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/after/hArmSecondary"), k0sCand.alpha(), k0sCand.qtarm()); + histos.fill(HIST("QA/after/hInvmassSecondary"), trkkMass); } + histos.fill(HIST("hInvmass_K0s"), lCentrality, trkkpt, trkkMass); + } + k0sIndices.push_back(k0sCand.index()); + } // K0s - // Selection cuts - if (temp13.M() < cMinAnotherSecondaryMassCut || temp13.M() > cMaxAnotherSecondaryMassCut) - continue; - if (temp23.M() < cMinPiKaMassCut || temp23.M() > cMaxPiKaMassCut) - continue; - if (lK1Angle < cMinAngle || lK1Angle > cMaxAngle) - continue; - if (lPairAsym < cMinPairAsym || lPairAsym > cMaxPairAsym) + for (const auto& btrackIndex : btrackIndices) { + auto bTrack = dTracks1.rawIteratorAt(btrackIndex); + for (const auto& strackIndex : strackIndices) { + auto sTrack = dTracks2.rawIteratorAt(strackIndex); + + if (bTrack.index() == sTrack.index()) continue; - // QA histograms after the cuts - if constexpr (!IsMix) { - histos.fill(HIST("QAcut/K1OA"), lK1Angle); - histos.fill(HIST("QAcut/K1PairAssym"), lPairAsym); - if (cfgModeK892orRho) { - histos.fill(HIST("QAcut/hInvmassK892_Rho"), lResonanceSecondary.M(), temp13.M()); - } else { - histos.fill(HIST("QAcut/hInvmassK892_Rho"), temp13.M(), lResonanceSecondary.M()); + for (const auto& k0sIndex : k0sIndices) { + auto k0sCand = dTracks3.rawIteratorAt(k0sIndex); + + auto posDauTrack = k0sCand.template posTrack_as(); + auto negDauTrack = k0sCand.template negTrack_as(); + + if (bTrack.index() == posDauTrack.index() || bTrack.index() == negDauTrack.index()) + continue; + if (sTrack.index() == posDauTrack.index() || sTrack.index() == negDauTrack.index()) + continue; + + lBachelor_pi = LorentzVectorSetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassPionCharged); + lDecayDaughter_pi = LorentzVectorSetXYZM(sTrack.px(), sTrack.py(), sTrack.pz(), MassPionCharged); + lDecayDaughter_K0s = LorentzVectorSetXYZM(k0sCand.px(), k0sCand.py(), k0sCand.pz(), MassK0Short); + lResoKstar = lDecayDaughter_pi + lDecayDaughter_K0s; + lResonanceK1 = lResoKstar + lBachelor_pi; + + // QA plots for Kstar + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + histos.fill(HIST("QA/before/hpT_Kstar"), lResoKstar.Pt()); + histos.fill(HIST("QA/before/hy_Kstar"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/before/kstarinvmass"), lResoKstar.M()); + } } - histos.fill(HIST("QAcut/hInvmassSecon_PiKa"), lResonanceSecondary.M(), temp23.M()); - histos.fill(HIST("QAcut/hInvmassSecon"), lResonanceSecondary.M()); - histos.fill(HIST("QAcut/hpT_Secondary"), lResonanceSecondary.Pt()); - } - if constexpr (!IsMix) { - unsigned int typeK1 = bTrack.sign() > 0 ? binType::kK1P : binType::kK1N; - unsigned int typeNormal = cfgModeK892orRho ? (trk1.sign() < 0 ? binAnti::kNormal : binAnti::kAnti) : binAnti::kNormal; - histos.fill(HIST("k1invmass"), lResonanceK1.M()); - histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - - if constexpr (IsMC) { - if (isTrueK1(trk1, trk2, bTrack)) { - typeK1 = bTrack.sign() > 0 ? binType::kK1P_Rec : binType::kK1N_Rec; - histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - histos.fill(HIST("k1invmass_MC"), lResonanceK1.M()); - histos.fill(HIST("QAMC/K1OA"), lK1Angle); - histos.fill(HIST("QAMC/K1PairAssym"), lPairAsym); - if (cfgModeK892orRho) { - histos.fill(HIST("QAMC/hInvmassK892_Rho"), lResonanceSecondary.M(), temp13.M()); + if (lResoKstar.Rapidity() > KstarCuts.cfgKstarMaxRap || lResoKstar.Rapidity() < KstarCuts.cfgKstarMinRap) + continue; + if (lResoKstar.Pt() < KstarCuts.cfgKstarMinPt) + continue; + if (std::fabs(lResoKstar.M() - MassKPlusStar892) > KstarCuts.cfgKstarMassWindow) + continue; + + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + histos.fill(HIST("QA/after/hpT_Kstar"), lResoKstar.Pt()); + histos.fill(HIST("QA/after/hy_Kstar"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/after/kstarinvmass"), lResoKstar.M()); + } + histos.fill(HIST("hInvmass_Kstar"), lCentrality, lResoKstar.Pt(), lResoKstar.M()); + } // IsMix + + lPairK0sPiSec = lDecayDaughter_K0s + lDecayDaughter_pi; + lPairK0sPiBach = lDecayDaughter_K0s + lBachelor_pi; + lPairPiPi = lDecayDaughter_pi + lBachelor_pi; + + float m2K0sPiSec = lPairK0sPiSec.M2(); + // float m2K0sPiBach = lPairK0sPiBach.M2(); + float m2PiPi = lPairPiPi.M2(); + + // QA plots for K1 + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + histos.fill(HIST("QA/before/hpT_K1"), lResonanceK1.Pt()); + histos.fill(HIST("QA/before/hy_K1"), lResonanceK1.Rapidity()); + if (bTrack.sign() * sTrack.sign() < 0) { + histos.fill(HIST("QA/before/K1invmass"), lResonanceK1.M()); + histos.fill(HIST("QA/before/K1DalitzOS"), m2K0sPiSec, m2PiPi); } else { - histos.fill(HIST("QAMC/hInvmassK892_Rho"), temp13.M(), lResonanceSecondary.M()); - } - histos.fill(HIST("QAMC/hInvmassSecon_PiKa"), lResonanceSecondary.M(), temp23.M()); - histos.fill(HIST("QAMC/hInvmassSecon"), lResonanceSecondary.M()); - histos.fill(HIST("QAMC/hpT_Secondary"), lResonanceSecondary.Pt()); - - // --- PID QA Pion - histos.fill(HIST("QAMC/trkspionTPCPID"), trk1pt, trk1NSigmaPiTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QAMC/trkspionTOFPID"), trk1pt, trk1NSigmaPiTOF); - histos.fill(HIST("QAMC/trkspionTPCTOFPID"), trk1NSigmaPiTPC, trk1NSigmaPiTOF); + histos.fill(HIST("QA/before/K1invmassLS"), lResonanceK1.M()); + histos.fill(HIST("QA/before/K1DalitzLS"), m2K0sPiSec, m2PiPi); } - histos.fill(HIST("QAMC/trkspionpT"), trk1pt); - histos.fill(HIST("QAMC/trkspionDCAxy"), trk1.dcaXY()); - histos.fill(HIST("QAMC/trkspionDCAz"), trk1.dcaZ()); - - if (cfgModeK892orRho) { // K892 mode - // --- PID QA Kaon - histos.fill(HIST("QAMC/trkkaonTPCPID"), trk2pt, trk2NSigmaKaTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QAMC/trkkaonTOFPID"), trk2pt, trk2NSigmaKaTOF); - histos.fill(HIST("QAMC/trkkaonTPCTOFPID"), trk2NSigmaKaTPC, trk2NSigmaKaTOF); + } + } // IsMix + + if (lResonanceK1.Rapidity() > K1Cuts.cfgK1MaxRap || lResonanceK1.Rapidity() < K1Cuts.cfgK1MinRap) + continue; + if (lResonanceK1.Pt() < K1Cuts.cfgK1MinPt) + continue; + if (lPairPiPi.Pt() < cfgPiPiMinPt) + continue; + + auto k1Region = getK1MassRegion(lResonanceK1.M()); + + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + histos.fill(HIST("QA/after/hpT_K1"), lResonanceK1.Pt()); + histos.fill(HIST("QA/after/hy_K1"), lResonanceK1.Rapidity()); + if (bTrack.sign() * sTrack.sign() < 0) { + histos.fill(HIST("QA/after/K1invmass"), lResonanceK1.M()); + // histos.fill(HIST("QA/after/K1DalitzOS"), m2K0sPiSec, m2PiPi); + if (k1Region == K1MassRegion::Signal) { + histos.fill(HIST("QA/after/K1DalitzOS_Signal"), m2K0sPiSec, m2PiPi); + } else if (k1Region == K1MassRegion::SBLeft) { + histos.fill(HIST("QA/after/K1DalitzOS_SBLeft"), m2K0sPiSec, m2PiPi); + } else if (k1Region == K1MassRegion::SBRight) { + histos.fill(HIST("QA/after/K1DalitzOS_SBRight"), m2K0sPiSec, m2PiPi); } - histos.fill(HIST("QAMC/trkkaonpT"), trk2pt); - histos.fill(HIST("QAMC/trkkaonDCAxy"), trk2.dcaXY()); - histos.fill(HIST("QAMC/trkkaonDCAz"), trk2.dcaZ()); - } else { // Rho mode - // --- PID QA Pion - histos.fill(HIST("QAMC/trkppionTPCPID"), trk2pt, trk2NSigmaPiTPC); - if (isTrk2hasTOF) { - histos.fill(HIST("QAMC/trkppionTOFPID"), trk2pt, trk2NSigmaPiTOF); - histos.fill(HIST("QAMC/trkppionTPCTOFPID"), trk2NSigmaPiTPC, trk2NSigmaPiTOF); + } else { + histos.fill(HIST("QA/after/K1invmassLS"), lResonanceK1.M()); + // histos.fill(HIST("QA/after/K1DalitzLS"), m2K0sPiSec, m2PiPi); + if (k1Region == K1MassRegion::Signal) { + histos.fill(HIST("QA/after/K1DalitzLS_Signal"), m2K0sPiSec, m2PiPi); + } else if (k1Region == K1MassRegion::SBLeft) { + histos.fill(HIST("QA/after/K1DalitzLS_SBLeft"), m2K0sPiSec, m2PiPi); + } else if (k1Region == K1MassRegion::SBRight) { + histos.fill(HIST("QA/after/K1DalitzLS_SBRight"), m2K0sPiSec, m2PiPi); } - histos.fill(HIST("QAMC/trkppionpT"), trk2pt); - histos.fill(HIST("QAMC/trkppionDCAxy"), trk2.dcaXY()); - histos.fill(HIST("QAMC/trkppionDCAz"), trk2.dcaZ()); } + } + + if (bTrack.sign() * sTrack.sign() < 0) { + // bTrack sign minus for particle, plus for anti-particle + unsigned int typeK1 = bTrack.sign() < 0 ? BinType::kK1P : BinType::kK1A; + histos.fill(HIST("hInvmass_K1"), typeK1, lCentrality, lResonanceK1.Pt(), lResonanceK1.M()); } else { - histos.fill(HIST("k1invmass_MC_noK1"), lResonanceK1.M()); + unsigned int typeK1 = bTrack.sign() < 0 ? BinType::kK1P_Like : BinType::kK1A_Like; + histos.fill(HIST("hInvmass_K1"), typeK1, lCentrality, lResonanceK1.Pt(), lResonanceK1.M()); } - } // MC - } else { // Mixed event handling - unsigned int typeK1 = bTrack.sign() > 0 ? binType::kK1P_Mix : binType::kK1N_Mix; - unsigned int typeNormal = cfgModeK892orRho ? (trk1.sign() < 0 ? binAnti::kNormal : binAnti::kAnti) : binAnti::kNormal; - histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - histos.fill(HIST("k1invmass_Mix"), lResonanceK1.M()); - } - } // bTrack - } - } - void processData(aod::ResoCollision& collision, - aod::ResoTracks const& resotracks) - { - fillHistograms(collision, resotracks, resotracks); - } - PROCESS_SWITCH(k1analysis, processData, "Process Event for data without Partitioning", true); + if (BkgEstimationConfig.cfgFillRotBkg) { + for (int i = 0; i < BkgEstimationConfig.cfgNrotBkg; i++) { + auto lRotAngle = BkgEstimationConfig.cfgMinRot + i * ((BkgEstimationConfig.cfgMaxRot - BkgEstimationConfig.cfgMinRot) / (BkgEstimationConfig.cfgNrotBkg - 1)); + if (cfgFillQAPlots) { + histos.fill(HIST("QA/RotBkg/hRotBkg"), lRotAngle); + } + if (BkgEstimationConfig.cfgRotPion) { + lDaughterRot = lBachelor_pi; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDaughterRot + lResoKstar; + } else { + lDaughterRot = lResoKstar; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot; + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lBachelor_pi + lDaughterRot; + } + unsigned int typeK1 = bTrack.sign() < 0 ? BinType::kK1P_Rot : BinType::kK1A_Rot; + histos.fill(HIST("hInvmass_K1"), typeK1, lCentrality, lResonanceRot.Pt(), lResonanceRot.M()); - void processMC(aod::ResoCollision& collision, - soa::Join const& resotracks) - { - fillHistograms(collision, resotracks, resotracks); - } - PROCESS_SWITCH(k1analysis, processMC, "Process Event for MC", false); + } // NrotBkg + } // cfgFillRotBkg + } // IsMix + } // k0sIndex + } // strackIndex + } // btrackIndex + + count++; - void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents& resoParents) + } // fillHistograms + + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& tracks, + V0Candidates const& v0s, + aod::BCsWithTimestamps const&) { - auto multiplicity = collision.cent(); - for (auto& part : resoParents) { // loop over all pre-filtered MC particles - if (abs(part.pdgCode()) != kK1Plus) // K892(0) - continue; - if (abs(part.y()) > 0.5) { // rapidity cut - continue; - } - bool pass1 = false; - bool pass2 = false; - if (cfgModeK892orRho) { - if (abs(part.daughterPDG1()) == 313 || abs(part.daughterPDG2()) == 313) { // At least one decay to K892 - pass2 = true; - } - if (abs(part.daughterPDG1()) == kPiPlus || abs(part.daughterPDG2()) == kPiPlus) { // At least one decay to Pion - pass1 = true; - } - if (!pass1 || !pass2) // If we have both decay products - continue; - } else { - if (abs(part.daughterPDG1()) == kPDGRho770 || abs(part.daughterPDG2()) == kPDGRho770) { // At least one decay to Rho - pass2 = true; - } - if (abs(part.daughterPDG1()) == kKPlus || abs(part.daughterPDG2()) == kKPlus) { // At least one decay to Kaon - pass1 = true; - } - if (!pass1 || !pass2) // If we have both decay products - continue; - } - auto typeNormal = part.pdgCode() > 0 ? binAnti::kNormal : binAnti::kAnti; - if (collision.isVtxIn10()) // INEL10 - { - auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenINEL10 : binType::kK1N_GenINEL10; - histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); - } - if (collision.isVtxIn10() && collision.isInSel8()) // INEL>10, vtx10 - { - auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenINELgt10 : binType::kK1N_GenINELgt10; - histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); - } - if (collision.isVtxIn10() && collision.isTriggerTVX()) // vtx10, TriggerTVX - { - auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenTrig10 : binType::kK1N_GenTrig10; - histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); - } - if (collision.isInAfterAllCuts()) // after all event selection - { - auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenEvtSel : binType::kK1N_GenEvtSel; - histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); - } + if (!colCuts.isSelected(collision)) // Default event selection + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + return; } + lCentrality = getCentrality(collision); + if (lCentrality < EventCuts.cfgEventCentralityMin || lCentrality > EventCuts.cfgEventCentralityMax) + return; + if (!collision.isInelGt0()) + return; + colCuts.fillQA(collision); + + fillHistograms(collision, tracks, tracks, v0s); } - PROCESS_SWITCH(k1analysis, processMCTrue, "Process Event for MC", false); - - // Processing Event Mixing - using BinningTypeVtxZT0M = ColumnBinningPolicy; - void processME(o2::aod::ResoCollisions& collisions, aod::ResoTracks const& resotracks) - { - auto tracksTuple = std::make_tuple(resotracks); - BinningTypeVtxZT0M colBinning{{CfgVtxBins, CfgMultBins}, true}; - SameKindPair pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + PROCESS_SWITCH(K1analysis, processData, "Process Event for data without Partitioning", true); - for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { - fillHistograms(collision1, tracks1, tracks2); - } - }; - PROCESS_SWITCH(k1analysis, processME, "Process EventMixing light without partition", false); -}; +}; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"lf-k1analysis"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/k892analysispbpb.cxx b/PWGLF/Tasks/Resonances/k892analysispbpb.cxx index f0d2db3a2f7..93e1407027b 100644 --- a/PWGLF/Tasks/Resonances/k892analysispbpb.cxx +++ b/PWGLF/Tasks/Resonances/k892analysispbpb.cxx @@ -114,6 +114,7 @@ struct K892analysispbpb { Configurable cTPClowpt{"cTPClowpt", true, "apply TPC at low pt"}; Configurable cTOFonlyHighpt{"cTOFonlyHighpt", false, "apply TOF only at high pt"}; Configurable cTOFandTPCHighpt{"cTOFandTPCHighpt", false, "apply TOF and TPC at high pt"}; + Configurable circularCut{"circularCut", false, "apply TOF and TPC circular cut (applied only if cTOFandTPCHighpt is true)"}; // rotational bkg Configurable cfgNoRotations{"cfgNoRotations", 3, "Number of rotations per pair for rotbkg"}; @@ -409,10 +410,16 @@ struct K892analysispbpb { } else if (cTOFandTPCHighpt) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) <= cMaxTOFnSigmaKaon && candidate.hasTPC() && std::abs(candidate.tpcNSigmaKa()) <= cMaxTPCnSigmaKaon) { // tof and tpc cut - return true; - } + if (circularCut) { + + if (candidate.hasTOF() && candidate.hasTPC() && std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2) + std::pow(candidate.tofNSigmaKa(), 2)) <= cMaxTPCnSigmaKaon) // tof and tpc circular cut + return true; + } else { + + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) <= cMaxTOFnSigmaKaon && candidate.hasTPC() && std::abs(candidate.tpcNSigmaKa()) <= cMaxTPCnSigmaKaon) // tof and tpc cut + return true; + } } else { if (candidate.hasTPC() && std::abs(candidate.tpcNSigmaKa()) <= cMaxTPCnSigmaKaon) { // tpc cut, tof when available @@ -447,8 +454,15 @@ struct K892analysispbpb { } else if (cTOFandTPCHighpt) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) <= cMaxTOFnSigmaPion && candidate.hasTPC() && std::abs(candidate.tpcNSigmaPi()) <= cMaxTPCnSigmaPion) { // tof and tpc cut - return true; + if (circularCut) { + + if (candidate.hasTOF() && candidate.hasTPC() && std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2) + std::pow(candidate.tofNSigmaPi(), 2)) <= cMaxTPCnSigmaPion) // tof and tpc circular cut + return true; + + } else { + + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) <= cMaxTOFnSigmaPion && candidate.hasTPC() && std::abs(candidate.tpcNSigmaPi()) <= cMaxTPCnSigmaPion) // tof and tpc cut + return true; } } else { @@ -838,7 +852,7 @@ struct K892analysispbpb { Preslice trackPerCollision = aod::track::collisionId; - template + template void callFillHistoswithPartitions(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&) { if (cTPClowpt) { @@ -846,39 +860,51 @@ struct K892analysispbpb { auto candPosPitpc = posPitpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto candNegKatpc = negKatpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - fillHistograms(collision1, candPosPitpc, candNegKatpc); - //-+ auto candNegPitpc = negPitpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto candPosKatpc = posKatpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - fillHistograms(collision1, candNegPitpc, candPosKatpc); + if constexpr (!isLikeSig) { + fillHistograms(collision1, candPosPitpc, candNegKatpc); + fillHistograms(collision1, candNegPitpc, candPosKatpc); + } else { + fillHistograms(collision1, candPosPitpc, candPosKatpc); + fillHistograms(collision1, candNegPitpc, candNegKatpc); + } } else if (cTOFandTPCHighpt) { //+- auto candPosPitoftpc = posPitoftpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto candNegKatoftpc = negKatoftpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - fillHistograms(collision1, candPosPitoftpc, candNegKatoftpc); - //-+ auto candNegPitoftpc = negPitoftpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto candPosKatoftpc = posKatoftpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - fillHistograms(collision1, candNegPitoftpc, candPosKatoftpc); + if constexpr (!isLikeSig) { + fillHistograms(collision1, candPosPitoftpc, candNegKatoftpc); + fillHistograms(collision1, candNegPitoftpc, candPosKatoftpc); + } else { + fillHistograms(collision1, candPosPitoftpc, candPosKatoftpc); + fillHistograms(collision1, candNegPitoftpc, candNegKatoftpc); + } } else if (cTOFonlyHighpt) { //+- auto candPosPitof = posPitof->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto candNegKatof = negKatof->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - fillHistograms(collision1, candPosPitof, candNegKatof); - //-+ auto candNegPitof = negPitof->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto candPosKatof = posKatof->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - fillHistograms(collision1, candNegPitof, candPosKatof); + if constexpr (!isLikeSig) { + fillHistograms(collision1, candPosPitof, candNegKatof); + fillHistograms(collision1, candNegPitof, candPosKatof); + } else { + fillHistograms(collision1, candPosPitof, candPosKatof); + fillHistograms(collision1, candNegPitof, candNegKatof); + } } } @@ -898,8 +924,8 @@ struct K892analysispbpb { histos.fill(HIST("TestME/hCollisionIndexSameE"), collision.globalIndex()); histos.fill(HIST("TestME/hnTrksSameE"), tracks.size()); } - // - callFillHistoswithPartitions(collision, tracks, collision, tracks); + // + callFillHistoswithPartitions(collision, tracks, collision, tracks); } PROCESS_SWITCH(K892analysispbpb, processSameEvent, "Process Same event", true); @@ -918,8 +944,8 @@ struct K892analysispbpb { histos.fill(HIST("TestME/hnTrksSameE"), tracks.size()); } - // - callFillHistoswithPartitions(collision, tracks, collision, tracks); + // + callFillHistoswithPartitions(collision, tracks, collision, tracks); } PROCESS_SWITCH(K892analysispbpb, processSameEventRun2, "Process Same event Run2", false); @@ -929,8 +955,8 @@ struct K892analysispbpb { if (!myEventSelections(collision)) return; - // - callFillHistoswithPartitions(collision, tracks, collision, tracks); + // + callFillHistoswithPartitions(collision, tracks, collision, tracks); } PROCESS_SWITCH(K892analysispbpb, processRotationalBkg, "Process Rotational Background", false); @@ -945,6 +971,17 @@ struct K892analysispbpb { } PROCESS_SWITCH(K892analysispbpb, processRotationalBkgMC, "Process Rotational Background MC", false); + void processLikeSign(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + + if (!myEventSelections(collision)) + return; + + // + callFillHistoswithPartitions(collision, tracks, collision, tracks); + } + PROCESS_SWITCH(K892analysispbpb, processLikeSign, "Process Like Sign", false); + void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) { auto tracksTuple = std::make_tuple(tracks); @@ -966,8 +1003,8 @@ struct K892analysispbpb { histos.fill(HIST("TestME/hnTrksMixedE"), tracks1.size()); } - // - callFillHistoswithPartitions(collision1, tracks1, collision2, tracks2); + // + callFillHistoswithPartitions(collision1, tracks1, collision2, tracks2); } } PROCESS_SWITCH(K892analysispbpb, processMixedEvent, "Process Mixed event", true); @@ -991,8 +1028,8 @@ struct K892analysispbpb { histos.fill(HIST("TestME/hnTrksMixedE"), tracks1.size()); } - // - callFillHistoswithPartitions(collision1, tracks1, collision2, tracks2); + // + callFillHistoswithPartitions(collision1, tracks1, collision2, tracks2); } } PROCESS_SWITCH(K892analysispbpb, processMixedEventRun2, "Process Mixed event Run2", false); diff --git a/PWGLF/Tasks/Resonances/kstar0analysis.cxx b/PWGLF/Tasks/Resonances/kstar0analysis.cxx new file mode 100644 index 00000000000..6fa7b2b21aa --- /dev/null +++ b/PWGLF/Tasks/Resonances/kstar0analysis.cxx @@ -0,0 +1,947 @@ +// 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 kstar0analysis.cxx +/// \brief the reconstruction of k*0(892) resonance analysis using K\pi decay channel +/// \author Hirak Kumar Koley + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct kstar0analysis { + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + //================================== + //|| + //|| Selection + //|| + //================================== + + // Event Selection + Configurable cfgEventSelections{"cfgEventSelections", "sel8", "Set event selection"}; + Configurable cfgEventVtxCut{"cfgEventVtxCut", 10.0, "V_z cut selection"}; + ConfigurableAxis cfgCentAxis{"cfgCentAxis", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0}, "Binning of the centrality axis"}; + Configurable cfgOccupancySel{"cfgOccupancySel", false, "Occupancy selection"}; + Configurable cfgOccupancyMax{"cfgOccupancyMax", 999999., "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgOccupancyMin{"cfgOccupancyMin", -100., "minimum occupancy of tracks in neighbouring collisions in a given time range"}; + + // Track Selection + // General + Configurable cfgTrackMinPt{"cfgTrackMinPt", 0.15, "set track min pT"}; + Configurable cfgTrackMaxEta{"cfgTrackMaxEta", 0.8, "set track max Eta"}; + Configurable cfgTrackMaxDCArToPVcut{"cfgTrackMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + Configurable cfgTrackMaxDCAzToPVcut{"cfgTrackMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cfgTrackGlobalSel{"cfgTrackGlobalSel", true, "Global track selection"}; + Configurable cfgTrackPrimaryTrack{"cfgTrackPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgTrackConnectedToPV{"cfgTrackConnectedToPV", true, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgTrackGlobalWoDCATrack{"cfgTrackGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + + // TPC + Configurable cfgTrackFindableTPCClusters{"cfgTrackFindableTPCClusters", 50, "nFindable TPC Clusters"}; + Configurable cfgTrackTPCCrossedRows{"cfgTrackTPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfgTrackRowsOverFindable{"cfgTrackRowsOverFindable", 1.2, "nRowsOverFindable TPC CLusters"}; + Configurable cfgTrackTPCChi2{"cfgTrackTPCChi2", 4.0, "nTPC Chi2 per Cluster"}; + + // ITS + Configurable cfgTrackITSChi2{"cfgTrackITSChi2", 36.0, "nITS Chi2 per Cluster"}; + + // PID + Configurable cfgTrackTPCPID{"cfgTrackTPCPID", true, "Enables TPC PID"}; + Configurable cfgTrackTOFPID{"cfgTrackTOFPID", true, "Enables TOF PID"}; + Configurable cfgTrackSquarePIDCut{"cfgTrackSqurePIDCut", true, "Enables PID cut shape square switch"}; + Configurable cfgTrackCirclePIDCut{"cfgTrackCirclePIDCut", true, "Enables PID cut shape circle switch"}; + Configurable cfgTrackCircleValue{"cfgTrackCircleValue", 2, "Enables TOF TPC PID circle cut value"}; + Configurable cfgTrackTOFHard{"cfgTrackTOFHard", false, "Enables TOF Hard"}; + + Configurable cfgTrackTPCPIDnSig{"cfgTrackTPCPIDnSig", 4.0, "nTPC PID sigma"}; + Configurable cfgTrackTOFPIDnSig{"cfgTrackTOFPIDnSig", 4.0, "nTOF PID sigma"}; + Configurable cDebugLevel{"cDebugLevel", 0, "Resolution of Debug"}; + + // Mixing + ConfigurableAxis cfgBinsMixMult{"cfgBinsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis cfgBinsMixVtx{"cfgBinsMixVtx", {VARIABLE_WIDTH, -10.0f, -5.f, 0.f, 5.f, 10.f}, "Mixing bins - z-vertex"}; + Configurable cfgMixNMixedEvents{"cfgMixNMixedEvents", 10, "Number of mixed events per event"}; + Configurable cfgVtxMixCut{"cfgVtxMixCut", 10, "Vertex Mix Cut"}; + + // MCGen + Configurable cfgForceGenReco{"cfgForceGenReco", false, "Only consider events which are reconstructed (neglect event-loss)"}; + Configurable cfgReqMcEffPID{"cfgReqMcEffPID", false, "Request McEfficiency PID"}; + + // Pair + Configurable cfgMinvNBins{"cfgMinvNBins", 300, "Number of bins for Minv axis"}; + Configurable cfgMinvMin{"cfgMinvMin", 0.60, "Minimum Minv value"}; + Configurable cfgMinvMax{"cfgMinvMax", 1.20, "Maximum Minv value"}; + + // Histogram + ConfigurableAxis binsDCAz{"binsDCAz", {40, -0.2, 0.2}, ""}; + ConfigurableAxis binsDCAxy{"binsDCAxy", {40, -0.2, 0.2}, ""}; + Configurable cfgEventCutQA{"cfgEventCutsQA", false, "Enable Event QA Hists"}; + Configurable cfgTrackCutQA{"cfgTrackCutQA", false, "Enable Track QA Hists"}; + + Configurable cfgMCHistos{"cfgMCHistos", false, "Enable MC Hists"}; + Configurable cfgMixedHistos{"cfgMixedHistos", false, "Enable Mixed Histos"}; + Configurable cfgManualEvSel{"cfgManualEvSel", false, "Enable Manual EvSel"}; + + // Main + void init(o2::framework::InitContext&) + { + // HISTOGRAMS + const AxisSpec axisEta{30, -1.5, +1.5, "#eta"}; + const AxisSpec axisPhi{200, -1, +7, "#phi"}; + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec pidAxis = {120, -6, 6}; + const AxisSpec minvAxis = {cfgMinvNBins, cfgMinvMin, cfgMinvMax}; + const AxisSpec axisDCAz{binsDCAz, "DCA_{z}"}; + const AxisSpec axisDCAxy{binsDCAxy, "DCA_{XY}"}; + + if (cfgEventCutQA) { + histos.add("hEvent_Cut", "Number of event after cuts", kTH1D, {{13, -0.5, 12.5}}); + histos.add("hPosZ_BC", "hPosZ_BC", kTH1F, {{300, -15.0, 15.0}}); + histos.add("hPosZ_AC", "hPosZ_AC", kTH1F, {{300, -15.0, 15.0}}); + histos.add("hcentFT0C_BC", "centFT0C_BC", kTH1F, {{110, 0.0, 110.0}}); + histos.add("hcentFT0C_AC", "centFT0C_AC", kTH1F, {{110, 0.0, 110.0}}); + } + if (cfgTrackCutQA) { + histos.add("hDCArToPv_BC", "DCArToPv_BC", kTH1F, {axisDCAxy}); + histos.add("hDCAzToPv_BC", "DCAzToPv_BC", kTH1F, {axisDCAz}); + histos.add("hIsPrim_BC", "hIsPrim_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_BC", "hIsGood_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_BC", "hIsPrimCont_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_BC", "hFindableTPCClusters_BC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_BC", "hFindableTPCRows_BC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_BC", "hClustersVsRows_BC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_BC", "hTPCChi2_BC", kTH1F, {{200, 0, 100}}); + histos.add("hITSChi2_BC", "hITSChi2_BC", kTH1F, {{200, 0, 100}}); + histos.add("QA_nSigma_pion_TPC_BC", "QA_nSigma_pion_TPC_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_pion_TOF_BC", "QA_nSigma_pion_TOF_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_pion_TPC_TOF_BC", "QA_pion_TPC_TOF_BC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TPC_BC", "QA_nSigma_kaon_TPC_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TOF_BC", "QA_nSigma_kaon_TOF_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_kaon_TPC_TOF_BC", "QA_kaon_TPC_TOF_BC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_track_pT_BC", "QA_track_pT_BC", kTH1F, {{13, 0.0, 13.0}}); + + histos.add("hDCArToPv_AC", "DCArToPv_AC", kTH1F, {axisDCAxy}); + histos.add("hDCAzToPv_AC", "DCAzToPv_AC", kTH1F, {axisDCAz}); + histos.add("hIsPrim_AC", "hIsPrim_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_AC", "hIsGood_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_AC", "hIsPrimCont_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_AC", "hFindableTPCClusters_AC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_AC", "hFindableTPCRows_AC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_AC", "hClustersVsRows_AC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_AC", "hTPCChi2_AC", kTH1F, {{200, 0, 100}}); + histos.add("hITSChi2_AC", "hITSChi2_AC", kTH1F, {{200, 0, 100}}); + histos.add("QA_nSigma_pion_TPC_AC", "QA_nSigma_pion_TPC_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_pion_TOF_AC", "QA_nSigma_pion_TOF_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_pion_TPC_TOF_AC", "QA_pion_TPC_TOF_AC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TPC_AC", "QA_nSigma_kaon_TPC_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TOF_AC", "QA_nSigma_kaon_TOF_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_kaon_TPC_TOF_AC", "QA_kaon_TPC_TOF_AC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_track_pT_AC", "QA_track_pT_AC", kTH1F, {{13, 0.0, 13.0}}); + } + + //////////////////////////////////// + histos.add("nEvents", "nEvents", kTH1F, {{7, 0.0, 7.0}}); + histos.add("hUSS_KPi", "hUSS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hUSS_PiK", "hUSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hLSS_KPi", "hLSS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hLSS_PiK", "hLSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + + if (cfgMixedHistos) { + histos.add("hUSS_KPi_Mix", "hUSS_KPi_Mix", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hUSS_PiK_Mix", "hUSS_PiK_Mix", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + } + if (cfgMCHistos) { + histos.add("nEvents_Gen", "nEvents_Gen", kTH1F, {{4, 0.0, 4.0}}); + histos.add("hUSS_TrueRec", "hUSS_TrueRec", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hGen_pT_Raw", "Gen_pT_Raw (GeV/c)", kTH1F, {{800, 0., 40.}}); + histos.add("hGen_pT_GoodEv", "hGen_pT_GoodEv", kTHnSparseF, {cfgCentAxis, ptAxis}); + } + + if (cfgEventCutQA) { + std::shared_ptr hCutFlow = histos.get(HIST("hEvent_Cut")); + std::vector eventCutLabels = { + "All Events", + "sel8", + Form("|Vz| < %.1f", cfgEventVtxCut.value), + "kIsGoodZvtxFT0vsPV", + "kNoSameBunchPileup", + "kNoTimeFrameBorder", + "kNoITSROFrameBorder", + "kNoCollInTimeRangeStandard", + "kIsGoodITSLayersAll", + Form("Occupancy < %.0f", cfgOccupancyMax.value), + "All passed events"}; + + for (size_t i = 0; i < eventCutLabels.size(); ++i) { + hCutFlow->GetXaxis()->SetBinLabel(i + 1, eventCutLabels[i].c_str()); + } + } + } // end of init + + //====================== + //|| For LF Analysis + //====================== + using EventCandidates = soa::Join; //, aod::CentFT0Ms, aod::CentFT0As + using EventCandidatesTrue = aod::McCollisions; + using TrackCandidates = soa::Join; + using TrackCandidatesMC = soa::Join; + + // For Mixed Event + using BinningType = ColumnBinningPolicy; + + Partition kaon = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfgTrackTPCPIDnSig); + Partition pion = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaPi) <= cfgTrackTPCPIDnSig); + Partition kaonMC = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfgTrackTPCPIDnSig); + Partition pionMC = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaPi) <= cfgTrackTPCPIDnSig); + + double massKa = o2::constants::physics::MassKPlus; + double massPi = o2::constants::physics::MassPiMinus; + + //================================== + //|| + //|| Helper Templates + //|| + //================================== + template + void fillQA(const bool pass, const objType& obj, const int objecttype = 0) + { + if (objecttype == 1) { + if constexpr (requires { obj.posZ(); }) { + if (!pass) { + histos.fill(HIST("hPosZ_BC"), obj.posZ()); + histos.fill(HIST("hcentFT0C_BC"), obj.centFT0C()); + } else { + histos.fill(HIST("hPosZ_AC"), obj.posZ()); + histos.fill(HIST("hcentFT0C_AC"), obj.centFT0C()); + } + } + } // eventSelection histogram + + if constexpr (requires { obj.tpcCrossedRowsOverFindableCls(); }) { + if (objecttype == 3) { + if (!pass) { + histos.fill(HIST("hDCArToPv_BC"), obj.dcaXY()); + histos.fill(HIST("hDCAzToPv_BC"), obj.dcaZ()); + histos.fill(HIST("hIsPrim_BC"), obj.isPrimaryTrack()); + histos.fill(HIST("hIsGood_BC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_BC"), obj.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_BC"), obj.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_BC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_BC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_BC"), obj.tpcChi2NCl()); + histos.fill(HIST("hITSChi2_BC"), obj.itsChi2NCl()); + histos.fill(HIST("QA_track_pT_BC"), obj.pt()); + } else { + histos.fill(HIST("hDCArToPv_AC"), obj.dcaXY()); + histos.fill(HIST("hDCAzToPv_AC"), obj.dcaZ()); + histos.fill(HIST("hIsPrim_AC"), obj.isPrimaryTrack()); + histos.fill(HIST("hIsGood_AC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_AC"), obj.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_AC"), obj.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_AC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_AC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_AC"), obj.tpcChi2NCl()); + histos.fill(HIST("hITSChi2_AC"), obj.itsChi2NCl()); + histos.fill(HIST("QA_track_pT_AC"), obj.pt()); + } + } + } // trackSelection + if (objecttype == 4) { + if constexpr (requires { obj.pt(); }) { + if (!pass) { + histos.fill(HIST("QA_nSigma_kaon_TPC_BC"), obj.pt(), obj.tpcNSigmaKa()); + histos.fill(HIST("QA_nSigma_kaon_TOF_BC"), obj.pt(), obj.tofNSigmaKa()); + histos.fill(HIST("QA_kaon_TPC_TOF_BC"), obj.tpcNSigmaKa(), obj.tofNSigmaKa()); + } else { + histos.fill(HIST("QA_nSigma_kaon_TPC_AC"), obj.pt(), obj.tpcNSigmaKa()); + histos.fill(HIST("QA_nSigma_kaon_TOF_AC"), obj.pt(), obj.tofNSigmaKa()); + histos.fill(HIST("QA_kaon_TPC_TOF_AC"), obj.tpcNSigmaKa(), obj.tofNSigmaKa()); + } + } + } // kaon pid Selection + if (objecttype == 5) { + if constexpr (requires { obj.pt(); }) { + if (!pass) { + histos.fill(HIST("QA_nSigma_pion_TPC_BC"), obj.pt(), obj.tpcNSigmaPi()); + histos.fill(HIST("QA_nSigma_pion_TOF_BC"), obj.pt(), obj.tofNSigmaPi()); + histos.fill(HIST("QA_pion_TPC_TOF_BC"), obj.tpcNSigmaPi(), obj.tofNSigmaPi()); + } else { + histos.fill(HIST("QA_nSigma_pion_TPC_AC"), obj.pt(), obj.tpcNSigmaPi()); + histos.fill(HIST("QA_nSigma_pion_TOF_AC"), obj.pt(), obj.tofNSigmaPi()); + histos.fill(HIST("QA_pion_TPC_TOF_AC"), obj.tpcNSigmaPi(), obj.tofNSigmaPi()); + } + } + } // pion pid Selection + } // fill QA + + enum class objectType { MB, + MBRecParticle }; + + template + void fillMinv(objectType type, const TrackType& trk1, const TrackType& trk2, const ROOT::Math::PxPyPzMVector& lReso, double centrality, bool IsMix, bool flip) + { + double conjugate = trk1.sign() * trk2.sign(); + switch (type) { + case objectType::MB: + if (IsMix && cfgMixedHistos) { + if (conjugate < 0) { + if (!flip) + histos.fill(HIST("hUSS_KPi_Mix"), centrality, lReso.Pt(), lReso.M()); + else + histos.fill(HIST("hUSS_PiK_Mix"), centrality, lReso.Pt(), lReso.M()); + } + } else { + if (conjugate < 0) { + if (!flip) + histos.fill(HIST("hUSS_KPi"), centrality, lReso.Pt(), lReso.M()); + else + histos.fill(HIST("hUSS_PiK"), centrality, lReso.Pt(), lReso.M()); + } else if (conjugate > 0) { + if (!flip) + histos.fill(HIST("hLSS_KPi"), centrality, lReso.Pt(), lReso.M()); + else + histos.fill(HIST("hLSS_PiK"), centrality, lReso.Pt(), lReso.M()); + } + } + break; + + case objectType::MBRecParticle: + if (cfgMCHistos) { + if (conjugate < 0) { + histos.fill(HIST("hUSS_TrueRec"), centrality, lReso.Pt(), lReso.M()); + } + } + break; + } // switch + } // fillMinv + //====================================================================== + + template + std::pair eventSelection(const EventType event, const bool QA) + { + if (cfgEventCutQA && QA) { + fillQA(false, event, 1); + histos.fill(HIST("hEvent_Cut"), 0); + } + + if (!event.sel8()) + return {false, 1}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 1); + } + if (std::abs(event.posZ()) > cfgEventVtxCut) + return {false, 2}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 2); + } + if (!event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return {false, 3}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 3); + } + if (!event.selection_bit(aod::evsel::kNoSameBunchPileup)) + return {false, 4}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 4); + } + if (!event.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return {false, 5}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 5); + } + if (!event.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return {false, 6}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 6); + } + if (!event.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) + return {false, 7}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 7); + } + if (!event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return {false, 8}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 8); + } + if (cfgOccupancySel && (event.trackOccupancyInTimeRange() > cfgOccupancyMax || event.trackOccupancyInTimeRange() < cfgOccupancyMin)) + return {false, 9}; + if (cfgEventCutQA && QA) { + histos.fill(HIST("hEvent_Cut"), 9); + } + + if (cfgEventCutQA && QA) { + fillQA(true, event, 1); + histos.fill(HIST("hEvent_Cut"), 10); + } + return {true, 11}; + }; + + template + bool trackSelection(const TracksType track, const bool QA) + { + if (cfgTrackCutQA && QA) { + fillQA(false, track, 3); + } + + if (cfgTrackGlobalSel && !track.isGlobalTrack()) + return false; + if (track.pt() < cfgTrackMinPt) + return false; + if (std::abs(track.eta()) > cfgTrackMaxEta) + return false; + if (std::abs(track.dcaXY()) > cfgTrackMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cfgTrackMaxDCAzToPVcut) + return false; + if (cfgTrackPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgTrackGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgTrackFindableTPCClusters > 0 && track.tpcNClsFindable() < cfgTrackFindableTPCClusters) + return false; + if (track.tpcNClsCrossedRows() < cfgTrackTPCCrossedRows) + return false; + if (cfgTrackRowsOverFindable > 0 && track.tpcCrossedRowsOverFindableCls() > cfgTrackRowsOverFindable) + return false; + if (track.tpcChi2NCl() > cfgTrackTPCChi2) + return false; + if (track.itsChi2NCl() > cfgTrackITSChi2) + return false; + if (cfgTrackConnectedToPV && !track.isPVContributor()) + return false; + + if (cfgTrackCutQA && QA) { + fillQA(true, track, 3); + } + return true; + }; + + template + bool trackPIDKaon(const TrackPID& candidate, const bool QA) + { + double tpcpid = 0; + double tofpid = 0; + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (cfgTrackCutQA && QA) { + fillQA(false, candidate, 4); + } + + // TPC + if (cfgTrackSquarePIDCut) { + if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) + tpcPIDPassed = true; + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < cfgTrackTOFPIDnSig) { + tofPIDPassed = true; + } + } else { + if (!cfgTrackTOFHard) { + tofPIDPassed = true; + } else { + tofPIDPassed = false; + } + } + } // end of square cut + if (cfgTrackCirclePIDCut) { + if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) + tpcpid = std::abs(candidate.tpcNSigmaKa()); + tofpid = 0; + + if (candidate.hasTOF()) { + tofpid = std::abs(candidate.tofNSigmaKa()); + } else { + if (cfgTrackTOFHard) { + tofpid = 999; + } + } + if (tpcpid * tpcpid + tofpid * tofpid < cfgTrackCircleValue) { + tpcPIDPassed = true; + tofPIDPassed = true; + } + } // circular cut + + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + if (cfgTrackCutQA && QA) { + fillQA(true, candidate, 4); + } + return true; + } + return false; + } + + template + bool trackPIDPion(const TrackPID& candidate, const bool QA) + { + double tpcpid = 0; + double tofpid = 0; + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (cfgTrackCutQA && QA) { + fillQA(false, candidate, 5); + } + + // TPC + if (cfgTrackSquarePIDCut) { + if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) + tpcPIDPassed = true; + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cfgTrackTOFPIDnSig) { + tofPIDPassed = true; + } + } else { + if (!cfgTrackTOFHard) { + tofPIDPassed = true; + } else { + tofPIDPassed = false; + } + } + } // end of square cut + if (cfgTrackCirclePIDCut) { + if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) + tpcpid = std::abs(candidate.tpcNSigmaPi()); + tofpid = 0; + + if (candidate.hasTOF()) { + tofpid = std::abs(candidate.tofNSigmaPi()); + } else { + if (cfgTrackTOFHard) { + tofpid = 999; + } + } + if (tpcpid * tpcpid + tofpid * tofpid < cfgTrackCircleValue) { + tpcPIDPassed = true; + tofPIDPassed = true; + } + } // circular cut + + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + if (cfgTrackCutQA && QA) { + fillQA(true, candidate, 5); + } + return true; + } + return false; + } + + template + ROOT::Math::PxPyPzMVector minvReconstruction(const TracksType& trk1, const TracksType& trk2, const bool QA, const bool flip) + { + if (!trackSelection(trk1, false) || !trackSelection(trk2, false)) + return {}; + + if (!trackPIDKaon(trk1, QA) || !trackPIDPion(trk2, QA)) + return {}; + + if (trk1.globalIndex() >= trk2.globalIndex()) + return {}; + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + if (!flip) { + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massPi); + } else { + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massPi); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + } + lResonance = lDecayDaughter1 + lDecayDaughter2; + + if (std::abs(lResonance.Eta()) > cfgTrackMaxEta) + return {}; + return {lResonance}; + } + + template + ROOT::Math::PxPyPzMVector TrueReconstruction(const TracksType& trk1, const TracksType& trk2) + { + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate > 0) + return {}; + + auto particle1 = trk1.mcParticle(); + auto particle2 = trk2.mcParticle(); + + if (!particle1.has_mothers() || !particle2.has_mothers()) { + return {}; + } + + std::vector mothers1{}; + std::vector mothers1PDG{}; + for (auto& particle1_mom : particle1.template mothers_as()) { + mothers1.push_back(particle1_mom.globalIndex()); + mothers1PDG.push_back(particle1_mom.pdgCode()); + } + + std::vector mothers2{}; + std::vector mothers2PDG{}; + for (auto& particle2_mom : particle2.template mothers_as()) { + mothers2.push_back(particle2_mom.globalIndex()); + mothers2PDG.push_back(particle2_mom.pdgCode()); + } + + if (mothers1PDG[0] != 313) + return {}; // mother not K*0 + if (mothers2PDG[0] != 313) + return {}; // mothers not K*0 + + if (mothers1[0] != mothers2[0]) + return {}; // Kaon and pion not from the same K*0 + + if (std::fabs(particle1.pdgCode()) != 211 && std::fabs(particle1.pdgCode()) != 321) + return {}; + if (std::fabs(particle2.pdgCode()) != 211 && std::fabs(particle2.pdgCode()) != 321) + return {}; + + double track1_mass, track2_mass; + if (std::fabs(particle1.pdgCode()) == 211) { + track1_mass = massPi; + } else { + track1_mass = massKa; + } + + if (std::fabs(particle2.pdgCode()) == 211) { + track2_mass = massPi; + } else { + track2_mass = massKa; + } + + if (track1_mass == track2_mass) { + return {}; + } + + ROOT::Math::PxPyPzMVector lTrueDaughter1, lTrueDaughter2, lTrueReso; + lTrueDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), track1_mass); + lTrueDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), track2_mass); + lTrueReso = lTrueDaughter1 + lTrueDaughter2; + + if (lTrueReso.M() < 0) + return {}; + + return {lTrueReso}; + } + + template + void TrackSlicing(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool IsMix, const bool QA) + { + auto tracks1 = kaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto tracks2 = pion->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (bool flip : {false, true}) { + auto lReso = minvReconstruction(trk1, trk2, QA, flip); + if (lReso.M() < 0) + continue; + + fillMinv(objectType::MB, trk1, trk2, lReso, centrality, IsMix, flip); + } // flip + } // for + } // TrackSlicing + + template + void TrackSlicingMC(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool IsMix, const bool QA) + { + auto tracks1 = kaonMC->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto tracks2 = pionMC->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) + continue; + + for (bool flip : {false, true}) { + auto lReso = minvReconstruction(trk1, trk2, QA, flip); + if (lReso.M() < 0) + continue; + + fillMinv(objectType::MB, trk1, trk2, lReso, centrality, IsMix, flip); + } // flip + + //============================ + //| True Reconstruction + //============================ + auto lTrueReso = TrueReconstruction(trk1, trk2); + fillMinv(objectType::MBRecParticle, trk1, trk2, lTrueReso, centrality, IsMix, false); + } // tracks + } // TrackSlicingMC + + //======================================================= + //| + //| DATA STUFF (SE) + //| + //======================================================= + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + if (cDebugLevel > 0) { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + } + + auto [goodEv, code] = eventSelection(collision, true); + histos.fill(HIST("nEvents"), 0.5); + + if (!goodEv) + return; + + bool INELgt0 = false; + for (const auto& track : tracks) { + if (!trackSelection(track, true)) + continue; + if (std::fabs(track.eta()) < cfgTrackMaxEta) { + INELgt0 = true; + } + } + if (!INELgt0) + return; + histos.fill(HIST("nEvents"), 1.5); + + TrackSlicing(collision, tracks, collision, tracks, false, true); + + } // processSameEvents + PROCESS_SWITCH(kstar0analysis, processDataSameEvent, "process Data Same Event", false); + + //======================================================= + //| + //| DATA STUFF (ME) + //| + //======================================================= + int nEventsMix = 0; + void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningType colBinning{{cfgBinsMixVtx, cfgBinsMixMult}, true}; // true is for 'ignore overflows' (true by default) + SameKindPair pairs{colBinning, cfgMixNMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + nEventsMix++; + if ((nEventsMix + 1) % 10000 == 0) { + std::cout << "Processed DATA Mixed Events : " << nEventsMix << std::endl; + } + } + auto [goodEv1, code1] = eventSelection(collision1, false); + auto [goodEv2, code2] = eventSelection(collision2, false); + bool VtxMixFlag = false; + bool CentMixFlag = false; + // bool OccupanacyMixFlag = false; + if (std::fabs(collision1.posZ() - collision2.posZ()) <= cfgVtxMixCut) // set default to maybe 10 + VtxMixFlag = true; + if (std::fabs(collision1.centFT0C() - collision2.centFT0C()) <= cfgVtxMixCut) // set default to maybe 10 + CentMixFlag = true; + + if (!goodEv1 || !goodEv2) + continue; + if (!CentMixFlag) + continue; + if (!VtxMixFlag) + continue; + + TrackSlicing(collision1, tracks1, collision2, tracks2, true, false); + } + } + PROCESS_SWITCH(kstar0analysis, processDataMixedEvent, "process DATA Mixed Event", false); + + //======================================================= + //| + //| MC STUFF (SE) + //| + //========================================================= + int nEventsMC = 0; + void processSameEventMC(EventCandidates::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&) + { + if (cDebugLevel > 0) { + nEventsMC++; + if ((nEventsMC + 1) % 10000 == 0) { + double histmem = histos.getSize(); + std::cout << histmem << std::endl; + std::cout << "process_SameEvent_MC: " << nEventsMC << std::endl; + } + } + auto [goodEv, code] = eventSelection(collision, true); + + histos.fill(HIST("nEvents"), 0.5); + + if (!goodEv) + return; + + bool INELgt0 = false; + for (const auto& track : tracks) { + if (!trackSelection(track, true)) + continue; + if (std::fabs(track.eta()) < cfgTrackMaxEta) { + INELgt0 = true; + } + } + if (!INELgt0) + return; + + histos.fill(HIST("nEvents"), 1.5); + + TrackSlicingMC(collision, tracks, collision, tracks, false, true); + } // processSameEvents_MC + PROCESS_SWITCH(kstar0analysis, processSameEventMC, "process Same Event MC", false); + + //======================================================= + //| + //| MC STUFF (ME) + //| + //======================================================= + int nEventsMCMix = 0; + void processMixedEventMC(EventCandidates const& collisions, TrackCandidatesMC const& tracks, aod::McParticles const&) + { + auto tracksTuple = std::make_tuple(tracks); + BinningType colBinning{{cfgBinsMixVtx, cfgBinsMixMult}, true}; // true is for 'ignore overflows' (true by default) + SameKindPair pairs{colBinning, cfgMixNMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + nEventsMCMix++; + if ((nEventsMCMix + 1) % 10000 == 0) { + std::cout << "Processed Mixed Events: " << nEventsMCMix << std::endl; + } + } + auto [goodEv1, code1] = eventSelection(collision1, false); + auto [goodEv2, code2] = eventSelection(collision2, false); + if (!goodEv1 || !goodEv2) { + continue; + } + + TrackSlicingMC(collision1, tracks1, collision2, tracks2, true, false); + } // mixing + } // processMixedEvent_MC + PROCESS_SWITCH(kstar0analysis, processMixedEventMC, "process Mixed Event MC", false); + + //====================================== + //| + //| GENERATED STUFF + //| + //====================================== + int nEventsGen = 0; + void processGen(EventCandidatesTrue::iterator const& collision, soa::SmallGroups> const& recocolls, aod::McParticles const& mcParticles) + { + if (cDebugLevel > 0) { + ++nEventsGen; + if (nEventsGen % 10000 == 0) { + std::cout << "Processed MC (GEN) Events: " << nEventsGen << std::endl; + } + } + //======================= + //|| Event & Signal loss + //======================= + if (cfgMCHistos) { + histos.fill(HIST("nEvents_Gen"), 0.5); + } + + for (auto& particle : mcParticles) { + if (particle.pdgCode() != 313) + continue; + if (std::fabs(particle.eta()) > cfgTrackMaxEta) + continue; + if (fabs(collision.posZ()) > cfgEventVtxCut) + break; + + if (cfgMCHistos) { + histos.fill(HIST("hGen_pT_Raw"), particle.pt()); + } + } // Unreconstructed collisions(=Raw coll) for correction + + if (recocolls.size() <= 0) { // not reconstructed + if (cfgForceGenReco) { + return; + } + } + double centrality = -1; + for (auto& recocoll : recocolls) { + centrality = recocoll.centFT0C(); + auto [goodEv, code] = eventSelection(recocoll, true); + + if (cfgMCHistos) { + histos.fill(HIST("nEvents_Gen"), 1.5); + } + if (!goodEv) + continue; + } // recocolls (=reconstructed collisions) + + //================= + //|| Efficiency + //================= + for (auto& particle : mcParticles) { + if (particle.pdgCode() != 313) + continue; // Not K*0 + if (std::fabs(particle.eta()) > cfgTrackMaxEta) + continue; + + if (cfgMCHistos) { + histos.fill(HIST("nEvents_Gen"), 2.5); + histos.fill(HIST("hGen_pT_GoodEv"), centrality, particle.pt()); + } // cfgMCHistos + } // loop over particles + } // processMCTrue + PROCESS_SWITCH(kstar0analysis, processGen, "process Generated Particles", false); + + void processEventsDummy(EventCandidates::iterator const&, TrackCandidates const&) + { + return; + } + PROCESS_SWITCH(kstar0analysis, processEventsDummy, "dummy", false); +}; // kstar0analysis +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/kstarqa.cxx b/PWGLF/Tasks/Resonances/kstarqa.cxx index 325139e0304..26a9c5aed59 100644 --- a/PWGLF/Tasks/Resonances/kstarqa.cxx +++ b/PWGLF/Tasks/Resonances/kstarqa.cxx @@ -91,6 +91,7 @@ struct Kstarqa { Configurable isapplypTdepPIDTOF{"isapplypTdepPIDTOF", false, "Apply pT dependent PID for TOF"}; Configurable isApplyParticleMID{"isApplyParticleMID", false, "Apply particle misidentification"}; Configurable isApplyParticleMIDPtDep{"isApplyParticleMIDPtDep", false, "Apply pT dependent MID selection"}; + Configurable AllGenEvents{"AllGenEvents", false, "Fill all generated events in MC for signal loss calculations"}; Configurable checkVzEvSigLoss{"checkVzEvSigLoss", false, "Check Vz event signal loss"}; Configurable isApplyDeepAngle{"isApplyDeepAngle", false, "Deep Angle cut"}; @@ -2761,7 +2762,7 @@ struct Kstarqa { const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); hInvMass.fill(HIST("hAllGenCollisions"), multiplicity); - if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + if (!selectionConfig.AllGenEvents && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection return; } double genMultiplicity = mcCollision.centFT0M(); diff --git a/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx b/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx index d8edd64cdb9..6af3bde09f8 100644 --- a/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx @@ -29,9 +29,6 @@ #include #include -#include -#include - #include using namespace o2; @@ -56,7 +53,15 @@ struct lambdaAnalysis_pb { Configurable cPMin{"cPMin", 0., "Minimum Track p"}; Configurable cEtaCut{"cEtaCut", 0.8, "Pseudorapidity cut"}; Configurable cDcaz{"cDcazMin", 1., "Minimum DCAz"}; - Configurable cDcaxy{"cDcaxyMin", 0.1, "Minimum DCAxy"}; + + Configurable> cDcaPtBinsPr{"cDcaPtBinsPr", {0.0f, 0.5f, 1.0f, 2.0f, 3.0f, 5.0f, 1000.0f}, "Proton pT bin edges for DCAxy cut"}; + + Configurable> cDcaXYBinsPr{"cDcaXYBinsPr", {0.020f, 0.015f, 0.010f, 0.007f, 0.005f, 0.004f}, "Proton max |DCAxy| per pT bin (cm)"}; + + // Kaon DCAxy — pT binned + Configurable> cDcaPtBinsKa{"cDcaPtBinsKa", {0.0f, 0.3f, 0.6f, 1.0f, 2.0f, 1000.0f}, "Kaon pT bin edges for DCAxy cut"}; + + Configurable> cDcaXYBinsKa{"cDcaXYBinsKa", {0.025f, 0.018f, 0.012f, 0.008f, 0.004f}, "Kaon max |DCAxy| per pT bin (cm)"}; Configurable isonlyQC{"isonlyQC", false, "only QC"}; Configurable isDeepAngle{"isDeepAngle", false, "Deep Angle cut"}; Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; @@ -108,6 +113,16 @@ struct lambdaAnalysis_pb { ConfigurableAxis cMixMultBins{"cMixMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 200.0f}, "Mixing bins - multiplicity"}; ConfigurableAxis cMixEPAngle{"cMixEPAngle", {VARIABLE_WIDTH, -1.5708f, -1.25664f, -0.942478f, -0.628319f, 0.f, 0.628319f, 0.942478f, 1.25664f, 1.5708f}, "event plane"}; ConfigurableAxis occupancy_bins{"occupancy_bins", {VARIABLE_WIDTH, 0.0, 100, 500, 600, 1000, 1100, 1500, 1600, 2000, 2100, 2500, 2600, 3000, 3100, 3500, 3600, 4000, 4100, 4500, 4600, 5000, 5100, 9999}, "Binning of the occupancy axis"}; + Configurable cNofRotations{"cNofRotations", 10, "Number of rotations for rotational background"}; + Configurable rotationalcut{"rotationalcut", 6.f, "Rotational background angle window: PI/rotationalcut"}; + + // ── MC Event Selection Configurables ───────────────────────────────────── + Configurable cEvtMCAfterAllCuts{"cEvtMCAfterAllCuts", false, "MC event sel: isInAfterAllCuts"}; + Configurable cEvtMCINELgt0{"cEvtMCINELgt0", false, "MC event sel: isINELgt0"}; + Configurable cEvtMCSel8{"cEvtMCSel8", false, "MC event sel: isInSel8"}; + Configurable cEvtMCVtxIn10{"cEvtMCVtxIn10", false, "MC event sel: isVtxIn10"}; + Configurable cEvtMCTriggerTVX{"cEvtMCTriggerTVX", false, "MC event sel: isTriggerTVX"}; + Configurable cEvtMCRecINELgt0{"cEvtMCRecINELgt0", false, "MC event sel: isRecINELgt0"}; // Histogram Registry. HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -131,6 +146,7 @@ struct lambdaAnalysis_pb { AxisSpec axisDCAz = {cDCAzBins, "DCA_{z} (cm)"}; histos.add("Event/h1d_ft0_mult_percentile", "FT0 (%)", kTH2F, {axisCent, axisOccupancy}); + histos.add("Event/h_ft0_vz", "Collision Vertex Z position", kTH1F, {{100, -15., 15.}}); if (doprocessMix || doprocessMixDF || doprocessMixepDF) { histos.add("Event/mixing_vzVsmultpercentile", "FT0(%)", kTH3F, {axisCent, axisVz, axisEP}); } @@ -208,19 +224,58 @@ struct lambdaAnalysis_pb { if (std::abs(track.eta()) > cEtaCut) return false; - if (std::abs(track.dcaZ()) > cDcaz) + if (cPrimaryTrack && !track.isPrimaryTrack()) return false; - if (std::abs(track.dcaXY()) > cDcaxy) + if (cGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) return false; - if (cPrimaryTrack && !track.isPrimaryTrack()) + if (cPVContributor && !track.isPVContributor()) return false; - if (cGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return true; + } + // ── Proton DCA Selection ────────────────────────────────────────────────── + template + bool dcaSelectionProton(T const& track, float p) + { + auto ptBinsPr = static_cast>(cDcaPtBinsPr); + auto dcaXYPr = static_cast>(cDcaXYBinsPr); + int nBinsPr = static_cast(ptBinsPr.size()) - 1; + + bool dcaXYPassed = false; + for (int i = 0; i < nBinsPr; i++) { + if (p >= ptBinsPr[i] && p < ptBinsPr[i + 1] && + std::abs(track.dcaXY()) < dcaXYPr[i]) + dcaXYPassed = true; + } + if (!dcaXYPassed) return false; - if (cPVContributor && !track.isPVContributor()) + if (std::abs(track.dcaZ()) > cDcaz) + return false; + + return true; + } + + // ── Kaon DCA Selection ──────────────────────────────────────────────────── + template + bool dcaSelectionKaon(T const& track, float p) + { + auto ptBinsKa = static_cast>(cDcaPtBinsKa); + auto dcaXYKa = static_cast>(cDcaXYBinsKa); + int nBinsKa = static_cast(ptBinsKa.size()) - 1; + + bool dcaXYPassed = false; + for (int i = 0; i < nBinsKa; i++) { + if (p >= ptBinsKa[i] && p < ptBinsKa[i + 1] && + std::abs(track.dcaXY()) < dcaXYKa[i]) + dcaXYPassed = true; + } + if (!dcaXYPassed) + return false; + + if (std::abs(track.dcaZ()) > cDcaz) return false; return true; @@ -362,8 +417,6 @@ struct lambdaAnalysis_pb { void fillDataHistos(trackType const& trk1, trackType const& trk2, float mult, int occup = 100) { - TLorentzVector p1, p2, p; - TRandom* rn = new TRandom(); float p_ptot = 0., k_ptot = 0.; for (auto const& [trkPr, trkKa] : soa::combinations(soa::CombinationsFullIndexPolicy(trk1, trk2))) { @@ -412,6 +465,9 @@ struct lambdaAnalysis_pb { continue; if (!selectionPIDProton(trkPr, p_ptot) || !selectionPIDKaon(trkKa, k_ptot)) continue; + if (!dcaSelectionProton(trkPr, p_ptot) || !dcaSelectionKaon(trkKa, k_ptot)) + continue; + if (isDeepAngle && TMath::ACos((trkPr.pt() * trkKa.pt() + _pzPr * _pzKa) / (p_ptot * k_ptot)) < cfgDeepAngle) continue; @@ -461,39 +517,56 @@ struct lambdaAnalysis_pb { if (isonlyQC) continue; - // Invariant mass reconstruction. - p1.SetXYZM(_pxPr, _pyPr, _pzPr, MassProton); - p2.SetXYZM(_pxKa, _pyKa, _pzKa, MassKaonCharged); - p = p1 + p2; - if (std::abs(p.Rapidity()) > 0.5) - continue; + std::array pvec0 = {_pxPr, _pyPr, _pzPr}; + std::array pvec1 = {_pxKa, _pyKa, _pzKa}; + std::array, 2> arrMomrec = {pvec0, pvec1}; + + float _M = RecoDecay::m(arrMomrec, std::array{MassProton, MassKaonCharged}); + float _pt = RecoDecay::pt(std::array{_pxPr + _pxKa, _pyPr + _pyKa}); - auto _M = p.M(); - auto _pt = p.Pt(); + if (std::abs(RecoDecay::y(std::array{_pxPr + _pxKa, _pyPr + _pyKa, _pzPr + _pzKa}, MassLambda1520)) > 0.5) + continue; // Apply kinematic cuts. - if (cKinCuts) { - TVector3 v1(_pxPr, _pyPr, _pzPr); - TVector3 v2(_pxKa, _pyKa, _pzKa); - float alpha = v1.Angle(v2); - if (alpha > 1.4 && alpha < 2.4) - continue; - } // Fill Invariant Mass Histograms. if constexpr (!mix && !mc) { if (trkPr.sign() * trkKa.sign() < 0) { + if (trkPr.sign() > 0) histos.fill(HIST("Analysis/h4d_lstar_invm_US_PM"), _M, _pt, mult, occup); else histos.fill(HIST("Analysis/h4d_lstar_invm_US_MP"), _M, _pt, mult, occup); + if (doRotate) { - float theta = rn->Uniform(1.56, 1.58); - p1.RotateZ(theta); - p = p1 + p2; - if (std::abs(p.Rapidity()) < 0.5) { - histos.fill(HIST("Analysis/h4d_lstar_invm_rot"), p.M(), p.Pt(), mult, occup); + for (int i = 0; i < cNofRotations; i++) { + + float delta = o2::constants::math::PI / rotationalcut; + float theta2 = (o2::constants::math::PI - delta) + i * (2.f * delta / (cNofRotations - 1)); + + float phiRot = trkKa.phi() + theta2; + if (phiRot > o2::constants::math::TwoPI) + phiRot -= o2::constants::math::TwoPI; + if (phiRot < 0.f) + phiRot += o2::constants::math::TwoPI; + + float _pxKaRot = trkKa.pt() * std::cos(phiRot); + float _pyKaRot = trkKa.pt() * std::sin(phiRot); + + std::array pvec0rot = {_pxPr, _pyPr, _pzPr}; + std::array pvec1rot = {_pxKaRot, _pyKaRot, _pzKa}; + std::array, 2> arrMomRot = {pvec0rot, pvec1rot}; + + float _Mrot = RecoDecay::m(arrMomRot, std::array{MassProton, MassKaonCharged}); + float _ptRot = RecoDecay::pt(std::array{_pxPr + _pxKaRot, _pyPr + _pyKaRot}); + + if (std::abs(RecoDecay::y( + std::array{_pxPr + _pxKaRot, _pyPr + _pyKaRot, _pzPr + _pzKa}, + MassLambda1520)) > 0.5f) + continue; + + histos.fill(HIST("Analysis/h4d_lstar_invm_rot"), _Mrot, _ptRot, mult, occup); } } } else { @@ -542,6 +615,8 @@ struct lambdaAnalysis_pb { } using resoCols = soa::Join; + using resoMCCols = soa::Join; + using resoTracks = aod::ResoTracks; void processData(resoCols::iterator const& collision, resoTracks const& tracks) @@ -549,17 +624,32 @@ struct lambdaAnalysis_pb { // LOGF(info, " collisions: Index = %d %d", collision.globalIndex(),tracks.size()); histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent(), 100); + histos.fill(HIST("Event/h_ft0_vz"), collision.posZ()); + fillDataHistos(tracks, tracks, collision.cent()); } PROCESS_SWITCH(lambdaAnalysis_pb, processData, "Process for Same Event Data", true); - void processMC(resoCols::iterator const& collision, + void processMC(resoMCCols::iterator const& collision, soa::Join const& tracks, aod::ResoMCParents const& resoParents) { + if (cEvtMCAfterAllCuts && !collision.isInAfterAllCuts()) + return; + if (cEvtMCINELgt0 && !collision.isINELgt0()) + return; + if (cEvtMCSel8 && !collision.isInSel8()) + return; + if (cEvtMCVtxIn10 && !collision.isVtxIn10()) + return; + if (cEvtMCTriggerTVX && !collision.isTriggerTVX()) + return; + if (cEvtMCRecINELgt0 && !collision.isRecINELgt0()) + return; auto mult = collision.cent(); histos.fill(HIST("Event/h1d_ft0_mult_percentile"), mult, 100); + histos.fill(HIST("Event/h_ft0_vz"), collision.posZ()); fillDataHistos(tracks, tracks, mult); // get MC pT-spectra @@ -587,9 +677,9 @@ struct lambdaAnalysis_pb { } for (auto const& part : resoParents) { - if (abs(part.pdgCode()) != lambda1520id) // // L* pdg_code = 3124 + if (std::abs(part.pdgCode()) != lambda1520id) // // L* pdg_code = 3124 continue; - if (abs(part.y()) > 0.5) { // rapidity cut + if (std::abs(part.y()) > 0.5) { // rapidity cut continue; } @@ -605,10 +695,10 @@ struct lambdaAnalysis_pb { if (!pass1 || !pass2) // If we have both decay products continue; + std::array pvec = {part.px(), part.py(), part.pz()}; + + float mass = RecoDecay::m(pvec, part.e()); - TLorentzVector p4; - p4.SetPxPyPzE(part.px(), part.py(), part.pz(), part.e()); - auto mass = p4.M(); if (part.pdgCode() > 0) histos.fill(HIST("Analysis/h3d_gen_lstar_PM"), mass, part.pt(), mult); else diff --git a/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx index 3d3aac5b773..fada8bbc6e4 100644 --- a/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx @@ -14,6 +14,7 @@ /// \author Hirak Kumar Koley #include "PWGLF/Utils/collisionCuts.h" +#include "PWGLF/Utils/inelGt.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" @@ -92,15 +93,15 @@ struct Lambda1520analysisinpp { Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.0f, "Evt sel: Max. z-Vertex (cm)"}; Configurable cfgEvtOccupancyInTimeRangeMax{"cfgEvtOccupancyInTimeRangeMax", -1, "Evt sel: maximum track occupancy"}; Configurable cfgEvtOccupancyInTimeRangeMin{"cfgEvtOccupancyInTimeRangeMin", -1, "Evt sel: minimum track occupancy"}; - Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; - Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", true, "Evt sel: check for offline selection"}; - Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; - Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; - Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; - Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", false, "Evt sel: apply Z-vertex time difference"}; - Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", false, "Evt sel: apply pileup rejection"}; - Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; - Configurable cfgEvtCollInTimeRangeStandard{"cfgEvtCollInTimeRangeStandard", false, "Evt sel: apply NoCollInTimeRangeStandard"}; + Configurable cfgEvtSel8{"cfgEvtSel8", false, "Evt Sel 8 check for offline selection"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", true, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtNoTFBorderCut{"cfgEvtNoTFBorderCut", true, "Evt sel: apply TF border cut"}; + Configurable cfgEvtIsVertexITSTPC{"cfgEvtIsVertexITSTPC", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable cfgEvtIsGoodZvtxFT0vsPV{"cfgEvtIsGoodZvtxFT0vsPV", true, "Evt sel: apply Z-vertex time difference"}; + Configurable cfgEvtNoSameBunchPileup{"cfgEvtNoSameBunchPileup", false, "Evt sel: apply pileup rejection"}; + Configurable cfgEvtNoITSROFrameBorderCut{"cfgEvtNoITSROFrameBorderCut", false, "Evt sel: apply NoITSRO border cut"}; + Configurable cfgEvtNoCollInTimeRangeStandard{"cfgEvtNoCollInTimeRangeStandard", false, "Evt sel: apply NoNoCollInTimeRangeStandard"}; + Configurable cfgEvtIsVertexTOFmatched{"cfgEvtIsVertexTOFmatched", true, "kIsVertexTOFmatched: apply vertex TOF matched"}; } configEvents; struct : ConfigurableGroup { @@ -157,7 +158,7 @@ struct Lambda1520analysisinpp { /// Event Mixing Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f}, "Mixing bins - z-vertex"}; - ConfigurableAxis cfgMultBins{"cfgMultBins", {VARIABLE_WIDTH, 0.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"}; + ConfigurableAxis cfgMultPercentileBins{"cfgMultPercentileBins", {VARIABLE_WIDTH, 0.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"}; // Rotational background Configurable rotationalcut{"rotationalcut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; @@ -174,7 +175,6 @@ struct Lambda1520analysisinpp { Configurable cfgUseDaughterEtaCutMC{"cfgUseDaughterEtaCutMC", false, "Switch to turn on/off eta cuts for daughters in MC"}; // MC selection cut - Configurable cZvertCutMC{"cZvertCutMC", 10.0f, "MC Z-vertex cut"}; Configurable cEtacutMC{"cEtacutMC", 0.5f, "MC eta cut"}; Configurable cUseRapcutMC{"cUseRapcutMC", true, "MC eta cut"}; Configurable cUseEtacutMC{"cUseEtacutMC", true, "MC eta cut"}; @@ -218,7 +218,7 @@ struct Lambda1520analysisinpp { // Filter primarytrackFilter = requirePVContributor() && requirePrimaryTrack() && requireGlobalTrackWoDCA(); using EventCandidates = soa::Join; - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; using MCEventCandidates = soa::Join; using MCTrackCandidates = soa::Filtered>; @@ -237,16 +237,17 @@ struct Lambda1520analysisinpp { void init(framework::InitContext&) { - colCuts.setCuts(configEvents.cfgEvtZvtx, configEvents.cfgEvtTriggerCheck, configEvents.cfgEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, configEvents.cfgEvtOccupancyInTimeRangeMax, configEvents.cfgEvtOccupancyInTimeRangeMin); + colCuts.setCuts(configEvents.cfgEvtZvtx, /* configEvents.cfgEvtTriggerCheck */ false, configEvents.cfgEvtSel8, /*checkRun3*/ true, /*triggerTVXsel*/ false, configEvents.cfgEvtOccupancyInTimeRangeMax, configEvents.cfgEvtOccupancyInTimeRangeMin); colCuts.init(&histos); colCuts.setTriggerTVX(configEvents.cfgEvtTriggerTVXSel); - colCuts.setApplyTFBorderCut(configEvents.cfgEvtTFBorderCut); - colCuts.setApplyITSTPCvertex(configEvents.cfgEvtUseITSTPCvertex); - colCuts.setApplyZvertexTimedifference(configEvents.cfgEvtZvertexTimedifference); - colCuts.setApplyPileupRejection(configEvents.cfgEvtPileupRejection); - colCuts.setApplyNoITSROBorderCut(configEvents.cfgEvtNoITSROBorderCut); - colCuts.setApplyCollInTimeRangeStandard(configEvents.cfgEvtCollInTimeRangeStandard); + colCuts.setApplyTFBorderCut(configEvents.cfgEvtNoTFBorderCut); + colCuts.setApplyITSTPCvertex(configEvents.cfgEvtIsVertexITSTPC); + colCuts.setApplyZvertexTimedifference(configEvents.cfgEvtIsGoodZvtxFT0vsPV); + colCuts.setApplyPileupRejection(configEvents.cfgEvtNoSameBunchPileup); + colCuts.setApplyNoITSROBorderCut(configEvents.cfgEvtNoITSROFrameBorderCut); + colCuts.setApplyCollInTimeRangeStandard(configEvents.cfgEvtNoCollInTimeRangeStandard); + colCuts.setApplyVertexTOFmatched(configEvents.cfgEvtIsVertexTOFmatched); colCuts.printCuts(); // axes @@ -255,26 +256,27 @@ struct Lambda1520analysisinpp { AxisSpec axisEta{binsEta, "#eta"}; AxisSpec axisRap{binsEta, "#it{y}"}; AxisSpec axisMassLambda1520{binsMass, "Invariant Mass (GeV/#it{c}^2)"}; - AxisSpec axisMult{binsMult, "mult_{V0M}"}; + AxisSpec axisMult{binsMult, "mult_{FT0M}"}; AxisSpec axisDCAz{binsDCAz, "DCA_{z}"}; AxisSpec axisDCAxy{binsDCAxy, "DCA_{XY}"}; AxisSpec axisTPCXrow{binsTPCXrows, "#Xrows_{TPC}"}; AxisSpec axisPIDQA{binsnSigma, "#sigma"}; AxisSpec axisTPCSignal{binsnTPCSignal, ""}; - AxisSpec axisMClabel{6, -1.5f, 5.5f, "MC Label"}; + AxisSpec axisMClabel{9, -1.f, 8.f, "MC Label"}; AxisSpec axisEtaPhi{binsEtaPhi, ""}; AxisSpec axisPhi{350, 0, 7, "#Phi"}; - AxisSpec axisMultMix{configBkg.cfgMultBins, "Multiplicity"}; + AxisSpec axisMultMix{configBkg.cfgMultPercentileBins, "Multiplicity Percentile"}; AxisSpec axisVtxMix{configBkg.cfgVtxBins, "Vertex Z (cm)"}; AxisSpec idxMCAxis = {26, -0.5f, 25.5f, "Index"}; if (cFilladditionalQAeventPlots) { // event histograms if (doprocessData) { + histos.add("QAevent/hEvents", "INEL>0 Events", HistType::kTH1F, {{2, 0.5f, 2.5f}}); histos.add("QAevent/hPairsCounterSameE", "total valid no. of pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); histos.add("QAevent/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0, 1000.0}}); } - // Test on Mixed event + // Gen on Mixed event if (doprocessME) { // Histograms for Mixed Event Pool characteristics @@ -287,6 +289,9 @@ struct Lambda1520analysisinpp { histos.add("QAevent/hMultiplicityPercentMixedE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); histos.add("QAevent/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); } + if (doprocessMCRec) { + histos.add("QAevent/hEventsMC", "INEL>0 Events MC", HistType::kTH1F, {{2, 0.5f, 2.5f}}); + } } if (doprocessData) { @@ -395,7 +400,8 @@ struct Lambda1520analysisinpp { // MC QA histos.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {axisMult, idxMCAxis}); - if (doprocessMCTrue) { + if (doprocessMCGen) { + histos.add("QA/Gen", "Gen histogram", kTH1D, {{10, 0, 10, "index"}}); histos.add("QA/MC/h2GenEtaPt_beforeanycut", " #eta-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); histos.add("QA/MC/h2GenPhiRapidity_beforeanycut", " #phi-y distribution of Generated #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); histos.add("QA/MC/h2GenEtaPt_afterEtaRapCut", " #eta-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); @@ -406,7 +412,7 @@ struct Lambda1520analysisinpp { histos.add("Result/MC/Genlambda1520pt", "pT distribution of True MC #Lambda(1520)0", kTH3F, {axisMClabel, axisPt, axisMult}); histos.add("Result/MC/Genantilambda1520pt", "pT distribution of True MC Anti-#Lambda(1520)0", kTH3F, {axisMClabel, axisPt, axisMult}); } - if (doprocessMC) { + if (doprocessMCRec) { histos.add("QA/MC/h2RecoEtaPt_after", " #eta-#it{p}_{T} distribution of Reconstructed #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPt}); histos.add("QA/MC/h2RecoPhiRapidity_after", " #phi-y distribution of Reconstructed #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); @@ -453,26 +459,6 @@ struct Lambda1520analysisinpp { return returnValue; } - auto static constexpr TripleCharge = 3.0f; - - // Check if the collision is INEL>0 - template - bool isTrueINEL0(MCColl const& /*mccoll*/, MCPart const& mcparts) - { - for (auto const& mcparticle : mcparts) { - if (!mcparticle.isPhysicalPrimary()) - continue; - auto p = pdg->GetParticle(mcparticle.pdgCode()); - if (p != nullptr) { - if (std::abs(p->Charge()) >= TripleCharge) { // check if the particle is charged - if (std::abs(mcparticle.eta()) < 1.0f) - return true; - } - } - } - return false; - } - template bool trackCut(const TrackType track) { @@ -1039,6 +1025,17 @@ struct Lambda1520analysisinpp { if (!colCuts.isSelected(collision)) // Default event selection return; + if (cFilladditionalQAeventPlots) { + histos.fill(HIST("QAevent/hEvents"), 1); + } + + if (!collision.isInelGt0()) // <-- + return; + + if (cFilladditionalQAeventPlots) { + histos.fill(HIST("QAevent/hEvents"), 2); + } + colCuts.fillQA(collision); fillHistograms(collision, tracks, tracks); @@ -1050,32 +1047,51 @@ struct Lambda1520analysisinpp { if (!colCuts.isSelected(collision, false)) // Default event selection return; + if (!collision.isInelGt0()) // <-- + return; + fillHistograms(collision, tracks, tracks); } PROCESS_SWITCH(Lambda1520analysisinpp, processRotational, "Process Rotational Background", false); - void processMC(MCEventCandidates::iterator const& collision, - aod::McCollisions const&, - MCTrackCandidates const& tracks, aod::McParticles const&) + void processMCRec(MCEventCandidates::iterator const& collision, + aod::McCollisions const&, + MCTrackCandidates const& tracks, aod::McParticles const&) { - colCuts.fillQA(collision); + if (!colCuts.isSelected(collision)) + return; + + if (cFilladditionalQAeventPlots) { + histos.fill(HIST("QAevent/hEventsMC"), 1); + } - if (std::abs(collision.posZ()) > cZvertCutMC) // Z-vertex cut + if (!collision.isInelGt0()) // <-- return; + if (cFilladditionalQAeventPlots) { + histos.fill(HIST("QAevent/hEventsMC"), 2); + } + + colCuts.fillQA(collision); + fillHistograms(collision, tracks, tracks); } - PROCESS_SWITCH(Lambda1520analysisinpp, processMC, "Process Event for MC Light without partition", false); + PROCESS_SWITCH(Lambda1520analysisinpp, processMCRec, "Process Event for MC Rec without partition", false); Partition selectedMCParticles = (nabs(aod::mcparticle::pdgCode) == static_cast(Pdg::kLambda1520_Py)); // Lambda(1520) - void processMCTrue(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) + void processMCGen(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) { - bool isInAfterAllCuts = colCuts.isSelected(collision); + bool isInAfterAllCuts = colCuts.isSelected(collision, false); bool inVtx10 = (std::abs(collision.mcCollision().posZ()) > configEvents.cfgEvtZvtx) ? false : true; bool isTriggerTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); bool isSel8 = collision.sel8(); - bool isTrueINELgt0 = isTrueINEL0(collision, mcParticles); + + auto mcPartsAll = mcParticles.sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + + bool isTrueINELgt0 = pwglf::isINELgt0mc(mcPartsAll, pdg); + // bool isTrueINELgt0 = collision.isInelGt0(); + auto centrality = centEst(collision); auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); @@ -1123,21 +1139,23 @@ struct Lambda1520analysisinpp { histos.fill(HIST("QA/MC/h2GenEtaPt_afterEtaRapCut"), part.eta(), part.pt()); histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterEtaRapCut"), part.phi(), part.y()); - // without any event selection - if (part.pdgCode() > 0) + histos.fill(HIST("QA/Gen"), 1); + if (part.pdgCode() > 0) // without any event selection histos.fill(HIST("Result/MC/Genlambda1520pt"), 0, part.pt(), centrality); else histos.fill(HIST("Result/MC/Genantilambda1520pt"), 0, part.pt(), centrality); - if (inVtx10) // INEL10 + if (inVtx10) // vtx10 { + histos.fill(HIST("QA/Gen"), 2); if (part.pdgCode() > 0) histos.fill(HIST("Result/MC/Genlambda1520pt"), 1, part.pt(), centrality); else histos.fill(HIST("Result/MC/Genantilambda1520pt"), 1, part.pt(), centrality); } - if (inVtx10 && isSel8) // INEL>10, vtx10 + if (inVtx10 && isSel8) // vtx10, sel8 { + histos.fill(HIST("QA/Gen"), 3); if (part.pdgCode() > 0) histos.fill(HIST("Result/MC/Genlambda1520pt"), 2, part.pt(), centrality); else @@ -1145,18 +1163,36 @@ struct Lambda1520analysisinpp { } if (inVtx10 && isTriggerTVX) // vtx10, TriggerTVX { + histos.fill(HIST("QA/Gen"), 4); if (part.pdgCode() > 0) histos.fill(HIST("Result/MC/Genlambda1520pt"), 3, part.pt(), centrality); else histos.fill(HIST("Result/MC/Genantilambda1520pt"), 3, part.pt(), centrality); } - if (isInAfterAllCuts) // after all event selection + if (inVtx10 && isTrueINELgt0) // vtx10, INEL>0 { + histos.fill(HIST("QA/Gen"), 5); if (part.pdgCode() > 0) histos.fill(HIST("Result/MC/Genlambda1520pt"), 4, part.pt(), centrality); else histos.fill(HIST("Result/MC/Genantilambda1520pt"), 4, part.pt(), centrality); } + if (isInAfterAllCuts) // after all event selection + { + histos.fill(HIST("QA/Gen"), 6); + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 5, part.pt(), centrality); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 5, part.pt(), centrality); + } + if (isInAfterAllCuts && isTrueINELgt0) // after all event selection && INEL>0 + { + histos.fill(HIST("QA/Gen"), 7); + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 6, part.pt(), centrality); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 6, part.pt(), centrality); + } } // QA for Trigger efficiency @@ -1198,7 +1234,7 @@ struct Lambda1520analysisinpp { if (isInAfterAllCuts && isTrueINELgt0 && inVtx10) histos.fill(HIST("Event/hMCEventIndices"), centrality, AllCutsINELg010); } - PROCESS_SWITCH(Lambda1520analysisinpp, processMCTrue, "Process Event for MC only", false); + PROCESS_SWITCH(Lambda1520analysisinpp, processMCGen, "Process Event for MC only", false); // Processing Event Mixing using BinningTypeVtxZT0M = ColumnBinningPolicy; @@ -1208,7 +1244,7 @@ struct Lambda1520analysisinpp { { auto tracksTuple = std::make_tuple(tracks); - BinningTypeVtxZT0M colBinning{{configBkg.cfgVtxBins, configBkg.cfgMultBins}, true}; + BinningTypeVtxZT0M colBinning{{configBkg.cfgVtxBins, configBkg.cfgMultPercentileBins}, true}; SameKindPair pairs{colBinning, configBkg.nEvtMixing, -1, collision, tracksTuple, &cache}; // -1 is the number of the bin to skip for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { @@ -1218,6 +1254,18 @@ struct Lambda1520analysisinpp { // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.index(), t2.index(), collision1.index(), collision2.index()); // } + if (!colCuts.isSelected(collision1, false)) // Default event selection + continue; + + if (!colCuts.isSelected(collision2, false)) // Default event selection + continue; + + if (!collision1.isInelGt0()) // <-- + continue; + + if (!collision2.isInelGt0()) // <-- + continue; + if (cFilladditionalQAeventPlots) { // Fill histograms for the characteristics of the *mixed* events (collision1 and collision2) // This will show the distribution of events that are actually being mixed. diff --git a/PWGLF/Tasks/Resonances/phiOO.cxx b/PWGLF/Tasks/Resonances/phi1020analysis.cxx similarity index 94% rename from PWGLF/Tasks/Resonances/phiOO.cxx rename to PWGLF/Tasks/Resonances/phi1020analysis.cxx index 9c7e6005264..c56a71e68c4 100644 --- a/PWGLF/Tasks/Resonances/phiOO.cxx +++ b/PWGLF/Tasks/Resonances/phi1020analysis.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file phiInJets.cxx +/// \file phi1020analysis.cxx /// \brief Reconstruction of Phi yield through track-track Minv correlations for resonance OO analysis /// /// @@ -61,7 +61,7 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -struct phiOO { +struct phi1020analysis { SliceCache cache; Preslice perCollision = aod::track::collisionId; @@ -77,6 +77,7 @@ struct phiOO { Configurable cfg_Event_Pileup{"cfg_Event_Pileup", true, "Pileup border cut"}; Configurable cfg_Event_OccupancyCut{"cfg_Event_OccupancyCut", true, "Occupancy border cut"}; Configurable cfg_Event_MaxOccupancy{"cfg_Event_MaxOccupancy", 1, "Max TPC Occupancy"}; + Configurable centEstimator{"centEstimator", 0, "Select centrality estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C"}; // Track configurables Configurable cfg_Track_Sel{"cfg_Track_Sel", "globalTracks", "set track selections"}; @@ -136,10 +137,10 @@ struct phiOO { // Event QA if (cfg_Event_CutQA) { histos.add("hPosZ_BC", "PosZ_BC", kTH1F, {{240, -12.0, 12.0}}); - histos.add("hcentFT0C_BC", "centFT0C_BC", kTH1F, {{110, 0.0, 110.0}}); + histos.add("hcentFT0_BC", "centFT0_BC", kTH1F, {{110, 0.0, 110.0}}); histos.add("hOccupancy_BC", "Occupancy_BC", kTH1F, {{100, 0.0, 20000}}); // - histos.add("hcentFT0C_AC", "centFT0C_AC", kTH1F, {{110, 0.0, 110.0}}); + histos.add("hcentFT0_AC", "centFT0_AC", kTH1F, {{110, 0.0, 110.0}}); histos.add("hPosZ_AC", "PosZ_AC", kTH1F, {{240, -12.0, 12.0}}); histos.add("hOccupancy_AC", "Occupancy_AC", kTH1F, {{100, 0.0, 20000}}); } @@ -198,7 +199,7 @@ struct phiOO { Filter collisionFilter = nabs(aod::collision::posZ) <= cfg_Event_VtxCut; Filter collisionFilter_MC = nabs(aod::mccollision::posZ) <= cfg_Event_VtxCut; - Filter centralityFilter = nabs(aod::cent::centFT0C) <= cfg_Event_CentralityMax; + // Filter centralityFilter = nabs(aod::cent::centFT0C) <= cfg_Event_CentralityMax; Filter acceptanceFilter = (nabs(aod::track::eta) < cfg_Track_MaxEta && nabs(aod::track::pt) >= cfg_Track_MinPt); using EventCandidates = soa::Filtered>; using EventCandidates_True = soa::Filtered; @@ -208,7 +209,7 @@ struct phiOO { using TrackCandidates_MC = soa::Filtered>; - using BinningTypeVtxCent = ColumnBinningPolicy; + using BinningTypeVtxCent = ColumnBinningPolicy; Partition PosKaon_MC = (aod::track::signed1Pt > static_cast(0)) && @@ -224,6 +225,29 @@ struct phiOO { (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); double massKa = o2::constants::physics::MassKPlus; + + // Centralicity estimator selection + template + float centEst(Coll collisions) + { + float returnValue = -999.0f; + switch (centEstimator) { + case 0: + returnValue = collisions.centFT0M(); + break; + case 1: + returnValue = collisions.centFT0A(); + break; + case 2: + returnValue = collisions.centFT0C(); + break; + default: + returnValue = collisions.centFT0M(); + break; + } + return returnValue; + } + //***********************************// // First, we declare some helper functions template @@ -234,10 +258,10 @@ struct phiOO { if constexpr (requires { obj.posZ(); }) { if (!pass) { histos.fill(HIST("hPosZ_BC"), obj.posZ()); - histos.fill(HIST("hcentFT0C_BC"), obj.centFT0C()); + histos.fill(HIST("hcentFT0_BC"), centEst(obj)); } else { histos.fill(HIST("hPosZ_AC"), obj.posZ()); - histos.fill(HIST("hcentFT0C_AC"), obj.centFT0C()); + histos.fill(HIST("hcentFT0_AC"), centEst(obj)); } } } @@ -300,7 +324,7 @@ struct phiOO { return {false, 4}; if (cfg_Event_Pileup && (!event.selection_bit(aod::evsel::kNoSameBunchPileup) || !event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) return {false, 5}; - if (cfg_Event_Centrality && (event.centFT0C() > cfg_Event_CentralityMax)) + if (cfg_Event_Centrality && (centEst(event) > cfg_Event_CentralityMax)) return {false, 6}; if (cfg_Event_OccupancyCut && (event.trackOccupancyInTimeRange() > cfg_Event_MaxOccupancy)) return {false, 7}; @@ -375,7 +399,7 @@ struct phiOO { tofPIDPassed = true; } if (!candidate.hasTOF()) { - std::cout << candidate.tofNSigmaKa() << std::endl; + // std::cout << candidate.tofNSigmaKa() << std::endl; } } if (tpcPIDPassed && tofPIDPassed) { @@ -392,7 +416,7 @@ struct phiOO { { auto slicedtracks1 = PosKaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto slicedtracks2 = NegKaon->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - auto centrality = collision1.centFT0C(); + auto centrality = centEst(collision1); for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(slicedtracks1, slicedtracks2))) { auto [Minv, PhiPt] = minvReconstruction(track1, track2, QA); if (Minv < 0) @@ -419,7 +443,7 @@ struct phiOO { { auto slicedtracks1 = PosKaon_MC->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto slicedtracks2 = NegKaon_MC->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - auto centrality = collision1.centFT0C(); + auto centrality = centEst(collision1); for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(slicedtracks1, slicedtracks2))) { auto [Minv, PhiPt] = minvReconstruction(track1, track2, QA); if (Minv < 0) @@ -526,7 +550,7 @@ struct phiOO { } // end of process - PROCESS_SWITCH(phiOO, processSameEvent, "Process Same events", true); + PROCESS_SWITCH(phi1020analysis, processSameEvent, "Process Same events", true); //***************// // DATA (MIX) @@ -553,7 +577,7 @@ struct phiOO { TrackSlicing(collision1, tracks1, collision2, tracks2, false, true); } // mixing } // end of process - PROCESS_SWITCH(phiOO, processMixedEvent, "Process Mixed events", false); + PROCESS_SWITCH(phi1020analysis, processMixedEvent, "Process Mixed events", false); //***************// // RECONSTRUCTED MC @@ -576,7 +600,7 @@ struct phiOO { TrackSlicing_MC(collision, tracks, collision, tracks, true, false); } // end of process - PROCESS_SWITCH(phiOO, processSameEvent_MC, "Process Same events (MC)", true); + PROCESS_SWITCH(phi1020analysis, processSameEvent_MC, "Process Same events (MC)", true); //***************// // RECONSTRUCTED MC (MIX) @@ -602,7 +626,7 @@ struct phiOO { TrackSlicing_MC(collision1, tracks1, collision2, tracks2, false, true); } // mixing } // end of process - PROCESS_SWITCH(phiOO, processMixedEvent_MC, "Process Mixed events (MC)", false); + PROCESS_SWITCH(phi1020analysis, processMixedEvent_MC, "Process Mixed events (MC)", false); //***************// // GENERATED MC @@ -629,7 +653,7 @@ struct phiOO { double centrality = -1; for (auto& recocoll : recocolls) { // poorly reconstructed - centrality = recocoll.centFT0C(); + centrality = centEst(recocoll); auto [goodEv, code] = eventSelection(recocoll, false); histos.fill(HIST("hnEvents_MC_True"), code); if (!goodEv) @@ -665,11 +689,11 @@ struct phiOO { } // loop over particles } // end of process - PROCESS_SWITCH(phiOO, processParticles, "Process Particles", false); + PROCESS_SWITCH(phi1020analysis, processParticles, "Process Particles", false); }; // end of main struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; }; diff --git a/PWGLF/Tasks/Resonances/phipbpb.cxx b/PWGLF/Tasks/Resonances/phipbpb.cxx index 2468059b1de..87d75fc8a2a 100644 --- a/PWGLF/Tasks/Resonances/phipbpb.cxx +++ b/PWGLF/Tasks/Resonances/phipbpb.cxx @@ -93,7 +93,7 @@ struct phipbpb { Configurable fillSA{"fillSA", false, "fill spin alignment"}; // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentrality{"cfgCutCentrality", 100.0f, "Accepted maximum Centrality"}; Configurable cfgCutOccupancy{"cfgCutOccupancy", 3000, "Occupancy cut"}; // track Configurable cqvas{"cqvas", false, "change q vectors after shift correction"}; @@ -198,6 +198,9 @@ struct phipbpb { AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; AxisSpec occupancyAxis = {occupancyBinning, "Occupancy"}; AxisSpec spAxis = {spNbins, lbinsp, hbinsp, "Sp"}; + histos.add("hImpactParameterVsEvrStatusGen", "hImpactParameterVsEvrStatusGen", HistType::kTH2F, {{200, 0.0, 20.0}, {5, 0.0, 5.0}}, true); + histos.add("hImpactParameterVsEvrStatusRec", "hImpactParameterVsEvrStatusRec", HistType::kTH3F, {{200, 0.0, 20.0}, {100, 0.0, 100.0}, {10, 0.0, 10.0}}, true); + histos.add("hINumRecCollisionVsEvrStatusRec", "hINumRecCollisionVsEvrStatusRec", HistType::kTH3F, {{21, -0.5, 20.5}, {100, 0.0, 100.0}, {10, 0.0, 10.0}}, true); if (fillv1) { histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); @@ -792,7 +795,7 @@ struct phipbpb { Npostrack = Npostrack + 1; } } - PROCESS_SWITCH(phipbpb, processSameEvent, "Process Same event", true); + PROCESS_SWITCH(phipbpb, processSameEvent, "Process Same event", false); void processSameEventv1(EventCandidatesv1::iterator const& collision, TrackCandidates const& /*tracks, aod::BCs const&*/, aod::BCsWithTimestamps const&) { @@ -1045,7 +1048,7 @@ struct phipbpb { } } } - PROCESS_SWITCH(phipbpb, processMEAcc, "Process ME Acceptance", true); + PROCESS_SWITCH(phipbpb, processMEAcc, "Process ME Acceptance", false); void processMEAccv1(EventCandidatesv1 const& collisions, TrackCandidates const& tracks) { @@ -1303,7 +1306,7 @@ struct phipbpb { } } } - PROCESS_SWITCH(phipbpb, processMixedEventOpti, "Process Mixed event new", true); + PROCESS_SWITCH(phipbpb, processMixedEventOpti, "Process Mixed event new", false); void processMixedEventOptiv1(EventCandidatesv1 const& collisions, TrackCandidates const& tracks) { @@ -1877,6 +1880,47 @@ struct phipbpb { } // process MC PROCESS_SWITCH(phipbpb, processMCPhiWeight, "Process MC Phi Weight", false); + + using McCollisionMults = soa::Join; + using EventCandidatesMC = soa::Join; + void processEvtLossMC(McCollisionMults::iterator const& mcCollision, const soa::SmallGroups& recCollisions) + { + auto impactPar = mcCollision.impactParameter(); + histos.fill(HIST("hImpactParameterVsEvrStatusGen"), impactPar, 0.5); + if (mcCollision.isInelGt0()) { + histos.fill(HIST("hImpactParameterVsEvrStatusGen"), impactPar, 1.5); + } + auto numberRecCollision = recCollisions.size(); + for (const auto& RecCollision : recCollisions) { + auto isTVX = RecCollision.selection_bit(o2::aod::evsel::kIsTriggerTVX); + auto vz = TMath::Abs(RecCollision.posZ()); + auto issel8 = RecCollision.sel8(); + auto isITSGoodLayer = RecCollision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); + auto isGoodVtxzFT0vsPV = RecCollision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); + auto isSameBunchPileup = RecCollision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + auto centrality = RecCollision.centFT0C(); + histos.fill(HIST("hImpactParameterVsEvrStatusRec"), impactPar, centrality, 0.5); + histos.fill(HIST("hINumRecCollisionVsEvrStatusRec"), numberRecCollision, centrality, 0.5); + if (isTVX) { + histos.fill(HIST("hImpactParameterVsEvrStatusRec"), impactPar, centrality, 1.5); + histos.fill(HIST("hINumRecCollisionVsEvrStatusRec"), numberRecCollision, centrality, 1.5); + } + if (isTVX && vz < 7) { + histos.fill(HIST("hImpactParameterVsEvrStatusRec"), impactPar, centrality, 2.5); + histos.fill(HIST("hINumRecCollisionVsEvrStatusRec"), numberRecCollision, centrality, 2.5); + } + if (isTVX && vz < 7 && issel8) { + histos.fill(HIST("hImpactParameterVsEvrStatusRec"), impactPar, centrality, 3.5); + histos.fill(HIST("hINumRecCollisionVsEvrStatusRec"), numberRecCollision, centrality, 3.5); + } + if (isTVX && vz < 7 && issel8 && isITSGoodLayer && isGoodVtxzFT0vsPV && isSameBunchPileup) { + histos.fill(HIST("hImpactParameterVsEvrStatusRec"), impactPar, centrality, 4.5); + histos.fill(HIST("hINumRecCollisionVsEvrStatusRec"), numberRecCollision, centrality, 4.5); + } + } + //} + } + PROCESS_SWITCH(phipbpb, processEvtLossMC, "Process to calculate Event Loss", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/rho770analysis.cxx b/PWGLF/Tasks/Resonances/rho770analysis.cxx index b1d954f0117..6715835c8ea 100644 --- a/PWGLF/Tasks/Resonances/rho770analysis.cxx +++ b/PWGLF/Tasks/Resonances/rho770analysis.cxx @@ -12,7 +12,7 @@ /// \file rho770analysis.cxx /// \brief rho(770)0 analysis in pp 13 & 13.6 TeV /// \author Hyunji Lim (hyunji.lim@cern.ch) -/// \since 08/02/2026 +/// \since 05/03/2026 #include "PWGLF/DataModel/LFResonanceTables.h" #include "PWGLF/DataModel/mcCentrality.h" @@ -64,9 +64,9 @@ struct rho770analysis { // DCA cuts Configurable cDCAxyToPVAsPt{"cDCAxyToPVAsPt", true, "DCAxy to PV selection as pt"}; - Configurable cDCAzToPVAsPt{"cDCAzToPVAsPt", false, "DCAz to PV selection as pt"}; - Configurable cfgMaxDCAxyToPVcut{"cfgMaxDCAxyToPVcut", 0.15, "Maximum transverse DCA"}; - Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 2.0, "Maximum longitudinal DCA"}; + Configurable cDCAzToPVAsPt{"cDCAzToPVAsPt", true, "DCAz to PV selection as pt"}; + Configurable cfgMaxDCAxyToPVcut{"cfgMaxDCAxyToPVcut", 0.10, "Maximum transverse DCA"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 0.10, "Maximum longitudinal DCA"}; Configurable cDCAxytoPVByPtPiFirstP0{"cDCAxytoPVByPtPiFirstP0", 0.0105, "Coeff. Track DCAxy cut to PV by pt for Pion First (p0)"}; Configurable cDCAxyToPVByPtPiFirstExp{"cDCAxyToPVByPtPiFirstExp", 0.035, "Coeff. Track DCAxy cut to PV by pt for Pion First (exp)"}; Configurable cDCAztoPVByPtPiFirstP0{"cDCAztoPVByPtPiFirstP0", 0.0105, "Coeff. Track DCAz cut to PV by pt for Pion First (p0)"}; @@ -88,7 +88,7 @@ struct rho770analysis { Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; Configurable cfgTPCcluster{"cfgTPCcluster", 1, "Number of TPC cluster"}; - Configurable cfgTPCRows{"cfgTPCRows", 80, "Minimum Number of TPC Crossed Rows "}; + Configurable cfgTPCRows{"cfgTPCRows", 70, "Minimum Number of TPC Crossed Rows "}; // PID Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF @@ -102,7 +102,7 @@ struct rho770analysis { ConfigurableAxis massK0sAxis{"massK0sAxis", {200, 0.46, 0.54}, "K0s Invariant mass axis"}; ConfigurableAxis massKstarAxis{"massKstarAxis", {200, 0.6, 1.3}, "Kstar Invariant mass axis"}; ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 10.0, 13.0, 20.0}, "Transverse momentum Binning"}; - ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 95.0, 100.0, 105.0, 110.0}, "Centrality Binning"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 85.0, 90.0, 95.0, 100.0, 105.0}, "Centrality Binning"}; void init(o2::framework::InitContext&) { @@ -197,7 +197,7 @@ struct rho770analysis { const auto mode = static_cast(selectTypeInt.value); if (mode == TrackPIDMode::TPCOrTOF) { // TPC or TOF - if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaPi()) >= cMaxTOFnSigmaPion) + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion && std::fabs(track.tofNSigmaPi()) >= cMaxTOFnSigmaPion) return false; } if (mode == TrackPIDMode::OnlyTPC) { // only TPC @@ -226,7 +226,7 @@ struct rho770analysis { const auto mode = static_cast(selectTypeInt.value); if (mode == TrackPIDMode::TPCOrTOF) { - if (std::fabs(track.tpcNSigmaKa()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaKa()) >= cMaxTOFnSigmaPion) + if (std::fabs(track.tpcNSigmaKa()) >= cMaxTPCnSigmaPion && std::fabs(track.tofNSigmaKa()) >= cMaxTOFnSigmaPion) return false; } if (mode == TrackPIDMode::OnlyTPC) { @@ -410,6 +410,8 @@ struct rho770analysis { for (const auto& part : resoParents) { // loop over all pre-filtered MC particles if (std::abs(part.pdgCode()) != kRho770_0) continue; + if (!part.isPhysicalPrimary()) + continue; if (!part.producedByGenerator()) continue; if (part.y() < cfgMinRap || part.y() > cfgMaxRap) diff --git a/PWGLF/Tasks/Resonances/xi1820Analysis.cxx b/PWGLF/Tasks/Resonances/xi1820Analysis.cxx index 997c68a5015..1528ac712b5 100644 --- a/PWGLF/Tasks/Resonances/xi1820Analysis.cxx +++ b/PWGLF/Tasks/Resonances/xi1820Analysis.cxx @@ -11,7 +11,8 @@ /// \file xi1820Analysis.cxx /// \brief Invariant Mass Reconstruction of Xi(1820) Resonance -/// \author Bong-Hwi Lim +/// +/// \author Bong-Hwi Lim , Minjae Kim #include "PWGLF/DataModel/LFResonanceTables.h" @@ -40,11 +41,12 @@ struct Xi1820Analysis { Preslice perResoCollisionTrack = aod::resodaughter::resoCollisionId; Preslice perResoCollisionMicroTrack = aod::resodaughter::resoCollisionId; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + using ResoMCCols = soa::Join; // Constants static constexpr float kSmallMomentumDenominator = 1e-10f; // Small value to avoid division by zero - static constexpr float kMaxDcaToPv = 1.0f; // Maximum DCA to primary vertex - static constexpr int kPdgXi1820 = 123314; // o2-linter: disable=pdg/explicit-code (Xi(1820) PDG code not available in PDG_t or o2::constants::physics::Pdg) + static constexpr int kPdgChagedXi1820 = 123314; // o2-linter: disable=pdg/explicit-code (Xi(1820) PDG code not available in PDG_t or o2::constants::physics::Pdg) + static constexpr int kPdgXi1820Zero = 123324; // o2-linter: disable=pdg/explicit-code (Xi(1820) PDG code not available in PDG_t or o2::constants::physics::Pdg) static constexpr int kExpectedDaughters = 2; // Expected number of daughters for two-body decay // Axes @@ -52,7 +54,7 @@ struct Xi1820Analysis { ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0}, "pT (QA)"}; ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Centrality"}; - // Invariant mass range for Xi(1820) → Λ + K + // Invariant mass range for Xi(1820) to Λ + K Configurable cInvMassStart{"cInvMassStart", 1.6, "Invariant mass start (GeV/c^2)"}; Configurable cInvMassEnd{"cInvMassEnd", 2.2, "Invariant mass end (GeV/c^2)"}; Configurable cInvMassBins{"cInvMassBins", 600, "Invariant mass bins"}; @@ -72,48 +74,64 @@ struct Xi1820Analysis { Configurable cKaonITSNClusMin{"cKaonITSNClusMin", 2, "Minimum ITS clusters for kaon"}; // Kaon PID selections - Configurable cKaonTPCNSigmaMax{"cKaonTPCNSigmaMax", 3.0, "Maximum TPC NSigma for kaon (if not using pT-dependent)"}; - Configurable cKaonTOFNSigmaMax{"cKaonTOFNSigmaMax", 3.0, "Maximum TOF NSigma for kaon (if not using pT-dependent)"}; + Configurable cKaonTPCNSigmaMax{"cKaonTPCNSigmaMax", 3.5, "Maximum TPC NSigma for kaon (if not using pT-dependent)"}; + Configurable cKaonTOFNSigmaMax{"cKaonTOFNSigmaMax", 999., "Maximum TOF NSigma for kaon (if not using pT-dependent)"}; Configurable cKaonUsePtDepPID{"cKaonUsePtDepPID", false, "Use pT-dependent PID cuts"}; Configurable> cKaonPIDPtBins{"cKaonPIDPtBins", {0.0f, 0.5f, 0.8f, 2.0f, 999.0f}, "pT bin edges for PID cuts (N+1 values for N bins)"}; Configurable> cKaonTPCNSigmaCuts{"cKaonTPCNSigmaCuts", {3.0f, 3.0f, 2.0f, 2.0f}, "TPC NSigma cuts per pT bin (N values)"}; Configurable> cKaonTOFNSigmaCuts{"cKaonTOFNSigmaCuts", {3.0f, 3.0f, 3.0f, 3.0f}, "TOF NSigma cuts per pT bin (N values)"}; - Configurable> cKaonTOFRequired{"cKaonTOFRequired", {0, 0, 1, 1}, "Require TOF per pT bin (N values, 0=false, 1=true)"}; + Configurable> cKaonTOFRequired{"cKaonTOFRequired", {0, 0, 0, 0}, "Require TOF per pT bin (N values, 0=false, 1=true)"}; // V0 (Lambda) selections Configurable cV0MinCosPA{"cV0MinCosPA", 0.995, "V0 minimum pointing angle cosine"}; - Configurable cV0MaxDaughDCA{"cV0MaxDaughDCA", 1.0, "V0 daughter DCA Maximum"}; - Configurable cV0MassWindow{"cV0MassWindow", 0.005, "Mass window for Lambda selection"}; + Configurable cV0MaxDaughDCA{"cV0MaxDaughDCA", 0.5, "V0 daughter DCA Maximum"}; + Configurable cV0MassWindow{"cV0MassWindow", 0.01, "Mass window for Lambda selection (GeV/c^2)"}; Configurable cMaxV0Etacut{"cMaxV0Etacut", 0.8, "V0 maximum eta cut"}; Configurable cV0RadiusMin{"cV0RadiusMin", 0.5, "V0 decay radius min"}; Configurable cV0RadiusMax{"cV0RadiusMax", 200.0, "V0 decay radius max"}; Configurable cV0DauPosDCAtoPVMin{"cV0DauPosDCAtoPVMin", 0.05, "V0 positive daughter DCA to PV min"}; Configurable cV0DauNegDCAtoPVMin{"cV0DauNegDCAtoPVMin", 0.05, "V0 negative daughter DCA to PV min"}; Configurable cV0ProperLifetimeMax{"cV0ProperLifetimeMax", 30.0, "Lambda proper lifetime max (cm/c)"}; + Configurable cV0sCrossMassRejection{"cV0sCrossMassRejection", true, "Enable K0s mass rejection for Lambda"}; + Configurable cV0sCrossMassRejectionWindow{"cV0sCrossMassRejectionWindow", 0.005, "K0s mass rejection window for Lambda (GeV/c^2)"}; // K0s selections - Configurable cK0sMinCosPA{"cK0sMinCosPA", 0.97, "K0s minimum pointing angle cosine"}; - Configurable cK0sMaxDaughDCA{"cK0sMaxDaughDCA", 1.0, "K0s daughter DCA Maximum"}; - Configurable cK0sMassWindow{"cK0sMassWindow", 0.0043, "Mass window for K0s selection"}; + Configurable cK0sMinCosPA{"cK0sMinCosPA", 0.98, "K0s minimum pointing angle cosine"}; + Configurable cK0sMaxDaughDCA{"cK0sMaxDaughDCA", 0.5, "K0s daughter DCA Maximum"}; + Configurable cK0sMassWindow{"cK0sMassWindow", 0.025, "Mass window for K0s selection (GeV/c^2)"}; Configurable cK0sProperLifetimeMax{"cK0sProperLifetimeMax", 20.0, "K0s proper lifetime max (cm/c)"}; Configurable cK0sArmenterosQtMin{"cK0sArmenterosQtMin", 0.0, "K0s Armenteros qt min"}; - Configurable cK0sArmenterosAlphaMax{"cK0sArmenterosAlphaMax", 0.8, "K0s Armenteros alpha max"}; - Configurable cK0sDauPosDCAtoPVMin{"cK0sDauPosDCAtoPVMin", 0.1, "K0s positive daughter DCA to PV min"}; - Configurable cK0sDauNegDCAtoPVMin{"cK0sDauNegDCAtoPVMin", 0.1, "K0s negative daughter DCA to PV min"}; + Configurable cK0sArmenterosAlphaCoeff{"cK0sArmenterosAlphaCoeff", 0.2, "K0s Armenteros alpha max"}; + Configurable cK0sDauPosDCAtoPVMin{"cK0sDauPosDCAtoPVMin", 0.05, "K0s positive daughter DCA to PV min"}; + Configurable cK0sDauNegDCAtoPVMin{"cK0sDauNegDCAtoPVMin", 0.05, "K0s negative daughter DCA to PV min"}; Configurable cK0sRadiusMin{"cK0sRadiusMin", 0.5, "K0s decay radius min"}; - Configurable cK0sRadiusMax{"cK0sRadiusMax", 100.0, "K0s decay radius max"}; + Configurable cK0sRadiusMax{"cK0sRadiusMax", 200.0, "K0s decay radius max"}; Configurable cK0sCrossMassRejection{"cK0sCrossMassRejection", true, "Enable Lambda mass rejection for K0s"}; + Configurable cK0sCrossMassRejectionWindow{"cK0sCrossMassRejectionWindow", 0.01, "Lambda mass rejection window for K0s (GeV/c^2)"}; // Event Mixing Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; ConfigurableAxis cfgVtxBins{"cfgVtxBins", {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 cfgMultBins{"cfgMultBins", {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 - centrality"}; - // Track type selection - Configurable cUseMicroTracks{"cUseMicroTracks", false, "Use ResoMicroTracks instead of ResoTracks"}; + // Additional QA and configurations + struct : ConfigurableGroup { + Configurable cRecoINELgt0{"cRecoINELgt0", false, "Apply Reco INEL>0 event selection"}; + Configurable cConsiderPairOnly{"cConsiderPairOnly", true, "Consider only the pair of tracks for the charged K + Lambda analysis"}; + Configurable cConsiderHasV0s{"cConsiderHasV0s", true, "Consider only the pair of tracks for the K0s + Lambda analysis"}; + Configurable cUseTruthRapidity{"cUseTruthRapidity", false, "Use truth rapidity for MC generated target"}; + + Configurable cUsePtDepDCAForKaons{"cUsePtDepDCAForKaons", true, "Use pT dependent DCA cuts for kaon tracks"}; + Configurable cDCAToPVByPtFirstP0{"cDCAToPVByPtFirstP0", 0.004, "pT dependent DCA cut first parameter (cm)"}; + Configurable cDCAToPVByPtFirstExp{"cDCAToPVByPtFirstExp", 0.013, "pT dependent DCA cut second parameter (exponent)"}; + Configurable cMaxDcaToPVV0{"cMaxDcaToPVV0", 1.0, "Maximum DCA to PV for V0 candidates (cm)"}; + + Configurable cfgRapidityCut{"cfgRapidityCut", 0.5, "Rapidity cut"}; + ConfigurableAxis multNTracksAxis{"multNTracksAxis", {500, 0, 500}, "N_{tracks}"}; + + } additionalConfig; using BinningTypeVertexContributor = ColumnBinningPolicy; - BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; void init(InitContext&) { @@ -123,137 +141,181 @@ struct Xi1820Analysis { AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, "Invariant Mass (GeV/#it{c}^{2})"}; AxisSpec lambdaMassAxis = {200, 1.08, 1.16, "#Lambda mass (GeV/#it{c}^{2})"}; AxisSpec dcaAxis = {200, 0., 2.0, "DCA (cm)"}; - AxisSpec dcaxyAxis = {200, -1.0, 1.0, "DCA_{xy} (cm)"}; - AxisSpec dcazAxis = {200, -2.0, 2.0, "DCA_{z} (cm)"}; + AxisSpec dcaxyAxis = {400, -0.2, 0.2, "DCA_{xy} (cm)"}; + AxisSpec dcazAxis = {400, -0.2, 0.2, "DCA_{z} (cm)"}; AxisSpec cosPAAxis = {1000, 0.95, 1.0, "cos(PA)"}; AxisSpec radiusAxis = {200, 0, 200, "Radius (cm)"}; AxisSpec lifetimeAxis = {200, 0, 50, "Proper lifetime (cm/c)"}; AxisSpec nsigmaAxis = {100, -5.0, 5.0, "N#sigma"}; + AxisSpec armenterosAlphaAxis = {200, -1.0, 1.0, "Armenteros alpha"}; + AxisSpec armenterosQtAxis = {500, 0.0, 0.5, "Armenteros qt (GeV/c)"}; // Event QA histograms histos.add("Event/posZ", "Event vertex Z position", kTH1F, {{200, -20., 20., "V_{z} (cm)"}}); - histos.add("Event/centrality", "Event centrality distribution", kTH1F, {centAxis}); + histos.add("Event/centrality", "Event centrality distribution", kTH1D, {centAxis}); histos.add("Event/posZvsCent", "Vertex Z vs Centrality", kTH2F, {{200, -20., 20., "V_{z} (cm)"}, centAxis}); histos.add("Event/nV0s", "Number of V0s per event", kTH1F, {{200, 0., 200., "N_{V0s}"}}); - histos.add("Event/nKaons", "Number of kaons per event", kTH1F, {{200, 0., 200., "N_{kaons}"}}); - histos.add("Event/nV0sAfterCuts", "Number of V0s per event after cuts", kTH1F, {{100, 0., 100., "N_{V0s}"}}); - histos.add("Event/nKaonsAfterCuts", "Number of kaons per event after cuts", kTH1F, {{100, 0., 100., "N_{kaons}"}}); - - // Lambda QA histograms - histos.add("QAbefore/lambdaMass", "Lambda mass before cuts", kTH1F, {lambdaMassAxis}); - histos.add("QAbefore/lambdaPt", "Lambda pT before cuts", kTH1F, {ptAxisQA}); - histos.add("QAbefore/lambdaEta", "Lambda eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); - histos.add("QAbefore/lambdaCosPA", "Lambda CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); - histos.add("QAbefore/lambdaRadius", "Lambda radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); - histos.add("QAbefore/lambdaDauDCA", "Lambda daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); - histos.add("QAbefore/lambdaProperLifetime", "Lambda proper lifetime before cuts", kTH2F, {ptAxisQA, lifetimeAxis}); - histos.add("QAbefore/lambdaDauPosDCA", "Lambda positive daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); - histos.add("QAbefore/lambdaDauNegDCA", "Lambda negative daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); - - histos.add("QAafter/lambdaMass", "Lambda mass after cuts", kTH1F, {lambdaMassAxis}); - histos.add("QAafter/lambdaPt", "Lambda pT after cuts", kTH1F, {ptAxisQA}); - histos.add("QAafter/lambdaEta", "Lambda eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); - histos.add("QAafter/lambdaCosPA", "Lambda CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); - histos.add("QAafter/lambdaRadius", "Lambda radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); - histos.add("QAafter/lambdaDauDCA", "Lambda daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); - histos.add("QAafter/lambdaProperLifetime", "Lambda proper lifetime after cuts", kTH2F, {ptAxisQA, lifetimeAxis}); - histos.add("QAafter/lambdaDauPosDCA", "Lambda positive daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); - histos.add("QAafter/lambdaDauNegDCA", "Lambda negative daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); - - // Kaon QA histograms - histos.add("QAbefore/kaonPt", "Kaon pT before cuts", kTH1F, {ptAxisQA}); - histos.add("QAbefore/kaonEta", "Kaon eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); - histos.add("QAbefore/kaonDCAxy", "Kaon DCAxy before cuts", kTH2F, {ptAxisQA, dcaxyAxis}); - histos.add("QAbefore/kaonDCAz", "Kaon DCAz before cuts", kTH2F, {ptAxisQA, dcazAxis}); - histos.add("QAbefore/kaonTPCNcls", "Kaon TPC clusters before cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); - histos.add("QAbefore/kaonITSNcls", "Kaon ITS clusters before cuts", kTH1F, {{10, 0, 10, "N_{ITS clusters}"}}); - histos.add("QAbefore/kaonTPCNSigma", "Kaon TPC NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); - histos.add("QAbefore/kaonTOFNSigma", "Kaon TOF NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); - - histos.add("QAafter/kaonPt", "Kaon pT after cuts", kTH1F, {ptAxisQA}); - histos.add("QAafter/kaonEta", "Kaon eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); - histos.add("QAafter/kaonDCAxy", "Kaon DCAxy after cuts", kTH2F, {ptAxisQA, dcaxyAxis}); - histos.add("QAafter/kaonDCAz", "Kaon DCAz after cuts", kTH2F, {ptAxisQA, dcazAxis}); - histos.add("QAafter/kaonTPCNcls", "Kaon TPC clusters after cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); - histos.add("QAafter/kaonITSNcls", "Kaon ITS clusters after cuts", kTH1F, {{10, 0, 10, "N_{ITS clusters}"}}); - histos.add("QAafter/kaonTPCNSigma", "Kaon TPC NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); - histos.add("QAafter/kaonTOFNSigma", "Kaon TOF NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("Event/nKaons", "Number of kaons per event", kTH1F, {{200, 0., 200., "N_{kaon}"}}); + histos.add("Event/nLambdasAfterCuts", "Number of Lambdas per event after cuts", kTH1F, {{100, 0., 100., "N_{Lambda}"}}); + histos.add("Event/nKaonsAfterCuts", "Number of kaons (or K0s) per event after cuts", kTH1F, {{100, 0., 100., "N_{Kaon}"}}); + + if (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMCWithTracks || doprocessK0sLambda || doprocessMCK0sLambda) { + // Lambda QA histograms + histos.add("QAbefore/lambdaMass", "Lambda mass before cuts", kTH1F, {lambdaMassAxis}); + histos.add("QAbefore/lambdaMassAnti", "Anti-Lambda mass before cuts", kTH1F, {lambdaMassAxis}); + histos.add("QAbefore/lambdaPt", "Lambda pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/lambdaEta", "Lambda eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/lambdaCosPA", "Lambda CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAbefore/lambdaRadius", "Lambda radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAbefore/lambdaDauDCA", "Lambda daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/lambdaProperLifetime", "Lambda proper lifetime before cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAbefore/lambdaDauPosDCA", "Lambda positive daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/lambdaDauNegDCA", "Lambda negative daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/lambdaArmenterosPodolanski", "Lambda candidate Armenteros-Podolanski before cuts", kTH3F, {armenterosAlphaAxis, armenterosQtAxis, ptAxisQA}); + + histos.add("QAafter/lambdaMass", "Lambda mass after cuts", kTH1F, {lambdaMassAxis}); + histos.add("QAafter/lambdaMassAnti", "Anti-Lambda mass after cuts", kTH1F, {lambdaMassAxis}); + histos.add("QAafter/lambdaPt", "Lambda pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/lambdaEta", "Lambda eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/lambdaCosPA", "Lambda CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAafter/lambdaRadius", "Lambda radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAafter/lambdaDauDCA", "Lambda daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/lambdaProperLifetime", "Lambda proper lifetime after cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAafter/lambdaDauPosDCA", "Lambda positive daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/lambdaDauNegDCA", "Lambda negative daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/lambdaArmenterosPodolanski", "Lambda candidate Armenteros-Podolanski after cuts", kTH3F, {armenterosAlphaAxis, armenterosQtAxis, ptAxisQA}); + } + + if (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMCWithTracks) { + // Kaon QA histograms + histos.add("QAbefore/kaonPt", "Kaon pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/kaonEta", "Kaon eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/kaonDCAxy", "Kaon DCAxy before cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAbefore/kaonDCAz", "Kaon DCAz before cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAbefore/kaonTPCNcls", "Kaon TPC clusters before cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); + histos.add("QAbefore/kaonITSNcls", "Kaon ITS clusters before cuts", kTH1F, {{10, 0, 10, "N_{ITS clusters}"}}); + histos.add("QAbefore/kaonTPCNSigma", "Kaon TPC NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAbefore/kaonTOFNSigma", "Kaon TOF NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + + histos.add("QAafter/kaonPt", "Kaon pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/kaonEta", "Kaon eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/kaonDCAxy", "Kaon DCAxy after cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAafter/kaonDCAz", "Kaon DCAz after cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAafter/kaonTPCNcls", "Kaon TPC clusters after cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); + histos.add("QAafter/kaonITSNcls", "Kaon ITS clusters after cuts", kTH1F, {{10, 0, 10, "N_{ITS clusters}"}}); + histos.add("QAafter/kaonTPCNSigma", "Kaon TPC NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAafter/kaonTOFNSigma", "Kaon TOF NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + } // Resonance histograms - 4 combinations // K+ Lambda - histos.add("xi1820/kplus_lambda/hInvMassKplusLambda", "Invariant mass of Xi(1820) → K^{+} + #Lambda", kTH1F, {invMassAxis}); - histos.add("xi1820/kplus_lambda/hInvMassKplusLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{+} + #Lambda", kTH1F, {invMassAxis}); - histos.add("xi1820/kplus_lambda/hMassPtCentKplusLambda", "Xi(1820) mass vs pT vs cent (K^{+}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); - histos.add("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{+}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); - - // K+ Anti-Lambda - histos.add("xi1820/kplus_antilambda/hInvMassKplusAntiLambda", "Invariant mass of Xi(1820) → K^{+} + #bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{+} + #bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda", "Xi(1820) mass vs pT vs cent (K^{+}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); - histos.add("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{+}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); - - // K- Lambda - histos.add("xi1820/kminus_lambda/hInvMassKminusLambda", "Invariant mass of Xi(1820) → K^{-} + #Lambda", kTH1F, {invMassAxis}); - histos.add("xi1820/kminus_lambda/hInvMassKminusLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{-} + #Lambda", kTH1F, {invMassAxis}); - histos.add("xi1820/kminus_lambda/hMassPtCentKminusLambda", "Xi(1820) mass vs pT vs cent (K^{-}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); - histos.add("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{-}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); - - // K- Anti-Lambda - histos.add("xi1820/kminus_antilambda/hInvMassKminusAntiLambda", "Invariant mass of Xi(1820) → K^{-} + #bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{-} + #bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda", "Xi(1820) mass vs pT vs cent (K^{-}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); - histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{-}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + if (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMixedEventWithTracks || doprocessMixedEventWithMicroTracks || doprocessMCWithTracks) { + histos.add("xi1820/kplus_lambda/hInvMassKplusLambda", "Invariant mass of K^{+} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_lambda/hInvMassKplusLambda_Mix", "Mixed event Invariant mass of K^{+} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_lambda/hMassPtCentKplusLambda", "K^{+} + #Lambda mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix", "Mixed event K^{+} + #Lambda mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + + // K+ Anti-Lambda + histos.add("xi1820/kplus_antilambda/hInvMassKplusAntiLambda", "Invariant mass of K^{+} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix", "Mixed event Invariant mass of K^{+} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda", "K^{+} + #bar{#Lambda} mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix", "Mixed event K^{+} + #bar{#Lambda} mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + + // K- Lambda + histos.add("xi1820/kminus_lambda/hInvMassKminusLambda", "Invariant mass of K^{-} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_lambda/hInvMassKminusLambda_Mix", "Mixed event Invariant mass of K^{-} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_lambda/hMassPtCentKminusLambda", "K^{-} + #Lambda mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix", "Mixed event K^{-} + #Lambda mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + + // K- Anti-Lambda + histos.add("xi1820/kminus_antilambda/hInvMassKminusAntiLambda", "Invariant mass of K^{-} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix", "Mixed event Invariant mass of K^{-} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda", "K^{-} + #bar{#Lambda} mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix", "Mixed event K^{-} + #bar{#Lambda} mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); + } + + // MC Reco histograms for charged K + Lambda channel + if (doprocessMCWithTracks) { + histos.add("MC/kplus_antilambda/hMCRecoInvMassKplusAntiLambda", "Invariant mass of Xi(1820) to K^{-} + #Lambda (MC Reco)", kTH1F, {invMassAxis}); + histos.add("MC/kplus_antilambda/hMCRecoMassPtCentKplusAntiLambda", "Xi(1820) mass vs pT vs cent (K^{-} + #Lambda) (MC Reco)", kTHnSparseD, {invMassAxis, ptAxis, centAxis, ptAxis}); + + histos.add("MC/kminus_antilambda/hMCRecoInvMassKminusAntiLambda", "Invariant mass of Xi(1820) to K^{+} + #bar{#Lambda} (MC Reco)", kTH1F, {invMassAxis}); + histos.add("MC/kminus_antilambda/hMCRecoMassPtCentKminusAntiLambda", "Xi(1820) mass vs pT vs cent (K^{+} + #bar{#Lambda}) (MC Reco)", kTHnSparseD, {invMassAxis, ptAxis, centAxis, ptAxis}); + } + + // K0s QA histograms + if (doprocessK0sLambda || doprocessMCK0sLambda) { + histos.add("QAbefore/k0sMass", "K0s mass before cuts", kTH1F, {{100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}}); + histos.add("QAbefore/k0sPt", "K0s pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/k0sEta", "K0s eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/k0sCosPA", "K0s CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAbefore/k0sRadius", "K0s radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAbefore/k0sDauDCA", "K0s daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/k0sProperLifetime", "K0s proper lifetime before cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAbefore/k0sArmenterosPodolanski", "K0s candidate Armenteros-Podolanski before cuts", kTH3F, {armenterosAlphaAxis, armenterosQtAxis, ptAxisQA}); + + histos.add("QAafter/k0sMass", "K0s mass after cuts", kTH1F, {{100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}}); + histos.add("QAafter/k0sPt", "K0s pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/k0sEta", "K0s eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/k0sCosPA", "K0s CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAafter/k0sRadius", "K0s radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAafter/k0sDauDCA", "K0s daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/k0sProperLifetime", "K0s proper lifetime after cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAafter/k0sArmenterosPodolanski", "K0s candidate Armenteros-Podolanski after cuts", kTH3F, {armenterosAlphaAxis, armenterosQtAxis, ptAxisQA}); + } // K0s + Lambda - histos.add("xi1820/k0s_lambda/hInvMassK0sLambda", "Invariant mass of Xi(1820) → K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); - histos.add("xi1820/k0s_lambda/hInvMassK0sLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); - histos.add("xi1820/k0s_lambda/hMassPtCentK0sLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); - histos.add("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{0}_{S}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); + if (doprocessK0sLambda || doprocessK0sLambdaMixedEvent || doprocessMCK0sLambda) { + histos.add("xi1820/k0s_lambda/hInvMassK0sLambda", "Invariant mass of Xi(1820) to K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_lambda/hInvMassK0sLambda_Mix", "Mixed event Invariant mass of Xi(1820) to K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_lambda/hMassPtCentK0sLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#Lambda)", kTH3D, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{0}_{S}#Lambda)", kTH3D, {invMassAxis, ptAxis, centAxis}); + + // K0s + Anti-Lambda + histos.add("xi1820/k0s_antilambda/hInvMassK0sAntiLambda", "Invariant mass of Xi(1820) to K^{0}_{S} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix", "Mixed event Invariant mass of Xi(1820) to K^{0}_{S} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3D, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3D, {invMassAxis, ptAxis, centAxis}); + } + + if (doprocessMCK0sLambda) { + histos.add("MC/k0s_lambda/hMCRecoInvMassK0sLambda", "Invariant mass of Xi(1820) to K^{0}_{S} + #Lambda (MC Reco)", kTH1F, {invMassAxis}); + histos.add("MC/k0s_lambda/hMCRecoMassPtCentK0sLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#Lambda) (MC Reco)", kTHnSparseD, {invMassAxis, ptAxis, centAxis, ptAxis}); + + histos.add("MC/k0s_antilambda/hMCRecoInvMassK0sAntiLambda", "Invariant mass of Xi(1820) to K^{0}_{S} + #bar{#Lambda} (MC Reco)", kTH1F, {invMassAxis}); + histos.add("MC/k0s_antilambda/hMCRecoMassPtCentK0sAntiLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda}) (MC Reco)", kTHnSparseD, {invMassAxis, ptAxis, centAxis, ptAxis}); + } - // K0s + Anti-Lambda - histos.add("xi1820/k0s_antilambda/hInvMassK0sAntiLambda", "Invariant mass of Xi(1820) → K^{0}_{S} + #bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{0}_{S} + #bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); - histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + if (doprocessMCGen) { + histos.add("multQA/h2MultCentMC", "Multiplicity vs Centrality MC", HistType::kTH2D, {centAxis, additionalConfig.multNTracksAxis}); + // MC truth invariant mass vs pT (2D) + histos.add("MC/hMCGenPtCentMultKminusLambda", "MC Truth Mass vs pT K^{-}#Lambda", kTH3D, {ptAxis, centAxis, additionalConfig.multNTracksAxis}); + histos.add("MC/hMCGenPtCentMultKplusAntiLambda", "MC Truth Mass vs pT K^{+}#bar{#Lambda}", kTH3D, {ptAxis, centAxis, additionalConfig.multNTracksAxis}); + histos.add("MC/hMCGenPtCentMultK0sLambda", "MC Truth Mass vs pT K^{0}_{S}#Lambda", kTH3D, {ptAxis, centAxis, additionalConfig.multNTracksAxis}); + histos.add("MC/hMCGenPtCentMultK0sAntiLambda", "MC Truth Mass vs pT K^{0}_{S}#bar{#Lambda}", kTH3D, {ptAxis, centAxis, additionalConfig.multNTracksAxis}); + } // MC truth histograms AxisSpec etaAxis = {100, -2.0, 2.0, "#eta"}; AxisSpec rapidityAxis = {100, -2.0, 2.0, "y"}; - histos.add("MC/hMCGenXi1820Pt", "MC Generated Xi(1820) pT", kTH1F, {ptAxis}); - histos.add("MC/hMCGenXi1820PtEta", "MC Generated Xi(1820) pT vs eta", kTH2F, {ptAxis, etaAxis}); - histos.add("MC/hMCGenXi1820Y", "MC Generated Xi(1820) rapidity", kTH1F, {rapidityAxis}); - histos.add("MC/hMCRecXi1820Pt", "MC Reconstructed Xi(1820) pT", kTH1F, {ptAxis}); - histos.add("MC/hMCRecXi1820PtEta", "MC Reconstructed Xi(1820) pT vs eta", kTH2F, {ptAxis, etaAxis}); - - // MC truth invariant mass (from MC particles) - histos.add("MC/hMCTruthInvMassKplusLambda", "MC Truth Inv Mass K^{+}#Lambda", kTH1F, {invMassAxis}); - histos.add("MC/hMCTruthInvMassKminusAntiLambda", "MC Truth Inv Mass K^{-}#bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("MC/hMCTruthInvMassK0sLambda", "MC Truth Inv Mass K^{0}_{S}#Lambda", kTH1F, {invMassAxis}); - histos.add("MC/hMCTruthInvMassK0sAntiLambda", "MC Truth Inv Mass K^{0}_{S}#bar{#Lambda}", kTH1F, {invMassAxis}); - - // MC truth invariant mass vs pT (2D) - histos.add("MC/hMCTruthMassPtKplusLambda", "MC Truth Mass vs pT K^{+}#Lambda", kTH2F, {invMassAxis, ptAxis}); - histos.add("MC/hMCTruthMassPtKminusAntiLambda", "MC Truth Mass vs pT K^{-}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); - histos.add("MC/hMCTruthMassPtK0sLambda", "MC Truth Mass vs pT K^{0}_{S}#Lambda", kTH2F, {invMassAxis, ptAxis}); - histos.add("MC/hMCTruthMassPtK0sAntiLambda", "MC Truth Mass vs pT K^{0}_{S}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); - - // K0s QA histograms - histos.add("QAbefore/k0sMass", "K0s mass before cuts", kTH1F, {{100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}}); - histos.add("QAbefore/k0sPt", "K0s pT before cuts", kTH1F, {ptAxisQA}); - histos.add("QAbefore/k0sEta", "K0s eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); - histos.add("QAbefore/k0sCosPA", "K0s CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); - histos.add("QAbefore/k0sRadius", "K0s radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); - histos.add("QAbefore/k0sDauDCA", "K0s daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); - histos.add("QAbefore/k0sProperLifetime", "K0s proper lifetime before cuts", kTH2F, {ptAxisQA, lifetimeAxis}); - - histos.add("QAafter/k0sMass", "K0s mass after cuts", kTH1F, {{100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}}); - histos.add("QAafter/k0sPt", "K0s pT after cuts", kTH1F, {ptAxisQA}); - histos.add("QAafter/k0sEta", "K0s eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); - histos.add("QAafter/k0sCosPA", "K0s CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); - histos.add("QAafter/k0sRadius", "K0s radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); - histos.add("QAafter/k0sDauDCA", "K0s daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); - histos.add("QAafter/k0sProperLifetime", "K0s proper lifetime after cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + if (doprocessMCTruth) { + histos.add("MC/hMCTruthXi1820Pt", "MC Generated Xi(1820) pT", kTH1F, {ptAxis}); + histos.add("MC/hMCTruthXi1820PtEta", "MC Generated Xi(1820) pT vs eta", kTH2F, {ptAxis, etaAxis}); + histos.add("MC/hMCTruthXi1820Y", "MC Generated Xi(1820) rapidity", kTH1F, {rapidityAxis}); + + // MC truth invariant mass (from MC particles) + histos.add("MC/hMCTruthInvMassKminusLambda", "MC Truth Inv Mass K^{-}#Lambda", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthInvMassKplusAntiLambda", "MC Truth Inv Mass K^{+}#bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthInvMassK0sLambda", "MC Truth Inv Mass K^{0}_{S}#Lambda", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthInvMassK0sAntiLambda", "MC Truth Inv Mass K^{0}_{S}#bar{#Lambda}", kTH1F, {invMassAxis}); + + // MC truth invariant mass vs pT (2D) + histos.add("MC/hMCTruthMassPtKminusLambda", "MC Truth Mass vs pT K^{-}#Lambda", kTH2F, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtKplusAntiLambda", "MC Truth Mass vs pT K^{+}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtK0sLambda", "MC Truth Mass vs pT K^{0}_{S}#Lambda", kTH2F, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtK0sAntiLambda", "MC Truth Mass vs pT K^{0}_{S}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); + } } // Lambda/Anti-Lambda selection @@ -279,7 +341,7 @@ struct Xi1820Analysis { return false; // Radius cuts - auto radius = v0.transRadius(); + float radius = v0.transRadius(); if (radius < cV0RadiusMin || radius > cV0RadiusMax) return false; @@ -302,6 +364,14 @@ struct Xi1820Analysis { return false; } + if (cV0sCrossMassRejection) { + if (std::abs(v0.mK0Short() - MassK0Short) < cV0sCrossMassRejectionWindow) + return false; + } + + if (v0.qtarm() > cK0sArmenterosAlphaCoeff * std::fabs(v0.alpha())) + return false; + return true; } @@ -328,12 +398,12 @@ struct Xi1820Analysis { return false; // Radius cuts - auto radius = v0.transRadius(); + float radius = v0.transRadius(); if (radius < cK0sRadiusMin || radius > cK0sRadiusMax) return false; // DCA to PV - if (std::abs(v0.dcav0topv()) > kMaxDcaToPv) + if (std::abs(v0.dcav0topv()) > additionalConfig.cMaxDcaToPVV0) return false; // Proper lifetime cut @@ -352,12 +422,15 @@ struct Xi1820Analysis { // Competing V0 rejection: remove (Anti)Λ if (cK0sCrossMassRejection) { - if (std::abs(v0.mLambda() - MassLambda) < cK0sMassWindow) + if (std::abs(v0.mLambda() - MassLambda) < cK0sCrossMassRejectionWindow) return false; - if (std::abs(v0.mAntiLambda() - MassLambda) < cK0sMassWindow) + if (std::abs(v0.mAntiLambda() - MassLambda) < cK0sCrossMassRejectionWindow) return false; } + if (v0.qtarm() < cK0sArmenterosAlphaCoeff * std::fabs(v0.alpha())) + return false; + return true; } @@ -476,23 +549,44 @@ struct Xi1820Analysis { template bool kaonCut(const TrackType& track) { + float candPt = track.pt(); // Basic kinematic cuts - if (track.pt() < cKaonPtMin) + if (candPt < cKaonPtMin) return false; if (std::abs(track.eta()) > cKaonEtaMax) return false; + float dcaXY = -999.f; + float dcaZ = -999.f; + // DCA cuts - different access for ResoMicroTracks if constexpr (IsResoMicrotrack) { - if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cKaonDCAxyMax) - return false; - if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()) > cKaonDCAzMax) - return false; + dcaXY = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()); + dcaZ = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()); + + if (additionalConfig.cUsePtDepDCAForKaons) { // Insert pT dependent DCAxy,z cut (tighter than global-track w DCA cut) + if (std::abs(dcaXY) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) + return false; + if (std::abs(dcaZ) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) + return false; + } else { + if (std::abs(dcaXY) > cKaonDCAxyMax) + return false; + if (std::abs(dcaZ) > cKaonDCAzMax) + return false; + } } else { - if (std::abs(track.dcaXY()) > cKaonDCAxyMax) - return false; - if (std::abs(track.dcaZ()) > cKaonDCAzMax) - return false; + if (additionalConfig.cUsePtDepDCAForKaons) { // Insert pT dependent DCAxy,z cut (tighter than global-track w DCA cut) + if (std::abs(track.dcaXY()) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) + return false; + if (std::abs(track.dcaZ()) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) + return false; + } else { + if (std::abs(track.dcaXY()) > cKaonDCAxyMax) + return false; + if (std::abs(track.dcaZ()) > cKaonDCAzMax) + return false; + } } // Track quality cuts - check if fields are available (only for ResoTracks) @@ -514,8 +608,8 @@ struct Xi1820Analysis { return true; } - template - void fill(const CollisionT& collision, const V0sT& v0s, const TracksT& tracks) + template + void fillChargedKLambda(const CollisionT& collision, const V0sT& v0s, const TracksT& tracks) // Xi(1820) analysis: charged K + Lambda channel { auto cent = collision.cent(); @@ -528,10 +622,16 @@ struct Xi1820Analysis { histos.fill(HIST("Event/nKaons"), tracks.size()); } + if (additionalConfig.cConsiderPairOnly && (v0s.size() < 1 || tracks.size() < 1)) + return; // skip events that cannot form pairs if the option is enabled (for increasing processing speed when only pairs are of interest) + // Count candidates after cuts int nV0sAfterCuts = 0; int nKaonsAfterCuts = 0; + // Build 4 combinations + ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes; + // Loop over kaon candidates for (const auto& kaon : tracks) { // QA before cuts @@ -599,6 +699,7 @@ struct Xi1820Analysis { // Lambda QA before cuts if constexpr (!IsMix) { histos.fill(HIST("QAbefore/lambdaMass"), v0.mLambda()); + histos.fill(HIST("QAbefore/lambdaMassAnti"), v0.mAntiLambda()); histos.fill(HIST("QAbefore/lambdaPt"), v0.pt()); histos.fill(HIST("QAbefore/lambdaEta"), v0.eta()); histos.fill(HIST("QAbefore/lambdaCosPA"), v0.pt(), v0.v0CosPA()); @@ -615,6 +716,7 @@ struct Xi1820Analysis { float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassLambda; histos.fill(HIST("QAbefore/lambdaProperLifetime"), v0.pt(), properLifetime); + histos.fill(HIST("QAbefore/lambdaArmenterosPodolanski"), v0.alpha(), v0.qtarm(), v0.pt()); } // Try Lambda @@ -632,7 +734,7 @@ struct Xi1820Analysis { histos.fill(HIST("QAafter/lambdaMass"), v0.mLambda()); } if (isAntiLambda) { - histos.fill(HIST("QAafter/lambdaMass"), v0.mAntiLambda()); + histos.fill(HIST("QAafter/lambdaMassAnti"), v0.mAntiLambda()); } histos.fill(HIST("QAafter/lambdaPt"), v0.pt()); histos.fill(HIST("QAafter/lambdaEta"), v0.eta()); @@ -649,55 +751,97 @@ struct Xi1820Analysis { float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassLambda; histos.fill(HIST("QAafter/lambdaProperLifetime"), v0.pt(), properLifetime); + histos.fill(HIST("QAafter/lambdaArmenterosPodolanski"), v0.alpha(), v0.qtarm(), v0.pt()); } - // Build 4 combinations - ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes; pKaon = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(kaon.pt(), kaon.eta(), kaon.phi(), MassKaonCharged)); - // K+ Lambda + // K+ + Lambda -> Bkg channel for charged Xi(1820) if (kaonCharge > 0 && isLambda) { pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + continue; if constexpr (!IsMix) { histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda"), pRes.M()); histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda"), pRes.M(), pRes.Pt(), cent); + } else { histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); } } - // K+ Anti-Lambda + // K+ + Anti-Lambda -> Signal channel for Anti-charged Xi(1820) if (kaonCharge > 0 && isAntiLambda) { pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + continue; if constexpr (!IsMix) { histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda"), pRes.M()); histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda"), pRes.M(), pRes.Pt(), cent); + if constexpr (IsMC) { // Calculate Acceptance x efficiency for "the particle" channel + if (std::abs(v0.motherPDG()) != kPdgChagedXi1820) + continue; + if (kaon.pdgCode() != PDG_t::kKPlus || v0.pdgCode() != PDG_t::kLambda0Bar) + continue; + if (kaon.motherId() != v0.motherId()) + continue; + auto pMCPt = v0.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && std::abs(v0.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut + continue; + histos.fill(HIST("MC/kplus_antilambda/hMCRecoInvMassKplusAntiLambda"), pRes.M()); + histos.fill(HIST("MC/kplus_antilambda/hMCRecoMassPtCentKplusAntiLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + + // Detail QA histograms for truth particle -> Will be updated + } } else { histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); } } - // K- Lambda + // K- + Lambda -> Signal channel for Xi(1820)- if (kaonCharge < 0 && isLambda) { pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + continue; if constexpr (!IsMix) { histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda"), pRes.M()); histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda"), pRes.M(), pRes.Pt(), cent); + if constexpr (IsMC) { // Calculate Acceptance x efficiency for "the particle" channel + if (std::abs(v0.motherPDG()) != kPdgChagedXi1820) + continue; + if (kaon.pdgCode() != PDG_t::kKMinus || v0.pdgCode() != PDG_t::kLambda0) + continue; + if (kaon.motherId() != v0.motherId()) + continue; + auto pMCPt = v0.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && std::abs(v0.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut + continue; + histos.fill(HIST("MC/kminus_lambda/hMCRecoInvMassKminusLambda"), pRes.M()); + histos.fill(HIST("MC/kminus_lambda/hMCRecoMassPtCentKminusLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + + // Detail QA histograms for the truth particle -> Will be updated + } } else { histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); } } - // K- Anti-Lambda + // K- + Anti-Lambda -> Bkg channel for charged Xi(1820) if (kaonCharge < 0 && isAntiLambda) { pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + continue; if constexpr (!IsMix) { histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda"), pRes.M()); histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda"), pRes.M(), pRes.Pt(), cent); @@ -711,203 +855,105 @@ struct Xi1820Analysis { // Fill event QA for after-cuts counters (only for same-event) if constexpr (!IsMix) { - histos.fill(HIST("Event/nV0sAfterCuts"), nV0sAfterCuts); + histos.fill(HIST("Event/nLambdasAfterCuts"), nV0sAfterCuts); histos.fill(HIST("Event/nKaonsAfterCuts"), nKaonsAfterCuts); } } - void processDummy(const aod::ResoCollision& /*collision*/) - { - // Dummy function to satisfy the compiler - } - PROCESS_SWITCH(Xi1820Analysis, processDummy, "Process Dummy", true); - - void processDataWithTracks(const aod::ResoCollision& collision, - aod::ResoV0s const& resov0s, - aod::ResoTracks const& resotracks) - { - fill(collision, resov0s, resotracks); - } - PROCESS_SWITCH(Xi1820Analysis, processDataWithTracks, "Process Event with ResoTracks", false); - - void processDataWithMicroTracks(const aod::ResoCollision& collision, - aod::ResoV0s const& resov0s, - aod::ResoMicroTracks const& resomicrotracks) + template + void fillK0sLambda(const CollisionT& collision, const V0sT& k0sCands, const V0sT& lambdaCands) // Xi(1820) analysis: K0s + Lambda channel, No need to MicroTrack! { - fill(collision, resov0s, resomicrotracks); - } - PROCESS_SWITCH(Xi1820Analysis, processDataWithMicroTracks, "Process Event with ResoMicroTracks", false); - - void processMixedEventWithTracks(const aod::ResoCollisions& collisions, - aod::ResoV0s const& resov0s, - aod::ResoTracks const& resotracks) - { - - auto v0sTracksTuple = std::make_tuple(resov0s, resotracks); - Pair pairs{colBinning, nEvtMixing, -1, collisions, v0sTracksTuple, &cache}; - - for (auto& [collision1, v0s1, collision2, tracks2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) - auto cent = collision1.cent(); - - for (const auto& kaon : tracks2) { - if (!kaonCut(kaon)) - continue; - int kaonCharge = kaon.sign(); - - for (const auto& v0 : v0s1) { - bool isLambda = v0Cut(collision1, v0, true); - bool isAntiLambda = v0Cut(collision1, v0, false); - - if (!isLambda && !isAntiLambda) - continue; - - ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes; - pKaon = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(kaon.pt(), kaon.eta(), kaon.phi(), MassKaonCharged)); + auto cent = collision.cent(); - // K+ Lambda - if (kaonCharge > 0 && isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } + // Fill event QA histograms + if constexpr (!IsMix) { + histos.fill(HIST("Event/posZ"), collision.posZ()); + histos.fill(HIST("Event/centrality"), cent); + histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); + histos.fill(HIST("Event/nV0s"), lambdaCands.size()); + histos.fill(HIST("Event/nKaons"), k0sCands.size()); + } - // K+ Anti-Lambda - if (kaonCharge > 0 && isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } + if (additionalConfig.cConsiderHasV0s && (lambdaCands.size() < 1)) + return; // skip events that do not have V0s if the option is enabled - // K- Lambda - if (kaonCharge < 0 && isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } + int nV0sAfterCuts = 0; + int nKaonsAfterCuts = 0; - // K- Anti-Lambda - if (kaonCharge < 0 && isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } - } + // Loop over V0s for K0s + for (const auto& k0s : k0sCands) { + // K0s QA before cuts + if constexpr (!IsMix) { + histos.fill(HIST("QAbefore/k0sMass"), k0s.mK0Short()); + histos.fill(HIST("QAbefore/k0sPt"), k0s.pt()); + histos.fill(HIST("QAbefore/k0sEta"), k0s.eta()); + histos.fill(HIST("QAbefore/k0sCosPA"), k0s.pt(), k0s.v0CosPA()); + histos.fill(HIST("QAbefore/k0sRadius"), k0s.pt(), k0s.transRadius()); + histos.fill(HIST("QAbefore/k0sDauDCA"), k0s.pt(), k0s.daughDCA()); + + float dx = k0s.decayVtxX() - collision.posX(); + float dy = k0s.decayVtxY() - collision.posY(); + float dz = k0s.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(k0s.px() * k0s.px() + k0s.py() * k0s.py() + k0s.pz() * k0s.pz()); + auto k0sProperLifetime = (l / (p + 1e-10)) * MassK0Short; + histos.fill(HIST("QAbefore/k0sProperLifetime"), k0s.pt(), k0sProperLifetime); + histos.fill(HIST("QAbefore/k0sArmenterosPodolanski"), k0s.alpha(), k0s.qtarm(), k0s.pt()); } - } - } - PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithTracks, "Process Mixed Event with ResoTracks", false); - - void processMixedEventWithMicroTracks(const aod::ResoCollisions& collisions, - aod::ResoV0s const& resov0s, - aod::ResoMicroTracks const& resomicrotracks) - { - auto v0sTracksTuple = std::make_tuple(resov0s, resomicrotracks); - Pair pairs{colBinning, nEvtMixing, -1, collisions, v0sTracksTuple, &cache}; + if (!k0sCut(collision, k0s)) + continue; + auto indexK0s = k0s.index(); - for (auto& [collision1, v0s1, collision2, tracks2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) - auto cent = collision1.cent(); + if constexpr (!IsMix) { + nKaonsAfterCuts++; + // K0s QA after cuts + histos.fill(HIST("QAafter/k0sMass"), k0s.mK0Short()); + histos.fill(HIST("QAafter/k0sPt"), k0s.pt()); + histos.fill(HIST("QAafter/k0sEta"), k0s.eta()); + histos.fill(HIST("QAafter/k0sCosPA"), k0s.pt(), k0s.v0CosPA()); + histos.fill(HIST("QAafter/k0sRadius"), k0s.pt(), k0s.transRadius()); + histos.fill(HIST("QAafter/k0sDauDCA"), k0s.pt(), k0s.daughDCA()); + + float dx = k0s.decayVtxX() - collision.posX(); + float dy = k0s.decayVtxY() - collision.posY(); + float dz = k0s.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(k0s.px() * k0s.px() + k0s.py() * k0s.py() + k0s.pz() * k0s.pz()); + auto k0sProperLifetime = (l / (p + 1e-10)) * MassK0Short; + histos.fill(HIST("QAafter/k0sProperLifetime"), k0s.pt(), k0sProperLifetime); + histos.fill(HIST("QAafter/k0sArmenterosPodolanski"), k0s.alpha(), k0s.qtarm(), k0s.pt()); + } - for (const auto& kaon : tracks2) { - if (!kaonCut(kaon)) - continue; - int kaonCharge = kaon.sign(); + // Loop over V0s for Lambda + for (const auto& lambda : lambdaCands) { - for (const auto& v0 : v0s1) { - bool isLambda = v0Cut(collision1, v0, true); - bool isAntiLambda = v0Cut(collision1, v0, false); + auto indexLambda = lambda.index(); - if (!isLambda && !isAntiLambda) + if constexpr (!IsMix) { + if (indexLambda == indexK0s) // Avoid self-combination continue; + histos.fill(HIST("QAbefore/lambdaMass"), lambda.mLambda()); + histos.fill(HIST("QAbefore/lambdaMassAnti"), lambda.mAntiLambda()); + histos.fill(HIST("QAbefore/lambdaPt"), lambda.pt()); + histos.fill(HIST("QAbefore/lambdaEta"), lambda.eta()); + histos.fill(HIST("QAbefore/lambdaCosPA"), lambda.pt(), lambda.v0CosPA()); + histos.fill(HIST("QAbefore/lambdaRadius"), lambda.pt(), lambda.transRadius()); + histos.fill(HIST("QAbefore/lambdaDauDCA"), lambda.pt(), lambda.daughDCA()); + histos.fill(HIST("QAbefore/lambdaDauPosDCA"), lambda.pt(), std::abs(lambda.dcapostopv())); + histos.fill(HIST("QAbefore/lambdaDauNegDCA"), lambda.pt(), std::abs(lambda.dcanegtopv())); - ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes; - pKaon = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(kaon.pt(), kaon.eta(), kaon.phi(), MassKaonCharged)); - - // K+ Lambda - if (kaonCharge > 0 && isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } - - // K+ Anti-Lambda - if (kaonCharge > 0 && isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } - - // K- Lambda - if (kaonCharge < 0 && isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } - - // K- Anti-Lambda - if (kaonCharge < 0 && isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); - pRes = pKaon + pLambda; - histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } + // Calculate proper lifetime manually + float dx = lambda.decayVtxX() - collision.posX(); + float dy = lambda.decayVtxY() - collision.posY(); + float dz = lambda.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(lambda.px() * lambda.px() + lambda.py() * lambda.py() + lambda.pz() * lambda.pz()); + auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassLambda; + histos.fill(HIST("QAbefore/lambdaProperLifetime"), lambda.pt(), properLifetime); + histos.fill(HIST("QAbefore/lambdaArmenterosPodolanski"), lambda.alpha(), lambda.qtarm(), lambda.pt()); } - } - } - } - PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithMicroTracks, "Process Mixed Event with ResoMicroTracks", false); - - // K0s + Lambda analysis - void processK0sLambda(const aod::ResoCollision& collision, - aod::ResoV0s const& resov0s) - { - auto cent = collision.cent(); - - // Fill event QA histograms - histos.fill(HIST("Event/posZ"), collision.posZ()); - histos.fill(HIST("Event/centrality"), cent); - histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); - histos.fill(HIST("Event/nV0s"), resov0s.size()); - - // Loop over V0s for K0s - for (const auto& k0s : resov0s) { - // K0s QA before cuts - histos.fill(HIST("QAbefore/k0sMass"), k0s.mK0Short()); - histos.fill(HIST("QAbefore/k0sPt"), k0s.pt()); - histos.fill(HIST("QAbefore/k0sEta"), k0s.eta()); - histos.fill(HIST("QAbefore/k0sCosPA"), k0s.pt(), k0s.v0CosPA()); - histos.fill(HIST("QAbefore/k0sRadius"), k0s.pt(), k0s.transRadius()); - histos.fill(HIST("QAbefore/k0sDauDCA"), k0s.pt(), k0s.daughDCA()); - - float dx = k0s.decayVtxX() - collision.posX(); - float dy = k0s.decayVtxY() - collision.posY(); - float dz = k0s.decayVtxZ() - collision.posZ(); - float l = std::sqrt(dx * dx + dy * dy + dz * dz); - float p = std::sqrt(k0s.px() * k0s.px() + k0s.py() * k0s.py() + k0s.pz() * k0s.pz()); - auto k0sProperLifetime = (l / (p + 1e-10)) * MassK0Short; - histos.fill(HIST("QAbefore/k0sProperLifetime"), k0s.pt(), k0sProperLifetime); - - if (!k0sCut(collision, k0s)) - continue; - // K0s QA after cuts - histos.fill(HIST("QAafter/k0sMass"), k0s.mK0Short()); - histos.fill(HIST("QAafter/k0sPt"), k0s.pt()); - histos.fill(HIST("QAafter/k0sEta"), k0s.eta()); - histos.fill(HIST("QAafter/k0sCosPA"), k0s.pt(), k0s.v0CosPA()); - histos.fill(HIST("QAafter/k0sRadius"), k0s.pt(), k0s.transRadius()); - histos.fill(HIST("QAafter/k0sDauDCA"), k0s.pt(), k0s.daughDCA()); - histos.fill(HIST("QAafter/k0sProperLifetime"), k0s.pt(), k0sProperLifetime); - - // Loop over V0s for Lambda - for (const auto& lambda : resov0s) { // Try Lambda bool isLambda = v0Cut(collision, lambda, true); // Try Anti-Lambda @@ -916,112 +962,270 @@ struct Xi1820Analysis { if (!isLambda && !isAntiLambda) continue; + if constexpr (!IsMix) { + nV0sAfterCuts++; + // QA after cuts (fill for whichever passes) + if (isLambda) { + histos.fill(HIST("QAafter/lambdaMass"), lambda.mLambda()); + } + if (isAntiLambda) { + histos.fill(HIST("QAafter/lambdaMassAnti"), lambda.mAntiLambda()); + } + histos.fill(HIST("QAafter/lambdaPt"), lambda.pt()); + histos.fill(HIST("QAafter/lambdaEta"), lambda.eta()); + histos.fill(HIST("QAafter/lambdaCosPA"), lambda.pt(), lambda.v0CosPA()); + histos.fill(HIST("QAafter/lambdaRadius"), lambda.pt(), lambda.transRadius()); + histos.fill(HIST("QAafter/lambdaDauDCA"), lambda.pt(), lambda.daughDCA()); + histos.fill(HIST("QAafter/lambdaDauPosDCA"), lambda.pt(), std::abs(lambda.dcapostopv())); + histos.fill(HIST("QAafter/lambdaDauNegDCA"), lambda.pt(), std::abs(lambda.dcanegtopv())); + + float dx = lambda.decayVtxX() - collision.posX(); + float dy = lambda.decayVtxY() - collision.posY(); + float dz = lambda.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(lambda.px() * lambda.px() + lambda.py() * lambda.py() + lambda.pz() * lambda.pz()); + auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassLambda; + histos.fill(HIST("QAafter/lambdaProperLifetime"), lambda.pt(), properLifetime); + histos.fill(HIST("QAafter/lambdaArmenterosPodolanski"), lambda.alpha(), lambda.qtarm(), lambda.pt()); + } + // 4-vectors ROOT::Math::PxPyPzEVector pK0s, pLambda, pRes; pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(k0s.pt(), k0s.eta(), k0s.phi(), MassK0Short)); - // K0s + Lambda if (isLambda) { pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mLambda())); pRes = pK0s + pLambda; - histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda"), pRes.M()); - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent); + auto pCandRapidity = pRes.Rapidity(); + if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + continue; + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda"), pRes.M()); + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent); + if constexpr (IsMC) { // Calculate Acceptance x efficiency + if (std::abs(lambda.motherPDG()) != kPdgXi1820Zero) + continue; + if (std::abs(k0s.pdgCode()) != PDG_t::kK0Short || lambda.pdgCode() != PDG_t::kLambda0) + continue; + if (k0s.motherId() != lambda.motherId()) + continue; + auto pMCPt = lambda.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && std::abs(lambda.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut + continue; + histos.fill(HIST("MC/k0s_lambda/hMCRecoInvMassK0sLambda"), pRes.M()); + histos.fill(HIST("MC/k0s_lambda/hMCRecoMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + // Detail QA histograms for truth particle -> Will be updated + } + } else { + histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } } - // K0s + Anti-Lambda if (isAntiLambda) { pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mAntiLambda())); pRes = pK0s + pLambda; - histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda"), pRes.M()); - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent); + auto pCandRapidity = pRes.Rapidity(); + if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + continue; + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda"), pRes.M()); + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent); + + if constexpr (IsMC) { // Calculate Acceptance x efficiency + if (std::abs(lambda.motherPDG()) != kPdgXi1820Zero) + continue; + if (std::abs(k0s.pdgCode()) != PDG_t::kK0Short || lambda.pdgCode() != PDG_t::kLambda0Bar) + continue; + if (k0s.motherId() != lambda.motherId()) + continue; + auto pMCPt = lambda.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && std::abs(lambda.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut + continue; + histos.fill(HIST("MC/k0s_antilambda/hMCRecoInvMassK0sAntiLambda"), pRes.M()); + histos.fill(HIST("MC/k0s_antilambda/hMCRecoMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + // Detail QA histograms for truth particle -> Will be updated + } + } else { + histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } } - } + } // End of loop over Lambda candidates + } // End of loop over K0s candidates + + // Fill event QA for after-cuts counters (only for same-event) + if constexpr (!IsMix) { + histos.fill(HIST("Event/nLambdasAfterCuts"), nV0sAfterCuts); + histos.fill(HIST("Event/nKaonsAfterCuts"), nKaonsAfterCuts); } } - PROCESS_SWITCH(Xi1820Analysis, processK0sLambda, "Process K0s + Lambda", false); - // K0s + Lambda mixed event analysis - void processK0sLambdaMixedEvent(const aod::ResoCollisions& collisions, - aod::ResoV0s const& resov0s) + void processDummy(const aod::ResoCollision& /*collision*/) { + // Dummy function to satisfy the compiler + } + PROCESS_SWITCH(Xi1820Analysis, processDummy, "Process Dummy", true); - auto v0sV0sTuple = std::make_tuple(resov0s, resov0s); - Pair pairs{colBinning, nEvtMixing, -1, collisions, v0sV0sTuple, &cache}; + void processDataWithTracks(const aod::ResoCollision& resoCollision, + aod::ResoV0s const& resoV0s, + aod::ResoTracks const& resoTracks) + { + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) + return; // skip event if RecoINEL>0 selection is enabled and event does not pass it + fillChargedKLambda(resoCollision, resoV0s, resoTracks); + } + PROCESS_SWITCH(Xi1820Analysis, processDataWithTracks, "Process Event with ResoTracks", false); - for (auto& [collision1, k0s1, collision2, lambda2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) - auto cent = collision1.cent(); + void processDataWithMicroTracks(const aod::ResoCollision& resoCollision, + aod::ResoV0s const& resoV0s, + aod::ResoMicroTracks const& resoMicroTracks) + { + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) + return; // skip event if RecoINEL>0 selection is enabled and event does not pass it + fillChargedKLambda(resoCollision, resoV0s, resoMicroTracks); + } + PROCESS_SWITCH(Xi1820Analysis, processDataWithMicroTracks, "Process Event with ResoMicroTracks", false); - for (const auto& k0s : k0s1) { - if (!k0sCut(collision1, k0s)) - continue; + void processMixedEventWithTracks(const aod::ResoCollisions& resoCollisions, + aod::ResoV0s const& resoV0s, + aod::ResoTracks const& resoTracks) + { - for (const auto& lambda : lambda2) { - bool isLambda = v0Cut(collision2, lambda, true); - bool isAntiLambda = v0Cut(collision2, lambda, false); + auto v0sTracksTuple = std::make_tuple(resoTracks, resoV0s); + BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; + Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, v0sTracksTuple, &cache}; - if (!isLambda && !isAntiLambda) - continue; + for (auto& [collision1, tracks1, collision2, v0s2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) + if (additionalConfig.cRecoINELgt0 && !collision1.isRecINELgt0()) + continue; // skip event if RecoINEL>0 selection is enabled and event does not pass it + fillChargedKLambda(collision1, v0s2, tracks1); + } + } + PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithTracks, "Process Mixed Event with ResoTracks", false); - ROOT::Math::PxPyPzEVector pK0s, pLambda, pRes; - pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(k0s.pt(), k0s.eta(), k0s.phi(), MassK0Short)); + void processMixedEventWithMicroTracks(const aod::ResoCollisions& resoCollisions, + aod::ResoV0s const& resoV0s, + aod::ResoMicroTracks const& resoMicroTracks) + { - // K0s + Lambda - if (isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mLambda())); - pRes = pK0s + pLambda; - histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } + auto v0sTracksTuple = std::make_tuple(resoV0s, resoMicroTracks); + BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; + Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, v0sTracksTuple, &cache}; - // K0s + Anti-Lambda - if (isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mAntiLambda())); - pRes = pK0s + pLambda; - histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix"), pRes.M()); - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); - } - } - } + for (auto& [collision1, v0s1, collision2, tracks2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) + if (additionalConfig.cRecoINELgt0 && !collision2.isRecINELgt0()) + continue; // skip event if RecoINEL>0 selection is enabled and event does not pass it + fillChargedKLambda(collision2, v0s1, tracks2); + } + } + PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithMicroTracks, "Process Mixed Event with ResoMicroTracks", false); + + // K0s + Lambda analysis + void processK0sLambda(const aod::ResoCollision& resoCollision, + aod::ResoV0s const& resoV0s) + { + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) + return; // skip event if RecoINEL>0 selection is enabled and event does not pass it + fillK0sLambda(resoCollision, resoV0s, resoV0s); + } + PROCESS_SWITCH(Xi1820Analysis, processK0sLambda, "Process K0s + Lambda", false); + + // K0s + Lambda mixed event analysis + void processK0sLambdaMixedEvent(const aod::ResoCollisions& resoCollisions, + aod::ResoV0s const& resoV0s) + { + + auto v0sV0sTuple = std::make_tuple(resoV0s, resoV0s); + BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; + Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, v0sV0sTuple, &cache}; + + for (auto& [collision1, k0s1, collision2, lambda2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) + if (additionalConfig.cRecoINELgt0 && !collision1.isRecINELgt0()) + continue; // skip event if RecoINEL>0 selection is enabled and event does not pass it + fillK0sLambda(collision1, k0s1, lambda2); } } PROCESS_SWITCH(Xi1820Analysis, processK0sLambdaMixedEvent, "Process K0s + Lambda Mixed Event", false); - // MC processes - placeholder for future implementation - void processMCWithTracks(const aod::ResoCollision& /*collision*/, - aod::ResoV0s const& /*resov0s*/, - aod::ResoTracks const& /*resotracks*/, - aod::McParticles const& /*mcParticles*/) + // MC processes for charged K + Lambda analysis + void processMCWithTracks(ResoMCCols::iterator const& resoMCcollision, + soa::Join const& resoMCV0s, + soa::Join const& resoMCTracks) + { + if (additionalConfig.cRecoINELgt0 && !resoMCcollision.isRecINELgt0()) + return; // skip event if RecoINEL>0 selection is enabled and event does not pass it + if (!resoMCcollision.isInAfterAllCuts()) // MC event selection + return; + fillChargedKLambda(resoMCcollision, resoMCV0s, resoMCTracks); + } + PROCESS_SWITCH(Xi1820Analysis, processMCWithTracks, "Process MC for charged K + Lambda", false); + + void processMCK0sLambda(ResoMCCols::iterator const& resoMCCollision, + soa::Join const& resoMCV0s) { - // TODO: Implement MC truth matching for K± + Lambda - // - Match reconstructed kaons to MC kaons - // - Match reconstructed Lambdas to MC Lambdas - // - Fill MC truth histograms - // - Fill reconstruction efficiency histograms + if (additionalConfig.cRecoINELgt0 && !resoMCCollision.isRecINELgt0()) + return; // skip event if RecoINEL>0 selection is enabled and event does not pass it + if (!resoMCCollision.isInAfterAllCuts()) // MC event selection + return; + fillK0sLambda(resoMCCollision, resoMCV0s, resoMCV0s); } - PROCESS_SWITCH(Xi1820Analysis, processMCWithTracks, "Process MC with ResoTracks (placeholder)", false); + PROCESS_SWITCH(Xi1820Analysis, processMCK0sLambda, "Process MC K0s + Lambda", false); - void processMCWithMicroTracks(const aod::ResoCollision& /*collision*/, - aod::ResoV0s const& /*resov0s*/, - aod::ResoMicroTracks const& /*resomicrotracks*/, + void processMCWithMicroTracks(const aod::ResoCollision& /*resoCollision*/, + aod::ResoV0s const& /*resoV0s*/, + aod::ResoMicroTracks const& /*resoMicroTracks*/, aod::McParticles const& /*mcParticles*/) { // TODO: Implement MC truth matching for K± + Lambda with MicroTracks + // But is this really necessary? -> Most of the injected MC sizes are already within small-train limit. } PROCESS_SWITCH(Xi1820Analysis, processMCWithMicroTracks, "Process MC with ResoMicroTracks (placeholder)", false); - void processMCK0sLambda(const aod::ResoCollision& /*collision*/, - aod::ResoV0s const& /*resov0s*/, - aod::McParticles const& /*mcParticles*/) + void processMCGen(ResoMCCols::iterator const& resoCollision, // Calculate denominator for the acceptance x efficiency and a part of Event-factor (for selected evennts) + aod::ResoMCParents const& resoParents) { - // TODO: Implement MC truth matching for K0s + Lambda - // - Match reconstructed K0s to MC K0s - // - Match reconstructed Lambdas to MC Lambdas - // - Fill MC truth histograms - // - Fill reconstruction efficiency histograms + auto multiplicity = resoCollision.mcMultiplicity(); + auto inCent = resoCollision.cent(); + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) // Check reco INELgt0 + return; + if (!resoCollision.isInAfterAllCuts()) + return; + histos.fill(HIST("multQA/h2MultCentMC"), inCent, multiplicity); + for (const auto& part : resoParents) { // loop over all pre-filtered Gen particle on selected events + auto pdgMother = part.pdgCode(); + if (std::abs(pdgMother) != kPdgChagedXi1820 && std::abs(pdgMother) != kPdgXi1820Zero) + continue; + if (std::abs(part.y()) >= additionalConfig.cfgRapidityCut) + continue; // skip if rapidity of the particle is outside of cut + auto motherPt = part.pt(); + auto daughter1PDG = part.daughterPDG1(); + auto daughter2PDG = part.daughterPDG2(); + + if (std::abs(pdgMother) == kPdgChagedXi1820) { // Explicity check for the safety. + // K- + Anti-Lambda, K+ + Anti-Lambda + if ((daughter1PDG == PDG_t::kKMinus && daughter2PDG == PDG_t::kLambda0) || + (daughter1PDG == PDG_t::kLambda0 && daughter2PDG == PDG_t::kKMinus)) { + histos.fill(HIST("MC/hMCGenPtCentMultKminusLambda"), motherPt, inCent, multiplicity); + } else if ((daughter1PDG == PDG_t::kKPlus && daughter2PDG == PDG_t::kLambda0Bar) || + (daughter1PDG == PDG_t::kLambda0Bar && daughter2PDG == PDG_t::kKPlus)) { + histos.fill(HIST("MC/hMCGenPtCentMultKplusAntiLambda"), motherPt, inCent, multiplicity); + } + } else { + // K0s + Lambda, K0s + Anti-Lambda + if ((std::abs(daughter1PDG) == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0) || + (daughter1PDG == PDG_t::kLambda0 && std::abs(daughter2PDG) == PDG_t::kK0Short)) { + histos.fill(HIST("MC/hMCGenPtCentMultK0sLambda"), motherPt, inCent, multiplicity); + } else if ((std::abs(daughter1PDG) == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0Bar) || + (daughter1PDG == PDG_t::kLambda0Bar && std::abs(daughter2PDG) == PDG_t::kK0Short)) { + histos.fill(HIST("MC/hMCGenPtCentMultK0sAntiLambda"), motherPt, inCent, multiplicity); + } + } + } } - PROCESS_SWITCH(Xi1820Analysis, processMCK0sLambda, "Process MC K0s + Lambda (placeholder)", false); + PROCESS_SWITCH(Xi1820Analysis, processMCGen, "Process Event for MC (Generated at selected events)", false); - void processMCGenerated(aod::McParticles const& mcParticles) + void processMCTruth(aod::McParticles const& mcParticles) // ->Let's keep it and use for injected MC QA...! { // Process MC generated particles (no reconstruction requirement) // Xi(1820)0 PDG code: 123314 (neutral, decays to K+ Lambda or K0s Lambda) @@ -1033,7 +1237,7 @@ struct Xi1820Analysis { // Xi(1820)0: PDG 123314 // Check if it's Xi(1820) or similar resonance - if (std::abs(pdg) != kPdgXi1820) + if (std::abs(pdg) != kPdgChagedXi1820 && std::abs(pdg) != kPdgXi1820Zero) continue; // Fill generated level histograms @@ -1041,9 +1245,9 @@ struct Xi1820Analysis { auto eta = mcParticle.eta(); auto y = mcParticle.y(); - histos.fill(HIST("MC/hMCGenXi1820Pt"), pt); - histos.fill(HIST("MC/hMCGenXi1820PtEta"), pt, eta); - histos.fill(HIST("MC/hMCGenXi1820Y"), y); + histos.fill(HIST("MC/hMCTruthXi1820Pt"), pt); + histos.fill(HIST("MC/hMCTruthXi1820PtEta"), pt, eta); + histos.fill(HIST("MC/hMCTruthXi1820Y"), y); // Get daughters auto daughters = mcParticle.daughters_as(); @@ -1064,43 +1268,42 @@ struct Xi1820Analysis { } iDaughter++; } - pMother = p1 + p2; // Check decay channels auto motherPt = pMother.Pt(); auto motherM = pMother.M(); - // K+ + Lambda - if ((daughter1PDG == PDG_t::kKPlus && daughter2PDG == PDG_t::kLambda0) || - (daughter1PDG == PDG_t::kLambda0 && daughter2PDG == PDG_t::kKPlus)) { - histos.fill(HIST("MC/hMCTruthInvMassKplusLambda"), motherM); - histos.fill(HIST("MC/hMCTruthMassPtKplusLambda"), motherM, motherPt); + // K- + Lambda + if ((daughter1PDG == PDG_t::kKMinus && daughter2PDG == PDG_t::kLambda0) || + (daughter1PDG == PDG_t::kLambda0 && daughter2PDG == PDG_t::kKMinus)) { + histos.fill(HIST("MC/hMCTruthInvMassKminusLambda"), motherM); + histos.fill(HIST("MC/hMCTruthMassPtKminusLambda"), motherM, motherPt); } - // K- + Anti-Lambda - if ((daughter1PDG == PDG_t::kKMinus && daughter2PDG == PDG_t::kLambda0Bar) || - (daughter1PDG == PDG_t::kLambda0Bar && daughter2PDG == PDG_t::kKMinus)) { - histos.fill(HIST("MC/hMCTruthInvMassKminusAntiLambda"), motherM); - histos.fill(HIST("MC/hMCTruthMassPtKminusAntiLambda"), motherM, motherPt); + // K+ + Anti-Lambda + if ((daughter1PDG == PDG_t::kKPlus && daughter2PDG == PDG_t::kLambda0Bar) || + (daughter1PDG == PDG_t::kLambda0Bar && daughter2PDG == PDG_t::kKPlus)) { + histos.fill(HIST("MC/hMCTruthInvMassKplusAntiLambda"), motherM); + histos.fill(HIST("MC/hMCTruthMassPtKplusAntiLambda"), motherM, motherPt); } // K0s + Lambda - if ((daughter1PDG == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0) || - (daughter1PDG == PDG_t::kLambda0 && daughter2PDG == PDG_t::kK0Short)) { + if ((std::abs(daughter1PDG) == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0) || + (daughter1PDG == PDG_t::kLambda0 && std::abs(daughter2PDG) == PDG_t::kK0Short)) { histos.fill(HIST("MC/hMCTruthInvMassK0sLambda"), motherM); histos.fill(HIST("MC/hMCTruthMassPtK0sLambda"), motherM, motherPt); } // K0s + Anti-Lambda - if ((daughter1PDG == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0Bar) || - (daughter1PDG == PDG_t::kLambda0Bar && daughter2PDG == PDG_t::kK0Short)) { + if ((std::abs(daughter1PDG) == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0Bar) || + (daughter1PDG == PDG_t::kLambda0Bar && std::abs(daughter2PDG) == PDG_t::kK0Short)) { histos.fill(HIST("MC/hMCTruthInvMassK0sAntiLambda"), motherM); histos.fill(HIST("MC/hMCTruthMassPtK0sAntiLambda"), motherM, motherPt); } } } - PROCESS_SWITCH(Xi1820Analysis, processMCGenerated, "Process MC generated particles", false); + PROCESS_SWITCH(Xi1820Analysis, processMCTruth, "Process MC Truth particles", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/CMakeLists.txt b/PWGLF/Tasks/Strangeness/CMakeLists.txt index e3d115324c6..d59685bc93d 100644 --- a/PWGLF/Tasks/Strangeness/CMakeLists.txt +++ b/PWGLF/Tasks/Strangeness/CMakeLists.txt @@ -166,6 +166,11 @@ o2physics_add_dpl_workflow(lambdajetpolarization PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lambdajetpolarizationionsderived + SOURCES lambdaJetPolarizationIonsDerived.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(lambdaspincorrderived SOURCES lambdaspincorrderived.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx index 8700b91bfd0..28a6759f51e 100644 --- a/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx @@ -215,6 +215,7 @@ struct derivedlambdakzeroanalysis { Configurable rejectNegITSafterburner{"rejectNegITSafterburner", false, "reject negative track formed out of afterburner ITS tracks"}; Configurable requirePosITSafterburnerOnly{"requirePosITSafterburnerOnly", false, "require positive track formed out of afterburner ITS tracks"}; Configurable requireNegITSafterburnerOnly{"requireNegITSafterburnerOnly", false, "require negative track formed out of afterburner ITS tracks"}; + Configurable requireAtLeastOneHasTOF{"requireAtLeastOneHasTOF", false, "require that at least one of daughter tracks has an associated TOF signal"}; Configurable requirePosHasTOF{"requirePosHasTOF", false, "require that positive track has an associated TOF signal. On false, TOF requirement (if any) is only applied IF the track has an associated TOF signal."}; Configurable requireNegHasTOF{"requireNegHasTOF", false, "require that negative track has an associated TOF signal. On false, TOF requirement (if any) is only applied IF the track has an associated TOF signal."}; Configurable rejectTPCsectorBoundary{"rejectTPCsectorBoundary", false, "reject tracks close to the TPC sector boundaries"}; @@ -529,15 +530,15 @@ struct derivedlambdakzeroanalysis { BITSET(maskAntiLambdaSpecific, selTPCPIDPositivePion); } // TOF PID - if (v0Selections.requirePosHasTOF || v0Selections.tofPidNsigmaCutK0Pi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut + if (v0Selections.requireAtLeastOneHasTOF || v0Selections.requirePosHasTOF || v0Selections.tofPidNsigmaCutK0Pi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut BITSET(maskK0ShortSpecific, selTOFNSigmaPositivePionK0Short); BITSET(maskK0ShortSpecific, selTOFDeltaTPositivePionK0Short); } - if (v0Selections.requirePosHasTOF || v0Selections.tofPidNsigmaCutLaPr < 1e+5 || v0Selections.maxDeltaTimeProton < 1e+6) { // safeguard for no cut + if (v0Selections.requireAtLeastOneHasTOF || v0Selections.requirePosHasTOF || v0Selections.tofPidNsigmaCutLaPr < 1e+5 || v0Selections.maxDeltaTimeProton < 1e+6) { // safeguard for no cut BITSET(maskLambdaSpecific, selTOFNSigmaPositiveProtonLambda); BITSET(maskLambdaSpecific, selTOFDeltaTPositiveProtonLambda); } - if (v0Selections.requirePosHasTOF || v0Selections.tofPidNsigmaCutLaPi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut + if (v0Selections.requireAtLeastOneHasTOF || v0Selections.requirePosHasTOF || v0Selections.tofPidNsigmaCutLaPi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut BITSET(maskAntiLambdaSpecific, selTOFNSigmaPositivePionLambda); BITSET(maskAntiLambdaSpecific, selTOFDeltaTPositivePionLambda); } @@ -555,15 +556,15 @@ struct derivedlambdakzeroanalysis { BITSET(maskAntiLambdaSpecific, selTPCPIDNegativeProton); } // TOF PID - if (v0Selections.requireNegHasTOF || v0Selections.tofPidNsigmaCutK0Pi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut + if (v0Selections.requireAtLeastOneHasTOF || v0Selections.requireNegHasTOF || v0Selections.tofPidNsigmaCutK0Pi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut BITSET(maskK0ShortSpecific, selTOFNSigmaNegativePionK0Short); BITSET(maskK0ShortSpecific, selTOFDeltaTNegativePionK0Short); } - if (v0Selections.requireNegHasTOF || v0Selections.tofPidNsigmaCutLaPi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut + if (v0Selections.requireAtLeastOneHasTOF || v0Selections.requireNegHasTOF || v0Selections.tofPidNsigmaCutLaPi < 1e+5 || v0Selections.maxDeltaTimePion < 1e+6) { // safeguard for no cut BITSET(maskLambdaSpecific, selTOFNSigmaNegativePionLambda); BITSET(maskLambdaSpecific, selTOFDeltaTNegativePionLambda); } - if (v0Selections.requireNegHasTOF || v0Selections.tofPidNsigmaCutLaPr < 1e+5 || v0Selections.maxDeltaTimeProton < 1e+6) { // safeguard for no cut + if (v0Selections.requireAtLeastOneHasTOF || v0Selections.requireNegHasTOF || v0Selections.tofPidNsigmaCutLaPr < 1e+5 || v0Selections.maxDeltaTimeProton < 1e+6) { // safeguard for no cut BITSET(maskAntiLambdaSpecific, selTOFNSigmaNegativeProtonLambda); BITSET(maskAntiLambdaSpecific, selTOFDeltaTNegativeProtonLambda); } @@ -1314,13 +1315,25 @@ struct derivedlambdakzeroanalysis { // TOF PID in DeltaT // Positive track - if (v0Selections.requirePosHasTOF) { - if (v0.positiveHasTOF() && std::fabs(v0.posTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + if (v0Selections.requirePosHasTOF || v0Selections.requireAtLeastOneHasTOF) { + if (v0.positiveHasTOF() && std::fabs(v0.posTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) { BITSET(bitMap, selTOFDeltaTPositiveProtonLambda); - if (v0.positiveHasTOF() && std::fabs(v0.posTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + if (v0Selections.requireAtLeastOneHasTOF) { // positive has a TOF hit --> no need to check for negative + BITSET(bitMap, selTOFDeltaTNegativePionLambda); + } + } + if (v0.positiveHasTOF() && std::fabs(v0.posTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) { BITSET(bitMap, selTOFDeltaTPositivePionLambda); - if (v0.positiveHasTOF() && std::fabs(v0.posTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) + if (v0Selections.requireAtLeastOneHasTOF) { // positive has a TOF hit --> no need to check for negative + BITSET(bitMap, selTOFDeltaTNegativeProtonLambda); + } + } + if (v0.positiveHasTOF() && std::fabs(v0.posTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) { BITSET(bitMap, selTOFDeltaTPositivePionK0Short); + if (v0Selections.requireAtLeastOneHasTOF) { // positive has a TOF hit --> no need to check for negative + BITSET(bitMap, selTOFDeltaTNegativePionK0Short); + } + } } else { // only apply TOF requirement if available if (!v0.positiveHasTOF() || std::fabs(v0.posTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) BITSET(bitMap, selTOFDeltaTPositiveProtonLambda); @@ -1330,13 +1343,25 @@ struct derivedlambdakzeroanalysis { BITSET(bitMap, selTOFDeltaTPositivePionK0Short); } // Negative track - if (v0Selections.requireNegHasTOF) { - if (v0.negativeHasTOF() && std::fabs(v0.negTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + if (v0Selections.requireNegHasTOF || v0Selections.requireAtLeastOneHasTOF) { + if (v0.negativeHasTOF() && std::fabs(v0.negTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) { BITSET(bitMap, selTOFDeltaTNegativeProtonLambda); - if (v0.negativeHasTOF() && std::fabs(v0.negTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + if (v0Selections.requireAtLeastOneHasTOF) { // negative has a TOF hit --> no need to check for positive + BITSET(bitMap, selTOFDeltaTPositivePionLambda); + } + } + if (v0.negativeHasTOF() && std::fabs(v0.negTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) { BITSET(bitMap, selTOFDeltaTNegativePionLambda); - if (v0.negativeHasTOF() && std::fabs(v0.negTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) + if (v0Selections.requireAtLeastOneHasTOF) { // negative has a TOF hit --> no need to check for positive + BITSET(bitMap, selTOFDeltaTPositiveProtonLambda); + } + } + if (v0.negativeHasTOF() && std::fabs(v0.negTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) { BITSET(bitMap, selTOFDeltaTNegativePionK0Short); + if (v0Selections.requireAtLeastOneHasTOF) { // negative has a TOF hit --> no need to check for positive + BITSET(bitMap, selTOFDeltaTPositivePionK0Short); + } + } } else { // only apply TOF requirement if available if (!v0.negativeHasTOF() || std::fabs(v0.negTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) BITSET(bitMap, selTOFDeltaTNegativeProtonLambda); @@ -1348,13 +1373,25 @@ struct derivedlambdakzeroanalysis { // TOF PID in NSigma // Positive track - if (v0Selections.requirePosHasTOF) { - if (v0.positiveHasTOF() && std::fabs(v0.tofNSigmaLaPr()) < v0Selections.tofPidNsigmaCutLaPr) + if (v0Selections.requirePosHasTOF || v0Selections.requireAtLeastOneHasTOF) { + if (v0.positiveHasTOF() && std::fabs(v0.tofNSigmaLaPr()) < v0Selections.tofPidNsigmaCutLaPr) { BITSET(bitMap, selTOFNSigmaPositiveProtonLambda); - if (v0.positiveHasTOF() && std::fabs(v0.tofNSigmaALaPi()) < v0Selections.tofPidNsigmaCutLaPi) + if (v0Selections.requireAtLeastOneHasTOF) { // positive has a TOF hit --> no need to check for negative + BITSET(bitMap, selTOFNSigmaNegativePionLambda); + } + } + if (v0.positiveHasTOF() && std::fabs(v0.tofNSigmaALaPi()) < v0Selections.tofPidNsigmaCutLaPi) { BITSET(bitMap, selTOFNSigmaPositivePionLambda); - if (v0.positiveHasTOF() && std::fabs(v0.tofNSigmaK0PiPlus()) < v0Selections.tofPidNsigmaCutK0Pi) + if (v0Selections.requireAtLeastOneHasTOF) { // positive has a TOF hit --> no need to check for negative + BITSET(bitMap, selTOFNSigmaNegativeProtonLambda); + } + } + if (v0.positiveHasTOF() && std::fabs(v0.tofNSigmaK0PiPlus()) < v0Selections.tofPidNsigmaCutK0Pi) { BITSET(bitMap, selTOFNSigmaPositivePionK0Short); + if (v0Selections.requireAtLeastOneHasTOF) { // positive has a TOF hit --> no need to check for negative + BITSET(bitMap, selTOFNSigmaNegativePionK0Short); + } + } } else { // only apply TOF requirement if available if (!v0.positiveHasTOF() || std::fabs(v0.tofNSigmaLaPr()) < v0Selections.tofPidNsigmaCutLaPr) BITSET(bitMap, selTOFNSigmaPositiveProtonLambda); @@ -1364,13 +1401,25 @@ struct derivedlambdakzeroanalysis { BITSET(bitMap, selTOFNSigmaPositivePionK0Short); } // Negative track - if (v0Selections.requireNegHasTOF) { - if (v0.negativeHasTOF() && std::fabs(v0.tofNSigmaALaPr()) < v0Selections.tofPidNsigmaCutLaPr) + if (v0Selections.requireNegHasTOF || v0Selections.requireAtLeastOneHasTOF) { + if (v0.negativeHasTOF() && std::fabs(v0.tofNSigmaALaPr()) < v0Selections.tofPidNsigmaCutLaPr) { BITSET(bitMap, selTOFNSigmaNegativeProtonLambda); - if (v0.negativeHasTOF() && std::fabs(v0.tofNSigmaLaPi()) < v0Selections.tofPidNsigmaCutLaPi) + if (v0Selections.requireAtLeastOneHasTOF) { // negative has a TOF hit --> no need to check for positive + BITSET(bitMap, selTOFNSigmaPositivePionLambda); + } + } + if (v0.negativeHasTOF() && std::fabs(v0.tofNSigmaLaPi()) < v0Selections.tofPidNsigmaCutLaPi) { BITSET(bitMap, selTOFNSigmaNegativePionLambda); - if (v0.negativeHasTOF() && std::fabs(v0.tofNSigmaK0PiMinus()) < v0Selections.tofPidNsigmaCutK0Pi) + if (v0Selections.requireAtLeastOneHasTOF) { // negative has a TOF hit --> no need to check for positive + BITSET(bitMap, selTOFNSigmaPositiveProtonLambda); + } + } + if (v0.negativeHasTOF() && std::fabs(v0.tofNSigmaK0PiMinus()) < v0Selections.tofPidNsigmaCutK0Pi) { BITSET(bitMap, selTOFNSigmaNegativePionK0Short); + if (v0Selections.requireAtLeastOneHasTOF) { // negative has a TOF hit --> no need to check for positive + BITSET(bitMap, selTOFNSigmaPositivePionK0Short); + } + } } else { // only apply TOF requirement if available if (!v0.negativeHasTOF() || std::fabs(v0.tofNSigmaALaPr()) < v0Selections.tofPidNsigmaCutLaPr) BITSET(bitMap, selTOFNSigmaNegativeProtonLambda); @@ -2013,7 +2062,12 @@ struct derivedlambdakzeroanalysis { return; // does not have mother particle in record, skip auto v0mother = v0.motherMCPart(); - float rapidityXi = RecoDecay::y(std::array{v0mother.px(), v0mother.py(), v0mother.pz()}, o2::constants::physics::MassXiMinus); + float rapidityXi = 999.; + if (std::abs(v0mother.pdgCode()) == PDG_t::kXiMinus) + rapidityXi = RecoDecay::y(std::array{v0mother.px(), v0mother.py(), v0mother.pz()}, o2::constants::physics::MassXiMinus); + if (std::abs(v0mother.pdgCode()) == o2::constants::physics::Pdg::kXi0) + rapidityXi = RecoDecay::y(std::array{v0mother.px(), v0mother.py(), v0mother.pz()}, o2::constants::physics::MassXi0); + if (std::fabs(rapidityXi) > 0.5f) return; // not a valid mother rapidity (PDG selection is later) diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index 8d56b547a82..0c0c04f1448 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -41,6 +41,7 @@ #include +#include #include #include @@ -68,8 +69,9 @@ struct HStrangeCorrelation { OutputObj zorroSummary{"zorroSummary"}; struct : ConfigurableGroup { + std::string prefix = "masterConfigurations"; Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; - Configurable collisionHasTrigOrAssoc{"collisionHasTriggOrAssoc", 0, "require the collisions containing (0:no requirement 1:trig 2:assoc 3:trig or assoc 4:trig and assoc"}; + Configurable collisionHasTriggOrAssoc{"collisionHasTriggOrAssoc", 0, "require the collisions containing (0:no requirement 1:trig 2:assoc 3:trig or assoc 4:trig and assoc"}; Configurable doFullCorrelationStudy{"doFullCorrelationStudy", true, "if true, do full correlation study by creating all THnSparse histograms for the correlation function"}; Configurable doCorrelationHadron{"doCorrelationHadron", false, "do Hadron correlation"}; Configurable doCorrelationK0Short{"doCorrelationK0Short", true, "do K0Short correlation"}; @@ -88,6 +90,7 @@ struct HStrangeCorrelation { Configurable mixingParameter{"mixingParameter", 10, "how many events are mixed"}; Configurable doMCassociation{"doMCassociation", false, "fill everything only for MC associated"}; Configurable doTriggPhysicalPrimary{"doTriggPhysicalPrimary", false, "require physical primary for trigger particles"}; + Configurable applyNewMCSelection{"applyNewMCSelection", false, "apply new MC Generated selection"}; } masterConfigurations; // master analysis switches @@ -111,6 +114,7 @@ struct HStrangeCorrelation { // Axes - configurable for smaller sizes struct : ConfigurableGroup { + std::string prefix = "axesConfigurations"; ConfigurableAxis axisMult{"axisMult", {VARIABLE_WIDTH, 0.0f, 0.01f, 1.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 70.0f, 100.0f}, "Mixing bins - multiplicity"}; ConfigurableAxis axisVtxZ{"axisVtxZ", {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 axisPhi{"axisPhi", {72, 0, TwoPI}, "#phi"}; @@ -126,6 +130,7 @@ struct HStrangeCorrelation { // for topo var QA struct : ConfigurableGroup { + std::string prefix = "massWindowConfigurations"; Configurable maxPeakNSigma{"maxPeakNSigma", 5, "Peak region edge definition (in sigma)"}; Configurable minBgNSigma{"minBgNSigma", 5, "Bg region edge closest to peak (in sigma)"}; Configurable maxBgNSigma{"maxBgNSigma", 10, "Bg region edge furthest to peak (in sigma)"}; @@ -134,6 +139,7 @@ struct HStrangeCorrelation { // Implementation of on-the-spot efficiency correction struct : ConfigurableGroup { + std::string prefix = "efficiencyFlags"; Configurable applyEfficiencyCorrection{"applyEfficiencyCorrection", false, "apply efficiency correction"}; Configurable applyEfficiencyForTrigger{"applyEfficiencyForTrigger", false, "apply efficiency correction for the trigger particle"}; Configurable applyEfficiencyPropagation{"applyEfficiencyPropagation", false, "propagate also the efficiency uncertainty"}; @@ -146,9 +152,8 @@ struct HStrangeCorrelation { Configurable efficiencyCCDBPath{"efficiencyCCDBPath", "GLO/Config/GeometryAligned", "Path of the efficiency corrections"}; // Configurables for doing subwagon systematics - // Group all settings necessary for systematics in a specific ConfigurableGroup struct : ConfigurableGroup { - std::string prefix = "systematics"; + std::string prefix = "trackSelection"; // --- Track quality variations (single track, both trigger and assoc daughters) Configurable minTPCNCrossedRowsTrigger{"minTPCNCrossedRowsTrigger", 70, "Minimum TPC crossed rows (trigger)"}; Configurable minTPCNCrossedRowsAssociated{"minTPCNCrossedRowsAssociated", 70, "Minimum TPC crossed rows (associated)"}; @@ -158,16 +163,22 @@ struct HStrangeCorrelation { Configurable assocMaxTPCSharedClusters{"assocMaxTPCSharedClusters", 200, "maximum number of shared TPC clusters (inclusive) for assoc primary tracks"}; Configurable triggerRequireL0{"triggerRequireL0", false, "require ITS L0 cluster for trigger"}; Configurable assocRequireL0{"assocRequireL0", true, "require ITS L0 cluster for assoc primary track"}; - // Track quality in PbPb - Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + Configurable minTPCChi2PerClusterAssociated{"minTPCChi2PerClusterAssociated", 4.0f, "Minimum TPC chi2 per cluster for associated primary tracks"}; + Configurable checksRequireTPCChi2{"checksRequireTPCChi2", false, "require TPC chi2 per cluster for trigger and associated primary tracks"}; + Configurable requireClusterInITS{"requireClusterInITS", false, "require cluster in ITS for V0 and cascade daughter tracks"}; + Configurable minITSClustersForDaughterTracks{"minITSClustersForDaughterTracks", 1, "Minimum number of ITS clusters for V0 daughter tracks"}; // --- Trigger: DCA variation from basic formula: |DCAxy| < 0.004f + (0.013f / pt) Configurable dcaXYconstant{"dcaXYconstant", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; - + // --- Assoc track: DCA variation from basic formula: |DCAxy| < 0.004f + (0.013f / pt) Configurable dcaXYconstantAssoc{"dcaXYconstantAssoc", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; Configurable dcaXYpTdepAssoc{"dcaXYpTdepAssoc", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; - + Configurable dEdxCompatibility{"dEdxCompatibility", 1, "0: loose, 1: normal, 2: tight. Defined in HStrangeCorrelationFilter"}; + } trackSelection; + struct : ConfigurableGroup { + std::string prefix = "v0Selection"; + // --- V0 selections (both K0Short and Lambda, but some can be Lambda specific, see below) // --- Associated: topological variable variation (OK to vary all-at-once, at least for first study) Configurable v0cospa{"v0cospa", 0.97, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) Configurable dcaV0dau{"dcaV0dau", 1.0, "DCA V0 Daughters"}; @@ -175,50 +186,49 @@ struct HStrangeCorrelation { Configurable dcapostopv{"dcapostopv", 0.06, "DCA Pos To PV"}; Configurable v0RadiusMin{"v0RadiusMin", 0.5, "v0radius"}; Configurable v0RadiusMax{"v0RadiusMax", 200, "v0radius"}; - // more V0 selections in PbPb + Configurable dcaBaryonToPV{"dcaBaryonToPV", 0.2, "DCA of baryon daughter track To PV"}; + Configurable dcaMesonToPV{"dcaMesonToPV", 0.05, "DCA of meson daughter track To PV"}; Configurable lifetimecutK0S{"lifetimecutK0S", 20, "lifetimecutK0S"}; Configurable lifetimecutLambda{"lifetimecutLambda", 30, "lifetimecutLambda"}; - Configurable dcanegtopvK0S{"dcanegtopvK0S", 0.1, "DCA Neg To PV"}; - Configurable dcapostopvK0S{"dcapostopvK0S", 0.1, "DCA Pos To PV"}; - Configurable dcanegtopvLambda{"dcanegtopvLambda", 0.05, "DCA Neg To PV"}; - Configurable dcapostopvLambda{"dcapostopvLambda", 0.2, "DCA Pos To PV"}; - Configurable dcanegtopvAntiLambda{"dcanegtopvAntiLambda", 0.2, "DCA Neg To PV"}; - Configurable dcapostopvAntiLambda{"dcapostopvAntiLambda", 0.05, "DCA Pos To PV"}; // original equation: lArmPt*2>TMath::Abs(lArmAlpha) only for K0S Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + } v0Selection; - // cascade selections + struct : ConfigurableGroup { + std::string prefix = "cascadeSelections"; Configurable cascCospa{"cascCospa", 0.95, "cascCospa"}; - Configurable cascDcacascdau{"cascDcacascdau", 1.0, "cascDcacascdau"}; - Configurable cascDcabachtopv{"cascDcabachtopv", 0.1, "cascDcabachtopv"}; + Configurable dcaCascDaughters{"dcaCascDaughters", 1.0, "DCA between the V0 candidate and the bachelor track"}; + // Configurable cascDcabachtopv{"cascDcabachtopv", 0.1, "cascDcabachtopv"}; Configurable cascRadius{"cascRadius", 0.5, "cascRadius"}; Configurable cascV0masswindow{"cascV0masswindow", 0.01, "cascV0masswindow"}; - Configurable cascMindcav0topv{"cascMindcav0topv", 0.01, "cascMindcav0topv"}; - // more cascade selections in PbPb Configurable bachBaryonCosPA{"bachBaryonCosPA", 0.9999, "Bachelor baryon CosPA"}; Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; - Configurable dcaBaryonToPV{"dcaBaryonToPV", 0.05, "DCA of baryon doughter track To PV"}; - Configurable dcaMesonToPV{"dcaMesonToPV", 0.1, "DCA of meson doughter track To PV"}; - Configurable dcaBachToPV{"dcaBachToPV", 0.07, "DCA Bach To PV"}; Configurable cascdcaV0dau{"cascdcaV0dau", 0.5, "DCA V0 Daughters"}; + Configurable proplifetime{"proplifetime", 3, "ctau/"}; + Configurable rejcomp{"rejcomp", 0.008, "Competing Cascade rejection"}; + Configurable rapCut{"rapCut", 0.8, "Rapidity acceptance"}; Configurable dcaCacsDauPar0{"dcaCacsDauPar0", 0.8, " par for pt dep DCA cascade daughter cut, p_T < 1 GeV/c"}; Configurable dcaCacsDauPar1{"dcaCacsDauPar1", 0.5, " par for pt dep DCA cascade daughter cut, 1< p_T < 4 GeV/c"}; Configurable dcaCacsDauPar2{"dcaCacsDauPar2", 0.2, " par for pt dep DCA cascade daughter cut, p_T > 4 GeV/c"}; Configurable cascdcaV0ToPV{"cascdcaV0ToPV", 0.06, "DCA V0 To PV"}; Configurable cascv0cospa{"cascv0cospa", 0.98, "V0 CosPA"}; Configurable cascv0RadiusMin{"cascv0RadiusMin", 2.5, "v0radius"}; - Configurable proplifetime{"proplifetime", 3, "ctau/"}; - Configurable lambdaMassWin{"lambdaMassWin", 0.005, "V0 Mass window limit"}; - Configurable rejcomp{"rejcomp", 0.008, "Competing Cascade rejection"}; - Configurable rapCut{"rapCut", 0.8, "Rapidity acceptance"}; - + Configurable dcaBaryonToPV{"dcaBaryonToPV", 0.05, "DCA of baryon doughter track To PV"}; + Configurable dcaMesonToPV{"dcaMesonToPV", 0.1, "DCA of meson doughter track To PV"}; + Configurable dcaBachToPV{"dcaBachToPV", 0.07, "DCA Bach To PV"}; // pt Range for pt dep cuts Configurable highPtForCascDaugPtDep{"highPtForCascDaugPtDep", 4.0, "high pt range for pt dep cuts"}; Configurable lowPtForCascDaugPtDep{"lowPtForCascDaugPtDep", 1.0, "low pt range for pt dep cuts"}; - // dE/dx for associated daughters - Configurable dEdxCompatibility{"dEdxCompatibility", 1, "0: loose, 1: normal, 2: tight. Defined in HStrangeCorrelationFilter"}; + } cascadeSelections; + struct : ConfigurableGroup { + std::string prefix = "`"; + // cascade selections + // more cascade selections in PbPb + // Configurable bachBaryonCosPA{"bachBaryonCosPA", 0.9999, "Bachelor baryon CosPA"}; + // Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; + // // on the fly correction instead of mixingParameter Configurable doOnTheFlyFlattening{"doOnTheFlyFlattening", 0, "enable an on-the-fly correction instead of using mixing"}; @@ -227,7 +237,36 @@ struct HStrangeCorrelation { Configurable transwerseDeltaEtaRangeMax{"transwerseDeltaEtaRangeMax", 2.0, "maximum delta eta for transverse region"}; Configurable towardDeltaEtaRange{"towardDeltaEtaRange", 0.8, "delta eta range for toward region"}; // (N.B.: sources that can be investigated in post are not listed!) - } systCuts; + } checks; + + struct ValidCollision { + struct ValidParticle { + float eta; + float phi; + float pt; + int region; + float efficiency; + float efficiencyError; + int type; + }; + float pvz; + float mult; + std::vector trigParticles; + std::vector assocParticles; + void addValidParticle(float eta, float phi, float pt, int region, float efficiency, float efficiencyError, int type) + { + ValidParticle particle{eta, phi, pt, region, efficiency, efficiencyError, type}; + + if (type == -1) { + trigParticles.push_back(particle); + } else { + assocParticles.push_back(particle); + } + } + }; + + using ValidCollisions = std::vector>; + ValidCollisions validCollisions; // objects to use for efficiency corrections TH2F* hEfficiencyTrigger; @@ -389,6 +428,8 @@ struct HStrangeCorrelation { hPurityUncertaintyHadronMult = static_cast(listEfficiencies->FindObject("hPurityUncertaintyHadronMult")); if (efficiencyFlags.applyEfficiencyPropagation && !efficiencyFlags.applyEffAsFunctionOfMultAndPhi && !hEfficiencyUncertaintyTrigger) LOG(fatal) << "Problem getting hEfficiencyUncertaintyTrigger!"; + if (efficiencyFlags.applyEffAsFunctionOfMult && !hEfficiencyTriggerMult) + LOG(fatal) << "Problem getting hEfficiencyTriggerMult!"; LOG(info) << "Efficiencies now loaded for " << mRunNumber; } @@ -400,26 +441,26 @@ struct HStrangeCorrelation { // proper lifetime , DCA daughter to prim.vtx if (masterConfigurations.doCorrelationK0Short) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S) SETBIT(bitMap, 0); // DCA daughter to prim.vtx and armenteros - if (std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha())) + if (std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha())) SETBIT(bitMap, 3); } if (masterConfigurations.doCorrelationLambda) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < systCuts.lifetimecutLambda) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) SETBIT(bitMap, 1); // DCA daughter to prim.vtx - if (std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda) + if (std::abs(v0.dcapostopv()) > v0Selection.dcaBaryonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV) SETBIT(bitMap, 4); } if (masterConfigurations.doCorrelationAntiLambda) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < systCuts.lifetimecutLambda) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) SETBIT(bitMap, 2); // DCA daughter to prim.vtx - if (std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda) + if (std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV) SETBIT(bitMap, 5); } return bitMap; @@ -433,64 +474,65 @@ struct HStrangeCorrelation { float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxi); float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomega); + + bool isGoodDCANegCasc = std::abs(casc.dcabachtopv()) > cascadeSelections.dcaBachToPV && std::abs(casc.dcapostopv()) > cascadeSelections.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > cascadeSelections.dcaMesonToPV; + bool isGoodDCAPosCasc = std::abs(casc.dcabachtopv()) > cascadeSelections.dcaBachToPV && std::abs(casc.dcapostopv()) > cascadeSelections.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > cascadeSelections.dcaBaryonToPV; // TPC PID and DCA daughter to prim.vtx and comopeting casc.rej and life time if (masterConfigurations.doCorrelationXiMinus) { // DCA daughter to prim.vtx - if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > systCuts.dcaMesonToPV) + if (isGoodDCANegCasc) SETBIT(bitMap, 0); // comopeting casc.rej - if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > systCuts.rejcomp) + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) SETBIT(bitMap, 4); - if (ctauXi < systCuts.proplifetime) + if (ctauXi < cascadeSelections.proplifetime) SETBIT(bitMap, 8); // y cut - if (std::abs(casc.yXi()) < systCuts.rapCut) + if (std::abs(casc.yXi()) < cascadeSelections.rapCut) SETBIT(bitMap, 12); } if (masterConfigurations.doCorrelationXiPlus) { // DCA daughter to prim.vtx - if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > systCuts.dcaBaryonToPV) + if (isGoodDCAPosCasc) SETBIT(bitMap, 1); // comopeting casc.rej - if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > systCuts.rejcomp) + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) SETBIT(bitMap, 5); // life time - if (ctauXi < systCuts.proplifetime) + if (ctauXi < cascadeSelections.proplifetime) SETBIT(bitMap, 9); // y cut - if (std::abs(casc.yXi()) > systCuts.rapCut) + if (std::abs(casc.yXi()) > cascadeSelections.rapCut) SETBIT(bitMap, 13); } if (masterConfigurations.doCorrelationOmegaMinus) { // DCA daughter to prim.vtx - if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaBaryonToPV && - std::abs(casc.dcanegtopv()) > systCuts.dcaMesonToPV) + if (isGoodDCANegCasc) SETBIT(bitMap, 2); // comopeting casc.rej - if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > systCuts.rejcomp) + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) SETBIT(bitMap, 6); // life time - if (ctauOmega < systCuts.proplifetime) + if (ctauOmega < cascadeSelections.proplifetime) SETBIT(bitMap, 10); // y cut - if (std::abs(casc.yOmega()) < systCuts.rapCut) + if (std::abs(casc.yOmega()) < cascadeSelections.rapCut) SETBIT(bitMap, 14); } if (masterConfigurations.doCorrelationOmegaPlus) { // DCA daughter to prim.vtx - if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaMesonToPV && - std::abs(casc.dcanegtopv()) > systCuts.dcaBaryonToPV) + if (isGoodDCAPosCasc) SETBIT(bitMap, 3); // comopeting casc.rej - if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > systCuts.rejcomp) + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) SETBIT(bitMap, 7); // life time - if (ctauOmega < systCuts.proplifetime) + if (ctauOmega < cascadeSelections.proplifetime) SETBIT(bitMap, 11); // y cut - if (std::abs(casc.yOmega()) > systCuts.rapCut) + if (std::abs(casc.yOmega()) > cascadeSelections.rapCut) SETBIT(bitMap, 15); } return bitMap; @@ -499,20 +541,20 @@ struct HStrangeCorrelation { template bool isValidTrigger(TTrack track, bool isLeading) { - if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsTrigger) { + if (track.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsTrigger) { return false; // crossed rows } - if (!track.hasITS() && systCuts.triggerRequireITS) { + if (!track.hasITS() && trackSelection.triggerRequireITS) { return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) } - if (track.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) { + if (track.tpcNClsShared() > trackSelection.triggerMaxTPCSharedClusters) { return false; // skip, has shared clusters } - if (!(TESTBIT(track.itsClusterMap(), 0)) && systCuts.triggerRequireL0) { + if (!(TESTBIT(track.itsClusterMap(), 0)) && trackSelection.triggerRequireL0) { return false; // skip, doesn't have cluster in ITS L0 } // systematic variations: trigger DCAxy - if (std::abs(track.dcaXY()) > systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(track.signed1Pt())) { + if (std::abs(track.dcaXY()) > trackSelection.dcaXYconstant + trackSelection.dcaXYpTdep * std::abs(track.signed1Pt())) { return false; } if (track.pt() > axisRanges[3][1] || track.pt() < axisRanges[3][0]) { @@ -532,20 +574,20 @@ struct HStrangeCorrelation { template bool isValidAssocHadron(TTrack track) { - if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) { + if (track.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { return false; // crossed rows } - if (!track.hasITS() && systCuts.assocRequireITS) { + if (!track.hasITS() && trackSelection.assocRequireITS) { return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) } - if (track.tpcNClsShared() > systCuts.assocMaxTPCSharedClusters) { + if (track.tpcNClsShared() > trackSelection.assocMaxTPCSharedClusters) { return false; // skip, has shared clusters } - if (!(TESTBIT(track.itsClusterMap(), 0)) && systCuts.assocRequireL0) { + if (!(TESTBIT(track.itsClusterMap(), 0)) && trackSelection.assocRequireL0) { return false; // skip, doesn't have cluster in ITS L0 } // systematic variations: trigger DCAxy - if (std::abs(track.dcaXY()) > systCuts.dcaXYconstantAssoc + systCuts.dcaXYpTdepAssoc * std::abs(track.signed1Pt())) { + if (std::abs(track.dcaXY()) > trackSelection.dcaXYconstantAssoc + trackSelection.dcaXYpTdepAssoc * std::abs(track.signed1Pt())) { return false; } if (track.pt() > axisRanges[2][1] || track.pt() < axisRanges[2][0]) { @@ -558,15 +600,15 @@ struct HStrangeCorrelation { bool v0SelectedPbPb(TV0 v0) { // v0radius - if (v0.v0radius() < systCuts.v0RadiusMin) + if (v0.v0radius() < v0Selection.v0RadiusMin) return false; - if (v0.v0radius() > systCuts.v0RadiusMax) + if (v0.v0radius() > v0Selection.v0RadiusMax) return false; // v0cosPA - if (v0.v0cosPA() < systCuts.v0cospa) + if (v0.v0cosPA() < v0Selection.v0cospa) return false; // dcaV0daughters - if (v0.dcaV0daughters() > systCuts.dcaV0dau) + if (v0.dcaV0daughters() > v0Selection.dcaV0dau) return false; return true; } @@ -576,39 +618,39 @@ struct HStrangeCorrelation { bool cascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) { // bachBaryonCosPA - if (casc.bachBaryonCosPA() < systCuts.bachBaryonCosPA) + if (casc.bachBaryonCosPA() < cascadeSelections.bachBaryonCosPA) return false; // bachBaryonDCAxyToPV - if (std::abs(casc.bachBaryonDCAxyToPV()) > systCuts.bachBaryonDCAxyToPV) + if (std::abs(casc.bachBaryonDCAxyToPV()) > cascadeSelections.bachBaryonDCAxyToPV) return false; // casccosPA - if (casc.casccosPA(pvx, pvy, pvz) < systCuts.cascCospa) + if (casc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa) return false; // dcacascdaughters - float ptDepCut = systCuts.dcaCacsDauPar0; - if (casc.pt() > systCuts.lowPtForCascDaugPtDep && casc.pt() < systCuts.highPtForCascDaugPtDep) - ptDepCut = systCuts.dcaCacsDauPar1; - else if (casc.pt() > systCuts.highPtForCascDaugPtDep) - ptDepCut = systCuts.dcaCacsDauPar2; + float ptDepCut = cascadeSelections.dcaCacsDauPar0; + if (casc.pt() > cascadeSelections.lowPtForCascDaugPtDep && casc.pt() < cascadeSelections.highPtForCascDaugPtDep) + ptDepCut = cascadeSelections.dcaCacsDauPar1; + else if (casc.pt() > cascadeSelections.highPtForCascDaugPtDep) + ptDepCut = cascadeSelections.dcaCacsDauPar2; if (casc.dcacascdaughters() > ptDepCut) return false; // dcaV0daughters - if (casc.dcaV0daughters() > systCuts.dcaV0dau) + if (casc.dcaV0daughters() > cascadeSelections.cascdcaV0dau) return false; // dcav0topv - if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < systCuts.cascdcaV0ToPV) + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV) return false; // cascradius - if (casc.cascradius() < systCuts.cascRadius) + if (casc.cascradius() < cascadeSelections.cascRadius) return false; // v0radius - if (casc.v0radius() < systCuts.cascv0RadiusMin) + if (casc.v0radius() < cascadeSelections.cascv0RadiusMin) return false; // v0cosPA - if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < systCuts.cascv0cospa) + if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascadeSelections.cascv0cospa) return false; // lambdaMassWin - if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.lambdaMassWin) + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow) return false; return true; } @@ -650,8 +692,22 @@ struct HStrangeCorrelation { hist->SetBinContent(bin, currentContent); hist->SetBinError2(bin, currentError2); } - void fillCorrelationsV0(aod::TriggerTracks const& triggers, aod::AssocV0s const& assocs, bool mixing, float pvx, float pvy, float pvz, float mult, double bField) + void fillCorrelationsV0(aod::TriggerTracks const& triggers, aod::AssocV0s const& assocs, bool mixing, bool mixingInBf, float pvx, float pvy, float pvz, float mult, double bField) { + ValidCollision currentCollision; + int binMult = 0; + int nBinsMult = 0; + int nBinsVtxZ = 0; + int binVtxZ = 0; + currentCollision.pvz = pvz; + currentCollision.mult = mult; + if (mixingInBf) { + nBinsMult = histos.get(HIST("axes/hMultAxis"))->GetNbinsX(); + binMult = histos.get(HIST("axes/hMultAxis"))->GetXaxis()->FindBin(mult) - 1; + nBinsVtxZ = histos.get(HIST("axes/hVertexZAxis"))->GetNbinsX(); + binVtxZ = histos.get(HIST("axes/hVertexZAxis"))->GetXaxis()->FindBin(pvz) - 1; + } + bool firstLoop = false; for (auto const& triggerTrack : triggers) { if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) continue; @@ -692,13 +748,19 @@ struct HStrangeCorrelation { double triggSign = trigg.sign(); double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + if (mixingInBf) { + currentCollision.addValidParticle(trigg.eta(), trigg.phi(), trigg.pt(), -1, efficiencyTrigg, efficiencyTriggError, -1); + if (firstLoop) + continue; + } for (auto const& assocCandidate : assocs) { + firstLoop = true; auto assoc = assocCandidate.v0Core_as(); //---] syst cuts [--- - if ((masterConfigurations.doPPAnalysis && (assoc.v0radius() < systCuts.v0RadiusMin || assoc.v0radius() > systCuts.v0RadiusMax || - std::abs(assoc.dcapostopv()) < systCuts.dcapostopv || std::abs(assoc.dcanegtopv()) < systCuts.dcanegtopv || - assoc.v0cosPA() < systCuts.v0cospa || assoc.dcaV0daughters() > systCuts.dcaV0dau))) + if ((masterConfigurations.doPPAnalysis && (assoc.v0radius() < v0Selection.v0RadiusMin || assoc.v0radius() > v0Selection.v0RadiusMax || + std::abs(assoc.dcapostopv()) < v0Selection.dcapostopv || std::abs(assoc.dcanegtopv()) < v0Selection.dcanegtopv || + assoc.v0cosPA() < v0Selection.v0cospa || assoc.dcaV0daughters() > v0Selection.dcaV0dau))) continue; if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(assoc)) @@ -709,19 +771,25 @@ struct HStrangeCorrelation { //---] removing autocorrelations [--- auto postrack = assoc.posTrack_as(); auto negtrack = assoc.negTrack_as(); - if (doAutocorrelationRejection) { - if (trigg.globalIndex() == postrack.globalIndex()) { - histos.fill(HIST("hNumberOfRejectedPairsV0"), 0.5); - continue; - } - if (trigg.globalIndex() == negtrack.globalIndex()) { - histos.fill(HIST("hNumberOfRejectedPairsV0"), 0.5); - continue; + if (!mixingInBf) { + if (doAutocorrelationRejection) { + if (trigg.globalIndex() == postrack.globalIndex()) { + histos.fill(HIST("hNumberOfRejectedPairsV0"), 0.5); + continue; + } + if (trigg.globalIndex() == negtrack.globalIndex()) { + histos.fill(HIST("hNumberOfRejectedPairsV0"), 0.5); + continue; + } } } //---] track quality check [--- - if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + continue; + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + continue; + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) continue; float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); @@ -755,7 +823,7 @@ struct HStrangeCorrelation { } float etaWeight = 1; - if (systCuts.doOnTheFlyFlattening) { + if (checks.doOnTheFlyFlattening) { float preWeight = 1 - std::abs(deltaeta) / 1.6; etaWeight = preWeight != 0 ? 1.0f / preWeight : 1.0f; } @@ -767,7 +835,7 @@ struct HStrangeCorrelation { double ptProton = postrack.pt(); double ptPion = negtrack.pt(); double signProton = postrack.sign(); - if (assocCandidate.compatible(2, systCuts.dEdxCompatibility)) { + if (assocCandidate.compatible(2, trackSelection.dEdxCompatibility)) { phiProton = negtrack.phi(); etaProton = negtrack.eta(); ptProton = negtrack.pt(); @@ -802,7 +870,7 @@ struct HStrangeCorrelation { } double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; if (TESTBIT(doCorrelation, Index) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (masterConfigurations.doPPAnalysis || (TESTBIT(selMap, Index) && TESTBIT(selMap, Index + 3)))) { - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -820,13 +888,13 @@ struct HStrangeCorrelation { } } } - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); - if (std::abs(deltaphi) < systCuts.towardDeltaEtaRange && doITSClustersQA) { + if (std::abs(deltaphi) < checks.towardDeltaEtaRange && doITSClustersQA) { histos.fill(HIST("hITSClusters") + HIST(V0names[Index]) + HIST("NegativeDaughterToward"), ptassoc, negtrack.itsNCls(), assoc.v0radius()); histos.fill(HIST("hITSClusters") + HIST(V0names[Index]) + HIST("PositiveDaughterToward"), ptassoc, postrack.itsNCls(), assoc.v0radius()); } - if (std::abs(deltaphi) > systCuts.transwerseDeltaEtaRangeMin && std::abs(deltaphi) < systCuts.transwerseDeltaEtaRangeMax && doITSClustersQA) { + if (std::abs(deltaphi) > checks.transwerseDeltaEtaRangeMin && std::abs(deltaphi) < checks.transwerseDeltaEtaRangeMax && doITSClustersQA) { histos.fill(HIST("hITSClusters") + HIST(V0names[Index]) + HIST("NegativeDaughterTransverse"), ptassoc, negtrack.itsNCls(), assoc.v0radius()); histos.fill(HIST("hITSClusters") + HIST(V0names[Index]) + HIST("PositiveDaughterTransverse"), ptassoc, postrack.itsNCls(), assoc.v0radius()); } @@ -846,7 +914,7 @@ struct HStrangeCorrelation { } } } - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/RightBg/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -864,20 +932,100 @@ struct HStrangeCorrelation { } } } - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) - fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) - fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) - fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + if (mixingInBf) { + currentCollision.addValidParticle(assoc.eta(), assoc.phi(), assoc.pt(), 0, efficiency, efficiencyError, Index); + } else { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + } + } + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + if (mixingInBf) { + currentCollision.addValidParticle(assoc.eta(), assoc.phi(), assoc.pt(), 1, efficiencyTrigg, efficiencyError, Index); + } else { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + } + } + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { + if (mixingInBf) { + currentCollision.addValidParticle(assoc.eta(), assoc.phi(), assoc.pt(), 2, efficiencyTrigg, efficiencyError, Index); + } else { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + } + } } }); } } + if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) + return; + int binnumb = binMult * nBinsVtxZ + binVtxZ; + int hastirgorassoc = masterConfigurations.collisionHasTriggOrAssoc; + if ((hastirgorassoc == 1 && currentCollision.trigParticles.empty()) || + (hastirgorassoc == 2 && currentCollision.assocParticles.empty()) || + (hastirgorassoc == 3 && currentCollision.trigParticles.empty() && currentCollision.assocParticles.empty()) || + (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) + return; + for (const auto& collision : validCollisions[binnumb]) { + BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; + // When 'collisionHasTriggOrAssoc' = 0: + // binContent(hMECollisionBins) = Σ(RunNumbers)[binContent(the same bin of hSECollisionBins) * masterConfigurations.mixingParameter - Σ(k=0 to min(masterConfigurations.mixingParameter,binContent)) k] + // When 'collisionHasTriggOrAssoc' = 3 + // More collision loss at higher peripheral centrality (fewer target particles); higher bincontent of HIST("mixedEvent/Signal/") + HIST(Cascadenames[Index]) + // due to avoiding vector occupancy by collisions with no trigger&associated particles + histos.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision.pvz, collision.mult})); + for (const auto& trigger : collision.trigParticles) { + for (const auto& assoc : currentCollision.assocParticles) { + float deltaeta = trigger.eta - assoc.eta; + float deltaphi = computeDeltaPhi(trigger.phi, assoc.phi); + float efficiencyTrigg = trigger.efficiency; + float efficiencyAssoc = assoc.efficiency; + float efficiencyTriggError = trigger.efficiencyError; + float efficiencyAssocError = assoc.efficiencyError; + float totalEffUncert = 0.0; + float ptassoc = assoc.pt; + float pttrigger = trigger.pt; + if (efficiencyFlags.applyEfficiencyPropagation) { + totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyAssocError, 2) + std::pow(efficiencyTriggError * efficiencyAssoc, 2)); + } + double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + static_for<0, 2>([&](auto i) { + constexpr int Index = i.value; + if (Index == assoc.type && assoc.region == 0) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(V0names[Index])), binFillThn, 1, efficiencyTrigg * efficiencyAssoc, totalEffUncert, 1., 0.); + } + if (Index == assoc.type && assoc.region == 1) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index])), binFillThn, 1, efficiencyTrigg * efficiencyAssoc, totalEffUncert, 1., 0.); + } + if (Index == assoc.type && assoc.region == 2) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(V0names[Index])), binFillThn, 1, efficiencyTrigg * efficiencyAssoc, totalEffUncert, 1., 0.); + } + }); + } + } + } + if (validCollisions[binnumb].size() >= static_cast(masterConfigurations.mixingParameter)) { + validCollisions[binnumb].erase(validCollisions[binnumb].begin()); + } + validCollisions[binnumb].push_back(currentCollision); } - void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, float pvx, float pvy, float pvz, float mult, double bField) + void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, bool mixingInBf, float pvx, float pvy, float pvz, float mult, double bField) { + ValidCollision currentCollision; + int nBinsMult = 0; + int binMult = 0; + int nBinsVtxZ = 0; + int binVtxZ = 0; + currentCollision.pvz = pvz; + currentCollision.mult = mult; + if (mixingInBf) { + nBinsMult = histos.get(HIST("axes/hMultAxis"))->GetNbinsX(); + binMult = histos.get(HIST("axes/hMultAxis"))->GetXaxis()->FindBin(mult) - 1; + nBinsVtxZ = histos.get(HIST("axes/hVertexZAxis"))->GetNbinsX(); + binVtxZ = histos.get(HIST("axes/hVertexZAxis"))->GetXaxis()->FindBin(pvz) - 1; + } + bool firstLoop = false; for (auto const& triggerTrack : triggers) { if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) continue; @@ -929,20 +1077,26 @@ struct HStrangeCorrelation { double triggSign = trigg.sign(); double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + if (mixingInBf) { + currentCollision.addValidParticle(trigg.eta(), trigg.phi(), trigg.pt(), -1, efficiencyTrigg, efficiencyTriggError, -1); + if (firstLoop) + continue; + } for (auto const& assocCandidate : assocs) { + firstLoop = true; auto assoc = assocCandidate.cascData(); //---] syst cuts [--- - if (masterConfigurations.doPPAnalysis && (std::abs(assoc.dcapostopv()) < systCuts.dcapostopv || - std::abs(assoc.dcanegtopv()) < systCuts.dcanegtopv || - std::abs(assoc.dcabachtopv()) < systCuts.cascDcabachtopv || - assoc.dcaV0daughters() > systCuts.dcaV0dau || - assoc.dcacascdaughters() > systCuts.cascDcacascdau || - assoc.v0cosPA(pvx, pvy, pvz) < systCuts.v0cospa || - assoc.casccosPA(pvx, pvy, pvz) < systCuts.cascCospa || - assoc.cascradius() < systCuts.cascRadius || - std::abs(assoc.dcav0topv(pvx, pvy, pvz)) < systCuts.cascMindcav0topv || - std::abs(assoc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow)) + if (masterConfigurations.doPPAnalysis && (std::abs(assoc.dcapostopv()) < v0Selection.dcapostopv || + std::abs(assoc.dcanegtopv()) < v0Selection.dcanegtopv || + std::abs(assoc.dcabachtopv()) < cascadeSelections.dcaBachToPV || + assoc.dcaV0daughters() > cascadeSelections.cascdcaV0dau || + assoc.dcacascdaughters() > cascadeSelections.dcaCascDaughters || + assoc.v0cosPA(pvx, pvy, pvz) < cascadeSelections.cascv0cospa || + assoc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa || + assoc.cascradius() < cascadeSelections.cascRadius || + std::abs(assoc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV || + std::abs(assoc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) continue; if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(assoc, pvx, pvy, pvz)) continue; @@ -951,18 +1105,20 @@ struct HStrangeCorrelation { auto postrack = assoc.posTrack_as(); auto negtrack = assoc.negTrack_as(); auto bachtrack = assoc.bachelor_as(); - if (doAutocorrelationRejection) { - if (trigg.globalIndex() == postrack.globalIndex()) { - histos.fill(HIST("hNumberOfRejectedPairsCascades"), 0.5); - continue; - } - if (trigg.globalIndex() == negtrack.globalIndex()) { - histos.fill(HIST("hNumberOfRejectedPairsCascades"), 0.5); - continue; - } - if (trigg.globalIndex() == bachtrack.globalIndex()) { - histos.fill(HIST("hNumberOfRejectedPairsCascades"), 0.5); - continue; + if (!mixingInBf) { + if (doAutocorrelationRejection) { + if (trigg.globalIndex() == postrack.globalIndex()) { + histos.fill(HIST("hNumberOfRejectedPairsCascades"), 0.5); + continue; + } + if (trigg.globalIndex() == negtrack.globalIndex()) { + histos.fill(HIST("hNumberOfRejectedPairsCascades"), 0.5); + continue; + } + if (trigg.globalIndex() == bachtrack.globalIndex()) { + histos.fill(HIST("hNumberOfRejectedPairsCascades"), 0.5); + continue; + } } } double phiProton = postrack.phi(); @@ -977,7 +1133,11 @@ struct HStrangeCorrelation { } double assocForDeltaPhiStar[] = {phiProton, ptProton, signProton}; //---] track quality check [--- - if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + continue; + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + continue; + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || bachtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) continue; float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); @@ -1014,7 +1174,7 @@ struct HStrangeCorrelation { hEfficiencyUncertaintyCascade[3] = hEfficiencyUncertaintyOmegaPlus; float etaWeight = 1; - if (systCuts.doOnTheFlyFlattening) { + if (checks.doOnTheFlyFlattening) { float preWeight = 1 - std::abs(deltaeta) / 1.6; etaWeight = preWeight != 0 ? 1.0f / preWeight : 1.0f; } @@ -1033,7 +1193,7 @@ struct HStrangeCorrelation { } else { efficiency = hEfficiencyCascade[Index]->Interpolate(ptassoc, assoc.eta()); if (efficiencyFlags.applyEfficiencyPropagation) - efficiencyError = hEfficiencyUncertaintyCascade[Index]->Interpolate(ptassoc, assoc.eta(), assoc.phi()); + efficiencyError = hEfficiencyUncertaintyCascade[Index]->Interpolate(ptassoc, assoc.eta()); } } if (efficiency == 0) { // check for zero efficiency, do not apply if the case @@ -1045,7 +1205,7 @@ struct HStrangeCorrelation { } double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; if (TESTBIT(doCorrelation, Index + 3) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (masterConfigurations.doPPAnalysis || (TESTBIT(cascselMap, Index) && TESTBIT(cascselMap, Index + 4) && TESTBIT(cascselMap, Index + 8) && TESTBIT(cascselMap, Index + 12)))) { - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -1055,7 +1215,7 @@ struct HStrangeCorrelation { histos.fill(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); } } - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -1065,7 +1225,7 @@ struct HStrangeCorrelation { histos.fill(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); } } - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -1075,16 +1235,77 @@ struct HStrangeCorrelation { histos.fill(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); } } - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) - fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) - fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); - if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) - fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + if (mixingInBf) { + currentCollision.addValidParticle(assoc.eta(), assoc.phi(), assoc.pt(), 0, efficiency, efficiencyError, Index); + } else { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + } + } + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + if (mixingInBf) { + currentCollision.addValidParticle(assoc.eta(), assoc.phi(), assoc.pt(), 1, efficiency, efficiencyError, Index); + } else { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + } + } + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { + if (mixingInBf) { + currentCollision.addValidParticle(assoc.eta(), assoc.phi(), assoc.pt(), 2, efficiency, efficiencyError, Index); + } else { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + } + } } }); } } + if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) + return; + int binnumb = binMult * nBinsVtxZ + binVtxZ; + int hastirgorassoc = masterConfigurations.collisionHasTriggOrAssoc; + if ((hastirgorassoc == 1 && currentCollision.trigParticles.empty()) || + (hastirgorassoc == 2 && currentCollision.assocParticles.empty()) || + (hastirgorassoc == 3 && currentCollision.trigParticles.empty() && currentCollision.assocParticles.empty()) || + (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) + return; + for (const auto& collision : validCollisions[binnumb]) { + BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; + histos.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision.pvz, collision.mult})); + for (const auto& trigger : collision.trigParticles) { + for (const auto& assoc : currentCollision.assocParticles) { + float deltaeta = trigger.eta - assoc.eta; + float deltaphi = computeDeltaPhi(trigger.phi, assoc.phi); + float efficiencyTrigg = trigger.efficiency; + float efficiencyAssoc = assoc.efficiency; + float efficiencyTriggError = trigger.efficiencyError; + float efficiencyAssocError = assoc.efficiencyError; + float totalEffUncert = 0.0; + float ptassoc = assoc.pt; + float pttrigger = trigger.pt; + if (efficiencyFlags.applyEfficiencyPropagation) { + totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyAssocError, 2) + std::pow(efficiencyTriggError * efficiencyAssoc, 2)); + } + double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + static_for<0, 3>([&](auto i) { + constexpr int Index = i.value; + if (Index == assoc.type && assoc.region == 0) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiencyTrigg * efficiencyAssoc, totalEffUncert, 1., 0.); + } + if (Index == assoc.type && assoc.region == 1) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiencyTrigg * efficiencyAssoc, totalEffUncert, 1., 0.); + } + if (Index == assoc.type && assoc.region == 2) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(Cascadenames[Index])), binFillThn, 1, efficiencyTrigg * efficiencyAssoc, totalEffUncert, 1., 0.); + } + }); + } + } + } + if (validCollisions[binnumb].size() >= static_cast(masterConfigurations.mixingParameter)) { + validCollisions[binnumb].erase(validCollisions[binnumb].begin()); + } + validCollisions[binnumb].push_back(currentCollision); } template void fillCorrelationsHadron(TTriggers const& triggers, THadrons const& assocs, bool mixing, float pvz, float mult, double bField) @@ -1165,7 +1386,7 @@ struct HStrangeCorrelation { double assocForDeltaPhiStar[] = {assoc.phi(), assoc.pt(), assocSign}; float etaWeight = 1.; - if (systCuts.doOnTheFlyFlattening) { + if (checks.doOnTheFlyFlattening) { float preWeight = 1 - std::abs(deltaeta) / 1.6; etaWeight = preWeight != 0 ? 1.0f / preWeight : 1.0f; } @@ -1451,6 +1672,13 @@ struct HStrangeCorrelation { const AxisSpec axisPtTriggerNDim{edgesPtTrigger, "#it{p}_{T}^{trigger} (GeV/c)"}; const AxisSpec axisVtxZNDim{edgesVtxZ, "vertex Z (cm)"}; const AxisSpec axisMultNDim{edgesMult, "mult percentile"}; + + if (doprocessMixedEventHV0sInBuffer || doprocessMixedEventHCascadesInBuffer) { + validCollisions.resize(histos.get(HIST("axes/hMultAxis"))->GetNbinsX() * histos.get(HIST("axes/hVertexZAxis"))->GetNbinsX()); + for (auto& inner_vec : validCollisions) { + inner_vec.reserve(masterConfigurations.mixingParameter); + } + } if (!masterConfigurations.doPPAnalysis) { // event selections in Pb-Pb histos.add("hEventSelection", "hEventSelection", kTH1F, {{10, 0, 10}}); @@ -1559,7 +1787,7 @@ struct HStrangeCorrelation { LOGF(info, "Init THnFs done"); // mixed-event correlation functions - if ((doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions || doprocessMixedEventHHadrons) && masterConfigurations.doFullCorrelationStudy) { + if ((doprocessMixedEventHV0sInBuffer || doprocessMixedEventHCascadesInBuffer || doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions || doprocessMixedEventHHadrons) && masterConfigurations.doFullCorrelationStudy) { histos.addClone("sameEvent/", "mixedEvent/"); } if (doprocessSameEventHHadrons && masterConfigurations.doFullCorrelationStudy) @@ -1937,13 +2165,16 @@ struct HStrangeCorrelation { //---] track quality check [--- auto postrack = v0Data.posTrack_as(); auto negtrack = v0Data.negTrack_as(); - if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + continue; + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + continue; + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) continue; - //---] syst cuts [--- - if (masterConfigurations.doPPAnalysis && (v0Data.v0radius() < systCuts.v0RadiusMin || v0Data.v0radius() > systCuts.v0RadiusMax || - std::abs(v0Data.dcapostopv()) < systCuts.dcapostopv || std::abs(v0Data.dcanegtopv()) < systCuts.dcanegtopv || - v0Data.v0cosPA() < systCuts.v0cospa || v0Data.dcaV0daughters() > systCuts.dcaV0dau)) + if (masterConfigurations.doPPAnalysis && (v0Data.v0radius() < v0Selection.v0RadiusMin || v0Data.v0radius() > v0Selection.v0RadiusMax || + std::abs(v0Data.dcapostopv()) < v0Selection.dcapostopv || std::abs(v0Data.dcanegtopv()) < v0Selection.dcanegtopv || + v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau)) continue; if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(v0Data)) continue; @@ -1966,7 +2197,7 @@ struct HStrangeCorrelation { efficiency = 1; } float weight = efficiencyFlags.applyEfficiencyCorrection ? 1. / efficiency : 1.0f; - if (v0.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || v0.mcTrue(Index)) && (!doAssocPhysicalPrimary || v0.mcPhysicalPrimary()) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0)) { + if (v0.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || v0.mcTrue(Index)) && (!doAssocPhysicalPrimary || v0.mcPhysicalPrimary()) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0)) { if ((TESTBIT(doCorrelation, Index)) && (masterConfigurations.doPPAnalysis || (TESTBIT(selMap, Index) && TESTBIT(selMap, Index + 3)))) { histos.fill(HIST("h3d") + HIST(V0names[Index]) + HIST("Spectrum"), v0Data.pt(), cent, v0.invMassNSigma(Index), weight); if (std::abs(v0Data.rapidity(Index)) < ySel) { @@ -2012,7 +2243,7 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - V0 correlations if (masterConfigurations.doFullCorrelationStudy) - fillCorrelationsV0(triggerTracks, associatedV0s, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + fillCorrelationsV0(triggerTracks, associatedV0s, false, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); } void processSameEventHCascades(soa::Join::iterator const& collision, @@ -2071,16 +2302,16 @@ struct HStrangeCorrelation { auto cascData = casc.cascData(); //---] syst cuts [--- - if (masterConfigurations.doPPAnalysis && (std::abs(cascData.dcapostopv()) < systCuts.dcapostopv || - std::abs(cascData.dcanegtopv()) < systCuts.dcanegtopv || - std::abs(cascData.dcabachtopv()) < systCuts.cascDcabachtopv || - cascData.dcaV0daughters() > systCuts.dcaV0dau || - cascData.dcacascdaughters() > systCuts.cascDcacascdau || - cascData.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.v0cospa || - cascData.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.cascCospa || - cascData.cascradius() < systCuts.cascRadius || - std::abs(cascData.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < systCuts.cascMindcav0topv || - std::abs(cascData.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow)) + if (masterConfigurations.doPPAnalysis && (std::abs(cascData.dcapostopv()) < v0Selection.dcapostopv || + std::abs(cascData.dcanegtopv()) < v0Selection.dcanegtopv || + std::abs(cascData.dcabachtopv()) < cascadeSelections.dcaBachToPV || + cascData.dcaV0daughters() > cascadeSelections.cascdcaV0dau || + cascData.dcacascdaughters() > cascadeSelections.dcaCascDaughters || + cascData.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadeSelections.cascv0cospa || + cascData.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadeSelections.cascCospa || + cascData.cascradius() < cascadeSelections.cascRadius || + std::abs(cascData.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascadeSelections.cascdcaV0ToPV || + std::abs(cascData.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) continue; if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(cascData, collision.posX(), collision.posY(), collision.posZ())) continue; @@ -2089,12 +2320,16 @@ struct HStrangeCorrelation { auto postrack = cascData.posTrack_as(); auto negtrack = cascData.negTrack_as(); auto bachtrack = cascData.bachelor_as(); - if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + continue; + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + continue; + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) continue; static_for<0, 3>([&](auto i) { constexpr int Index = i.value; - if ((Index == IndexOmegaMinus || Index == IndexOmegaPlus) && casc.compatible(Index, systCuts.dEdxCompatibility) && std::abs(casc.invMassNSigma(Index - 2)) < massWindowConfigurations.nSigmaNearXiMassCenter) { + if ((Index == IndexOmegaMinus || Index == IndexOmegaPlus) && casc.compatible(Index, trackSelection.dEdxCompatibility) && std::abs(casc.invMassNSigma(Index - 2)) < massWindowConfigurations.nSigmaNearXiMassCenter) { return; } float efficiency = 1.0f; @@ -2110,7 +2345,7 @@ struct HStrangeCorrelation { efficiency = 1; } float weight = efficiencyFlags.applyEfficiencyCorrection ? 1. / efficiency : 1.0f; - if (casc.compatible(Index, systCuts.dEdxCompatibility) && (!masterConfigurations.doMCassociation || casc.mcTrue(Index)) && (!doAssocPhysicalPrimary || casc.mcPhysicalPrimary()) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0)) { + if (casc.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || casc.mcTrue(Index)) && (!doAssocPhysicalPrimary || casc.mcPhysicalPrimary()) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0)) { if (TESTBIT(doCorrelation, Index + 3) && (masterConfigurations.doPPAnalysis || (TESTBIT(cascselMap, Index) && TESTBIT(cascselMap, Index + 4) && TESTBIT(cascselMap, Index + 8) && TESTBIT(cascselMap, Index + 12)))) { histos.fill(HIST("h3d") + HIST(Cascadenames[Index]) + HIST("Spectrum"), cascData.pt(), cent, casc.invMassNSigma(Index), weight); if (std::abs(cascData.rapidity(Index)) < ySel) { @@ -2158,7 +2393,7 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - cascade correlations if (masterConfigurations.doFullCorrelationStudy) - fillCorrelationsCascade(triggerTracks, associatedCascades, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + fillCorrelationsCascade(triggerTracks, associatedCascades, false, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); } void processSameEventHPions(soa::Join::iterator const& collision, soa::Join const& associatedPions, soa::Join const& triggerTracks, @@ -2298,7 +2533,7 @@ struct HStrangeCorrelation { } // Perform basic event selection on both collisions - if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, true) || (!isCollisionSelectedPbPb(collision2, true))))) { + if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, false) || (!isCollisionSelectedPbPb(collision2, false))))) { continue; } if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) @@ -2321,7 +2556,7 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - V0 correlations if (masterConfigurations.doFullCorrelationStudy) - fillCorrelationsV0(slicedTriggerTracks, slicedAssocV0s, true, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + fillCorrelationsV0(slicedTriggerTracks, slicedAssocV0s, true, false, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); } }, colBinning); @@ -2354,7 +2589,7 @@ struct HStrangeCorrelation { } // Perform basic event selection on both collisions - if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, true) || (!isCollisionSelectedPbPb(collision2, true))))) { + if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, false) || (!isCollisionSelectedPbPb(collision2, false))))) { continue; } if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) @@ -2376,7 +2611,7 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - cascade correlations if (masterConfigurations.doFullCorrelationStudy) - fillCorrelationsCascade(slicedTriggerTracks, slicedAssocCascades, true, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + fillCorrelationsCascade(slicedTriggerTracks, slicedAssocCascades, true, false, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); } }, colBinning); @@ -2472,6 +2707,7 @@ struct HStrangeCorrelation { float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; + bool isCollisionSelect = false; uint32_t bestCollisionTriggerPresenceMap = 0; for (auto const& collision : collisions) { @@ -2479,9 +2715,13 @@ struct HStrangeCorrelation { biggestNContribs = collision.numContrib(); bestCollisionFT0Mpercentile = collision.centFT0M(); bestCollisionFT0Cpercentile = collision.centFT0C(); - bestCollisionSel8 = collision.sel8(); - bestCollisionVtxZ = collision.posZ(); - bestCollisionINELgtZERO = collision.isInelGt0(); + if (masterConfigurations.applyNewMCSelection) { + isCollisionSelect = ((masterConfigurations.doPPAnalysis && isCollisionSelected(collision)) || (!masterConfigurations.doPPAnalysis && isCollisionSelectedPbPb(collision, false))); + } else { + bestCollisionSel8 = collision.sel8(); + bestCollisionVtxZ = collision.posZ(); + bestCollisionINELgtZERO = collision.isInelGt0(); + } if (triggerPresenceMap.size() > 0) bestCollisionTriggerPresenceMap = triggerPresenceMap[collision.globalIndex()]; } @@ -2511,12 +2751,17 @@ struct HStrangeCorrelation { if (triggerPresenceMap.size() > 0 && !TESTBIT(bestCollisionTriggerPresenceMap, triggerBinToSelect)) { return; } - if (!bestCollisionSel8) - return; - if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) - return; - if (!bestCollisionINELgtZERO) - return; + if (masterConfigurations.applyNewMCSelection) { + if (!isCollisionSelect) + return; + } else { + if (!bestCollisionSel8) + return; + if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) + return; + if (!bestCollisionINELgtZERO) + return; + } histos.fill(HIST("hClosureTestEventCounter"), 3.5f); @@ -2830,13 +3075,13 @@ struct HStrangeCorrelation { //---] track quality check [--- auto postrack = v0Data.posTrack_as(); auto negtrack = v0Data.negTrack_as(); - if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) continue; //---] syst cuts [--- - if (v0Data.v0radius() < systCuts.v0RadiusMin || v0Data.v0radius() > systCuts.v0RadiusMax || - std::abs(v0Data.dcapostopv()) < systCuts.dcapostopv || std::abs(v0Data.dcanegtopv()) < systCuts.dcanegtopv || - v0Data.v0cosPA() < systCuts.v0cospa || v0Data.dcaV0daughters() > systCuts.dcaV0dau) + if (v0Data.v0radius() < v0Selection.v0RadiusMin || v0Data.v0radius() > v0Selection.v0RadiusMax || + std::abs(v0Data.dcapostopv()) < v0Selection.dcapostopv || std::abs(v0Data.dcanegtopv()) < v0Selection.dcanegtopv || + v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau) continue; if (v0Data.has_mcParticle()) { @@ -2894,6 +3139,63 @@ struct HStrangeCorrelation { } } } + void processMixedEventHV0sInBuffer(soa::Join::iterator const& collision, + aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, + V0DatasWithoutTrackX const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + + double cent = masterConfigurations.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + auto bc = collision.template bc_as(); + auto bField = getMagneticField(bc.timestamp()); + // ________________________________________________ + if (efficiencyFlags.applyEfficiencyCorrection) { + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { + return; + } + + // Perform basic event selection on both collisions + if (((masterConfigurations.doPPAnalysis && !isCollisionSelected(collision))) || (!masterConfigurations.doPPAnalysis && !isCollisionSelectedPbPb(collision, true))) { + return; + } + if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) + return; + + // ________________________________________________ + if (masterConfigurations.doFullCorrelationStudy) + fillCorrelationsV0(triggerTracks, associatedV0s, true, true, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } + void processMixedEventHCascadesInBuffer(soa::Join::iterator const& collision, + aod::AssocV0s const&, aod::AssocCascades const& associatedCascades, aod::TriggerTracks const& triggerTracks, + V0DatasWithoutTrackX const&, aod::CascDatas const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + double cent = masterConfigurations.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + // ________________________________________________ + auto bc = collision.template bc_as(); + auto bField = getMagneticField(bc.timestamp()); + if (efficiencyFlags.applyEfficiencyCorrection) { + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { + return; + } + // Perform basic event selection on both collisions + if ((masterConfigurations.doPPAnalysis && !isCollisionSelected(collision)) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision, true)))) { + return; + } + if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) + return; + // ________________________________________________ + // Do hadron - cascade correlations + if (masterConfigurations.doFullCorrelationStudy) + fillCorrelationsCascade(triggerTracks, associatedCascades, true, true, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } PROCESS_SWITCH(HStrangeCorrelation, processSelectEventWithTrigger, "Select events with trigger only", true); PROCESS_SWITCH(HStrangeCorrelation, processSameEventHV0s, "Process same events, h-V0s", true); PROCESS_SWITCH(HStrangeCorrelation, processSameEventHCascades, "Process same events, h-Cascades", true); @@ -2904,6 +3206,8 @@ struct HStrangeCorrelation { PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHCascades, "Process mixed events, h-Cascades", true); PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHPions, "Process mixed events, h-Pion", true); PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHHadrons, "Process mixed events, h-h", true); + PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHV0sInBuffer, "Process mixed events in buffer, h-h", true); + PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHCascadesInBuffer, "Process mixed events in buffer, h-h", true); PROCESS_SWITCH(HStrangeCorrelation, processMCGenerated, "Process MC generated", false); PROCESS_SWITCH(HStrangeCorrelation, processClosureTest, "Process Closure Test", false); diff --git a/PWGLF/Tasks/Strangeness/lambdaJetPolarizationIonsDerived.cxx b/PWGLF/Tasks/Strangeness/lambdaJetPolarizationIonsDerived.cxx new file mode 100644 index 00000000000..dcf28b07b7f --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdaJetPolarizationIonsDerived.cxx @@ -0,0 +1,782 @@ +// 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 lambdajetpolarizationionsderived.cxx +/// \brief Lambda and antiLambda polarization analysis task using derived data +/// +/// \author Cicero Domenico Muncinelli , Campinas State University +// +// Jet Polarization Ions task -- Derived data +// ================ +// +// This code loops over custom derived data tables defined on +// lambdaJetPolarizationIons.h (JetsRing, LambdaLikeV0sRing). +// From this derived data, calculates polarization on an EbE +// basis (see TProfiles). +// Signal extraction is done out of the framework, based on +// the AnalysisResults of this code. +// +// +// Comments, questions, complaints, suggestions? +// Please write to: +// cicero.domenico.muncinelli@cern.ch +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Custom data model: +#include "PWGLF/DataModel/lambdaJetPolarizationIons.h" + +#include +#include +#include +#include + +// #include +// #include +// New recommended format: +#include // clang-tidy usually confuses this! Careful! +#include +#include +#include +#include // For perpendicular jet direction QAs + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using ROOT::Math::PtEtaPhiMVector; +using ROOT::Math::XYZVector; +// using namespace o2::aod::lambdajetpol; // Used it explicitly along the code for clarity + +// Declaring constants: +constexpr double protonMass = o2::constants::physics::MassProton; // Assumes particle identification for daughter is perfect +constexpr double lambdaWeakDecayConstant = 0.749; // DPG 2025 update +constexpr double antiLambdaWeakDecayConstant = -0.758; // DPG 2025 update +constexpr double polPrefactorLambda = 3.0 / lambdaWeakDecayConstant; +constexpr double polPrefactorAntiLambda = 3.0 / antiLambdaWeakDecayConstant; + +enum CentEstimator { + kCentFT0C = 0, + kCentFT0M, + kCentFV0A +}; + +// Helper macro to avoid writing the histogram fills 4 times for about 20 histograms: +#define RING_OBSERVABLE_FILL_LIST(X, FOLDER) \ + /* Counters */ \ + X(FOLDER "/QA/hDeltaPhi", deltaPhiJet) \ + X(FOLDER "/QA/hDeltaTheta", deltaThetaJet) \ + X(FOLDER "/QA/hIntegrated", 0.) \ + /* Lambda pT variation -- Youpeng's proposal */ \ + X(FOLDER "/QA/hLambdaPt", v0pt) \ + /* Counters */ \ + X(FOLDER "/QA/h2dDeltaPhiVsLambdaPt", deltaPhiJet, v0pt) \ + X(FOLDER "/QA/h2dDeltaThetaVsLambdaPt", deltaThetaJet, v0pt) \ + /* Additional plots for instant gratification - 1D Profiles */ \ + X(FOLDER "/pRingObservableDeltaPhi", deltaPhiJet, ringObservable) \ + X(FOLDER "/pRingObservableDeltaTheta", deltaThetaJet, ringObservable) \ + X(FOLDER "/pRingObservableIntegrated", 0., ringObservable) \ + X(FOLDER "/pRingObservableLambdaPt", v0pt, ringObservable) \ + /* 2D Profiles */ \ + X(FOLDER "/p2dRingObservableDeltaPhiVsLambdaPt", deltaPhiJet, v0pt, ringObservable) \ + X(FOLDER "/p2dRingObservableDeltaThetaVsLambdaPt", deltaThetaJet, v0pt, ringObservable) \ + X(FOLDER "/p2dRingObservableDeltaPhiVsLeadJetPt", deltaPhiJet, leadingJetPt, ringObservable) \ + X(FOLDER "/p2dRingObservableDeltaThetaVsLeadJetPt", deltaThetaJet, leadingJetPt, ringObservable) \ + /* 1D Mass */ \ + X(FOLDER "/QA/hMass", v0LambdaLikeMass) \ + X(FOLDER "/QA/hRingObservableNumMass", v0LambdaLikeMass, ringObservable) \ + X(FOLDER "/hMassSigExtract", v0LambdaLikeMass) \ + /* Counters */ \ + X(FOLDER "/QA/h2dDeltaPhiVsMass", deltaPhiJet, v0LambdaLikeMass) \ + X(FOLDER "/QA/h2dDeltaThetaVsMass", deltaThetaJet, v0LambdaLikeMass) \ + X(FOLDER "/QA/h3dDeltaPhiVsMassVsLambdaPt", deltaPhiJet, v0LambdaLikeMass, v0pt) \ + X(FOLDER "/QA/h3dDeltaThetaVsMassVsLambdaPt", deltaThetaJet, v0LambdaLikeMass, v0pt) \ + X(FOLDER "/QA/h3dDeltaPhiVsMassVsLeadJetPt", deltaPhiJet, v0LambdaLikeMass, leadingJetPt) \ + X(FOLDER "/QA/h3dDeltaThetaVsMassVsLeadJetPt", deltaThetaJet, v0LambdaLikeMass, leadingJetPt) \ + X(FOLDER "/QA/h3dDeltaPhiVsMassVsCent", deltaPhiJet, v0LambdaLikeMass, centrality) \ + X(FOLDER "/QA/h3dDeltaThetaVsMassVsCent", deltaThetaJet, v0LambdaLikeMass, centrality) \ + /* TProfile of Ring vs Mass */ \ + X(FOLDER "/pRingObservableMass", v0LambdaLikeMass, ringObservable) \ + /* TProfile of Ring vs Mass -- Leading Particle and 2nd-to-leading jet - QA */ \ + X(FOLDER "/pRingObservableLeadPMass", v0LambdaLikeMass, ringObservableLeadP) \ + X(FOLDER "/pRingObservable2ndJetMass", v0LambdaLikeMass, ringObservable2ndJet) \ + /* 2D Profiles: Angle vs Mass */ \ + X(FOLDER "/p2dRingObservableDeltaPhiVsMass", deltaPhiJet, v0LambdaLikeMass, ringObservable) \ + X(FOLDER "/p2dRingObservableDeltaThetaVsMass", deltaThetaJet, v0LambdaLikeMass, ringObservable) \ + /* 3D Profiles: Angle vs Mass vs Lambda pT */ \ + X(FOLDER "/p3dRingObservableDeltaPhiVsMassVsLambdaPt", deltaPhiJet, v0LambdaLikeMass, v0pt, ringObservable) \ + X(FOLDER "/p3dRingObservableDeltaThetaVsMassVsLambdaPt", deltaThetaJet, v0LambdaLikeMass, v0pt, ringObservable) \ + /* 3D Profiles: Angle vs Mass vs Lead Jet pT */ \ + X(FOLDER "/p3dRingObservableDeltaPhiVsMassVsLeadJetPt", deltaPhiJet, v0LambdaLikeMass, leadingJetPt, ringObservable) \ + X(FOLDER "/p3dRingObservableDeltaThetaVsMassVsLeadJetPt", deltaThetaJet, v0LambdaLikeMass, leadingJetPt, ringObservable) \ + /* 2D Profile: Mass vs Centrality */ \ + X(FOLDER "/p2dRingObservableMassVsCent", v0LambdaLikeMass, centrality, ringObservable) \ + /* 3D Profiles: Angle vs Mass vs Centrality */ \ + X(FOLDER "/p3dRingObservableDeltaPhiVsMassVsCent", deltaPhiJet, v0LambdaLikeMass, centrality, ringObservable) \ + X(FOLDER "/p3dRingObservableDeltaThetaVsMassVsCent", deltaThetaJet, v0LambdaLikeMass, centrality, ringObservable) \ + X(FOLDER "/pRingIntVsCentrality", centrality, ringObservable) +// (TODO: add counters for regular TH2Ds about centrality) + +// For leading particle +#define RING_OBSERVABLE_LEADP_FILL_LIST(X, FOLDER) \ + X(FOLDER "/pRingObservableLeadPDeltaPhi", deltaPhiLeadP, ringObservableLeadP) \ + X(FOLDER "/pRingObservableLeadPDeltaTheta", deltaThetaLeadP, ringObservableLeadP) \ + X(FOLDER "/pRingObservableLeadPIntegrated", 0., ringObservableLeadP) \ + X(FOLDER "/pRingObservableLeadPLambdaPt", v0pt, ringObservableLeadP) + +// For subleading jet: +#define RING_OBSERVABLE_2NDJET_FILL_LIST(X, FOLDER) \ + X(FOLDER "/pRingObservable2ndJetDeltaPhi", deltaPhi2ndJet, ringObservable2ndJet) \ + X(FOLDER "/pRingObservable2ndJetDeltaTheta", deltaTheta2ndJet, ringObservable2ndJet) \ + X(FOLDER "/pRingObservable2ndJetIntegrated", 0., ringObservable2ndJet) \ + X(FOLDER "/pRingObservable2ndJetLambdaPt", v0pt, ringObservable2ndJet) + +#define POLARIZATION_PROFILE_FILL_LIST(X, FOLDER) \ + /* =============================== */ \ + /* 1D TProfiles vs v0phi */ \ + /* =============================== */ \ + X(FOLDER "/QA/pPxStarPhi", v0phiToFillHists, PolStarX) \ + X(FOLDER "/QA/pPyStarPhi", v0phiToFillHists, PolStarY) \ + X(FOLDER "/QA/pPzStarPhi", v0phiToFillHists, PolStarZ) \ + /* =============================== */ \ + /* 1D TProfiles vs DeltaPhi_jet */ \ + /* =============================== */ \ + X(FOLDER "/QA/pPxStarDeltaPhi", deltaPhiJet, PolStarX) \ + X(FOLDER "/QA/pPyStarDeltaPhi", deltaPhiJet, PolStarY) \ + X(FOLDER "/QA/pPzStarDeltaPhi", deltaPhiJet, PolStarZ) \ + /* =============================== */ \ + /* 2D TProfiles vs DeltaPhi_jet and Lambda pT */ \ + /* =============================== */ \ + X(FOLDER "/QA/p2dPxStarDeltaPhiVsLambdaPt", deltaPhiJet, v0pt, PolStarX) \ + X(FOLDER "/QA/p2dPyStarDeltaPhiVsLambdaPt", deltaPhiJet, v0pt, PolStarY) \ + X(FOLDER "/QA/p2dPzStarDeltaPhiVsLambdaPt", deltaPhiJet, v0pt, PolStarZ) + +// Apply the macros (notice I had to include the semicolon (";") after the function, so you don't need to +// write that when calling this APPLY_HISTO_FILL. The code will look weird, but without this the compiler +// would not know to end each statement with a semicolon): +#define APPLY_HISTO_FILL(NAME, ...) histos.fill(HIST(NAME), __VA_ARGS__); + +struct lambdajetpolarizationionsderived { + + // Define histogram registries: + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Master analysis switches + Configurable analyseLambda{"analyseLambda", true, "process Lambda-like candidates"}; + Configurable analyseAntiLambda{"analyseAntiLambda", false, "process AntiLambda-like candidates"}; + Configurable doPPAnalysis{"doPPAnalysis", false, "if in pp, set to true. Default is HI"}; + + // Centrality: + Configurable centralityEstimator{"centralityEstimator", kCentFT0M, "Run 3 centrality estimator (0:CentFT0C, 1:CentFT0M, 2:CentFV0A)"}; // Default is FT0M + + // QAs that purposefully break the analysis + // -- All of these tests should give us zero signal if the source is truly Lambda Polarization from vortices + Configurable forcePolSignQA{"forcePolSignQA", false, "force antiLambda decay constant to be positive: should kill all the signal, if any. For QA"}; + Configurable forcePerpToJet{"forcePerpToJet", false, "force jet direction to be perpendicular to jet estimator. For QA"}; + Configurable forceJetDirectionSmudge{"forceJetDirectionSmudge", false, "fluctuate jet direction by 10% of R around original axis. For QA (tests sensibility)"}; + Configurable jetRForSmuding{"jetRForSmuding", 0.4, "QA quantity: the chosen R scale for the jet direction smudge"}; + + ///////////////////////// + // Configurable blocks: + // Histogram axes configuration: + struct : ConfigurableGroup { + std::string prefix = "axisConfigurations"; // JSON group name + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisPtCoarseQA{"axisPtCoarse", {VARIABLE_WIDTH, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 7.0f, 10.0f, 15.0f}, "pt axis for QA"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {450, 1.08f, 1.15f}, "Lambda mass in GeV/c"}; // Default is {200, 1.101f, 1.131f} + + // Jet axes: + ConfigurableAxis axisLeadingParticlePt{"axisLeadingParticlePt", {100, 0.f, 200.f}, "Leading particle p_{T} (GeV/c)"}; // Simpler version! + ConfigurableAxis axisJetPt{"axisJetPt", {50, 0.f, 200.f}, "Jet p_{t} (GeV)"}; + ConfigurableAxis axisDeltaTheta{"axisDeltaTheta", {40, 0, constants::math::PI}, "#Delta #theta_{jet}"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {40, -constants::math::PI, constants::math::PI}, "#Delta #phi_{jet}"}; + + // Coarser axes for signal extraction: + ConfigurableAxis axisPtSigExtract{"axisPtSigExtract", {VARIABLE_WIDTH, 0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 2.0f, 2.5f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 15.0f, 20.0f, 30.0f, 50.0f}, "pt axis for signal extraction"}; + // ConfigurableAxis axisLambdaMassSigExtract{"axisLambdaMassSigExtract", {175, 1.08f, 1.15f}, "Lambda mass in GeV/c"}; // With a sigma of 0.002 GeV/c, this has about 5 bins per sigma, so that the window is properly grasped. + // A coarser axis (sigma is still well estimated, with about 8 bins in the peak region) + ConfigurableAxis axisLambdaMassSigExtract{ + "axisLambdaMassSigExtract", + {VARIABLE_WIDTH, + // Left sideband (7 bins, 0.004 width) + 1.0800, 1.0840, 1.0880, 1.0920, + 1.0960, 1.1000, 1.1040, 1.1080, + // Fine peak region (8 bins, 0.0016 width) + 1.1096, 1.1112, 1.1128, 1.1144, + 1.1160, 1.1176, 1.1192, 1.1208, + // Right sideband (7 bins, 0.004 width) + 1.1248, 1.1288, 1.1328, 1.1368, + 1.1408, 1.1448, 1.1488}, + "Lambda mass in GeV/c"}; + ConfigurableAxis axisLeadingParticlePtSigExtract{"axisLeadingParticlePtSigExtract", {VARIABLE_WIDTH, 0, 4, 8, 12, 16, 20, 25, 30, 35, 40, 60, 100, 200}, "Leading particle p_{T} (GeV/c)"}; // Simpler version! + ConfigurableAxis axisJetPtSigExtract{"axisJetPtSigExtract", {VARIABLE_WIDTH, 0, 5, 10, 12, 16, 20, 25, 30, 35, 40, 60, 100, 200}, "Jet p_{t} (GeV)"}; + + // (TODO: add a lambdaPt axis that is pre-selected only on the 0.5 to 1.5 Pt region for the Ring observable with lambda cuts to not store a huge histogram with empty bins by construction) + + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f}, "Centrality"}; + } axisConfigurations; + + // Helper functions: + // Fast wrapping into [-PI, PI) (restricted to this interval for function speed) + inline double wrapToPiFast(double phi) + { + constexpr double TwoPi = o2::constants::math::TwoPI; + constexpr double Pi = o2::constants::math::PI; + if (phi >= Pi) + phi -= TwoPi; + else if (phi < -Pi) + phi += TwoPi; + return phi; + } + + void init(InitContext const&) + { + // Ring observable histograms: + // Helper to register one full histogram family (kinematic cut variation of ring observable) + auto addRingObservableFamily = [&](const std::string& folder) { + // =============================== + // QA histograms: angle and pT distributions + // (No mass dependency -- useful to check kinematic sculpting from cuts) + // =============================== + histos.add((folder + "/QA/hDeltaPhi").c_str(), "hDeltaPhi", kTH1D, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/QA/hDeltaTheta").c_str(), "hDeltaTheta", kTH1D, {axisConfigurations.axisDeltaTheta}); + histos.add((folder + "/QA/hIntegrated").c_str(), "hIntegrated", kTH1D, {{1, -0.5, 0.5}}); + // =============================== + // Lambda pT dependence + // =============================== + histos.add((folder + "/QA/hLambdaPt").c_str(), "hLambdaPt", kTH1D, {axisConfigurations.axisPt}); + histos.add((folder + "/QA/h2dDeltaPhiVsLambdaPt").c_str(), "h2dDeltaPhiVsLambdaPt", kTH2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisPt}); + histos.add((folder + "/QA/h2dDeltaThetaVsLambdaPt").c_str(), "h2dDeltaThetaVsLambdaPt", kTH2D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisPt}); + // =============================== + // Polarization observable QAs + // (not Ring: actual polarization!) + // =============================== + // Will implement these as TProfiles, as polarization is also a measure like P_\Lambda = (3/\alpha_\Lambda) * , so the error is similar + // =============================== + // 1D TProfiles + // =============================== + histos.add((folder + "/QA/pPxStarPhi").c_str(), "pPxStarPhi;#varphi_{#Lambda};_{x}", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/QA/pPyStarPhi").c_str(), "pPyStarPhi;#varphi_{#Lambda};_{y}", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/QA/pPzStarPhi").c_str(), "pPzStarPhi;#varphi_{#Lambda};_{z}", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/QA/pPxStarDeltaPhi").c_str(), "pPxStarDeltaPhi;#Delta#varphi_{jet};_{x}", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/QA/pPyStarDeltaPhi").c_str(), "pPyStarDeltaPhi;#Delta#varphi_{jet};_{y}", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/QA/pPzStarDeltaPhi").c_str(), "pPzStarDeltaPhi;#Delta#varphi_{jet};_{z}", kTProfile, {axisConfigurations.axisDeltaPhi}); + // =============================== + // 2D TProfiles (Lambda correlations) + // =============================== + histos.add((folder + "/QA/p2dPxStarDeltaPhiVsLambdaPt").c_str(), "p2dPxStarDeltaPhiVsLambdaPt;#Delta#varphi_{jet};#it{p}_{T}^{#Lambda};_{x}", kTProfile2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisPtSigExtract}); + histos.add((folder + "/QA/p2dPyStarDeltaPhiVsLambdaPt").c_str(), "p2dPyStarDeltaPhiVsLambdaPt;#Delta#varphi_{jet};#it{p}_{T}^{#Lambda};_{y}", kTProfile2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisPtSigExtract}); + histos.add((folder + "/QA/p2dPzStarDeltaPhiVsLambdaPt").c_str(), "p2dPzStarDeltaPhiVsLambdaPt;#Delta#varphi_{jet};#it{p}_{T}^{#Lambda};_{z}", kTProfile2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisPtSigExtract}); + + // TProfiles with correct error bars:: + // -- TProfiles will handle the error estimate of the Ring Observable via the variance, even though + // they still lack the proper signal extraction and possible efficiency corrections in the current state + // -- If any efficiency corrections arise, you can fill with the kTH1D as (deltaPhiJet, ringObservable, weight) + // instead of the simple (deltaPhiJet, ringObservable) --> Notice TProfile knows how to accept 3 entries + // for a TH1D-like object! + // -- CAUTION! The TProfile does not utilize unbiased variance estimators with N-1 instead of N in the denominator, + // so you might get biased errors when counts are too low in higher-dimensional profiles (i.e., kTProfile2Ds) + // =============================== + // 1D TProfiles + // =============================== + histos.add((folder + "/pRingObservableDeltaPhi").c_str(), "pRingObservableDeltaPhi;#Delta#varphi_{jet};<#it{R}>", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/pRingObservableDeltaTheta").c_str(), "pRingObservableDeltaTheta;#Delta#theta_{jet};<#it{R}>", kTProfile, {axisConfigurations.axisDeltaTheta}); + histos.add((folder + "/pRingObservableIntegrated").c_str(), "pRingObservableIntegrated; ;<#it{R}>", kTProfile, {{1, -0.5, 0.5}}); + histos.add((folder + "/pRingObservableLambdaPt").c_str(), "pRingObservableLambdaPt;#it{p}_{T}^{#Lambda};<#it{R}>", kTProfile, {axisConfigurations.axisPt}); + // For the leading particle: + histos.add((folder + "/pRingObservableLeadPDeltaPhi").c_str(), "pRingObservableLeadPDeltaPhi;#Delta#varphi_{leadP};<#it{R}>", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/pRingObservableLeadPDeltaTheta").c_str(), "pRingObservableLeadPDeltaTheta;#Delta#theta_{leadP};<#it{R}>", kTProfile, {axisConfigurations.axisDeltaTheta}); + histos.add((folder + "/pRingObservableLeadPIntegrated").c_str(), "pRingObservableLeadPIntegrated; ;<#it{R}>", kTProfile, {{1, -0.5, 0.5}}); + histos.add((folder + "/pRingObservableLeadPLambdaPt").c_str(), "pRingObservableLeadPLambdaPt;#it{p}_{T}^{#Lambda};<#it{R}>", kTProfile, {axisConfigurations.axisPt}); + // For the second-to-leading jet: + histos.add((folder + "/pRingObservable2ndJetDeltaPhi").c_str(), "pRingObservable2ndJetDeltaPhi;#Delta#varphi_{2ndJet};<#it{R}>", kTProfile, {axisConfigurations.axisDeltaPhi}); + histos.add((folder + "/pRingObservable2ndJetDeltaTheta").c_str(), "pRingObservable2ndJetDeltaTheta;#Delta#theta_{2ndJet};<#it{R}>", kTProfile, {axisConfigurations.axisDeltaTheta}); + histos.add((folder + "/pRingObservable2ndJetIntegrated").c_str(), "pRingObservable2ndJetIntegrated; ;<#it{R}>", kTProfile, {{1, -0.5, 0.5}}); + histos.add((folder + "/pRingObservable2ndJetLambdaPt").c_str(), "pRingObservable2ndJetLambdaPt;#it{p}_{T}^{#Lambda};<#it{R}>", kTProfile, {axisConfigurations.axisPt}); + // =============================== + // 2D TProfiles (Lambda correlations) + // =============================== + histos.add((folder + "/p2dRingObservableDeltaPhiVsLambdaPt").c_str(), "p2dRingObservableDeltaPhiVsLambdaPt;#Delta#varphi_{jet};#it{p}_{T}^{#Lambda};<#it{R}>", kTProfile2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisPt}); + histos.add((folder + "/p2dRingObservableDeltaThetaVsLambdaPt").c_str(), "p2dRingObservableDeltaThetaVsLambdaPt;#Delta#theta_{jet};#it{p}_{T}^{#Lambda};<#it{R}>", kTProfile2D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisPt}); + // =============================== + // 2D TProfiles (Jet correlations) + // =============================== + histos.add((folder + "/p2dRingObservableDeltaPhiVsLeadJetPt").c_str(), "p2dRingObservableDeltaPhiVsLeadJetPt;#Delta#varphi_{jet};#it{p}_{T}^{lead jet};<#it{R}>", kTProfile2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisJetPt}); + histos.add((folder + "/p2dRingObservableDeltaThetaVsLeadJetPt").c_str(), "p2dRingObservableDeltaThetaVsLeadJetPt;#Delta#theta_{jet};#it{p}_{T}^{lead jet};<#it{R}>", kTProfile2D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisJetPt}); + + // =============================== + // Multi-dimensional histograms for signal extraction + // (Mass-dependent polarization extraction) + // =============================== + // Simple invariant mass plot for QA: + histos.add((folder + "/QA/hMass").c_str(), "hMass", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add((folder + "/hMassSigExtract").c_str(), "hMassSigExtract", kTH1D, {axisConfigurations.axisLambdaMassSigExtract}); + // 1D Mass dependence of observable numerator: + histos.add((folder + "/QA/hRingObservableNumMass").c_str(), "hRingObservableNumMass", kTH1D, {axisConfigurations.axisLambdaMassSigExtract}); + // --- 2D counters: Angle vs Mass vs --- + histos.add((folder + "/QA/h2dDeltaPhiVsMass").c_str(), "h2dDeltaPhiVsMass", kTH2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract}); + histos.add((folder + "/QA/h2dDeltaThetaVsMass").c_str(), "h2dDeltaThetaVsMass", kTH2D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract}); + // --- 3D counters: Angle vs Mass vs Lambda pT --- + histos.add((folder + "/QA/h3dDeltaPhiVsMassVsLambdaPt").c_str(), "h3dDeltaPhiVsMassVsLambdaPt", kTH3D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisPtSigExtract}); + histos.add((folder + "/QA/h3dDeltaThetaVsMassVsLambdaPt").c_str(), "h3dDeltaThetaVsMassVsLambdaPt", kTH3D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisPtSigExtract}); + // --- 3D counters: Angle vs Mass vs Lead Jet pT --- + histos.add((folder + "/QA/h3dDeltaPhiVsMassVsLeadJetPt").c_str(), "h3dDeltaPhiVsMassVsLeadJetPt", kTH3D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisJetPtSigExtract}); + histos.add((folder + "/QA/h3dDeltaThetaVsMassVsLeadJetPt").c_str(), "h3dDeltaThetaVsMassVsLeadJetPt", kTH3D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisJetPtSigExtract}); + + // =============================== + // TProfiles vs Mass: quick glancing before signal extraction + // =============================== + // TProfile of ring vs mass (integrated in all phi, and properly normalized by N_\Lambda): + histos.add((folder + "/pRingObservableMass").c_str(), "pRingObservableMass;m_{p#pi};<#it{R}>", kTProfile, {axisConfigurations.axisLambdaMassSigExtract}); + histos.add((folder + "/pRingObservableLeadPMass").c_str(), "pRingObservableLeadPMass;m_{p#pi};<#it{R}>", kTProfile, {axisConfigurations.axisLambdaMassSigExtract}); + histos.add((folder + "/pRingObservable2ndJetMass").c_str(), "pRingObservable2ndJetMass;m_{p#pi};<#it{R}>", kTProfile, {axisConfigurations.axisLambdaMassSigExtract}); + // TProfile2D: vs Mass (DeltaPhi) + histos.add((folder + "/p2dRingObservableDeltaPhiVsMass").c_str(), "p2dRingObservableDeltaPhiVsMass;#Delta#varphi;m_{p#pi};<#it{R}>", kTProfile2D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract}); + // TProfile2D: vs Mass (DeltaTheta) + histos.add((folder + "/p2dRingObservableDeltaThetaVsMass").c_str(), "p2dRingObservableDeltaThetaVsMass;#Delta#theta;m_{p#pi};<#it{R}>", kTProfile2D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract}); + // --- TProfile3D: vs DeltaPhi vs Mass vs LambdaPt --- + histos.add((folder + "/p3dRingObservableDeltaPhiVsMassVsLambdaPt").c_str(), "p3dRingObservableDeltaPhiVsMassVsLambdaPt;#Delta#varphi;m_{p#pi};p_{T}^{#Lambda};<#it{R}>", kTProfile3D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisPtSigExtract}); + // --- TProfile3D: vs DeltaTheta vs Mass vs LambdaPt --- + histos.add((folder + "/p3dRingObservableDeltaThetaVsMassVsLambdaPt").c_str(), "p3dRingObservableDeltaThetaVsMassVsLambdaPt;#Delta#theta;m_{p#pi};p_{T}^{#Lambda};<#it{R}>", kTProfile3D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisPtSigExtract}); + // --- TProfile3D: vs DeltaPhi vs Mass vs LeadJetPt --- + histos.add((folder + "/p3dRingObservableDeltaPhiVsMassVsLeadJetPt").c_str(), "p3dRingObservableDeltaPhiVsMassVsLeadJetPt;#Delta#varphi;m_{p#pi};p_{T}^{jet};<#it{R}>", kTProfile3D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisJetPtSigExtract}); + // --- TProfile3D: vs DeltaTheta vs Mass vs LeadJetPt --- + histos.add((folder + "/p3dRingObservableDeltaThetaVsMassVsLeadJetPt").c_str(), "p3dRingObservableDeltaThetaVsMassVsLeadJetPt;#Delta#theta;m_{p#pi};p_{T}^{jet};<#it{R}>", kTProfile3D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisJetPtSigExtract}); + + // =============================== + // Mass histograms with centrality + // =============================== + // Counters + histos.add((folder + "/QA/h3dDeltaPhiVsMassVsCent").c_str(), "h3dDeltaPhiVsMassVsCent", kTH3D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisCentrality}); + histos.add((folder + "/QA/h3dDeltaThetaVsMassVsCent").c_str(), "h3dDeltaThetaVsMassVsCent", kTH3D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisCentrality}); + // Useful TProfiles: + // --- TProfile1D: Integrated vs Centrality: + histos.add((folder + "/pRingIntVsCentrality").c_str(), "pRingIntVsCentrality; Centrality (%);<#it{R}>", kTProfile, {axisConfigurations.axisCentrality}); + // --- TProfile2D: vs Mass vs Centrality --- + histos.add((folder + "/p2dRingObservableMassVsCent").c_str(), "p2dRingObservableMassVsCent;m_{p#pi};Centrality;<#it{R}>", kTProfile2D, {axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisCentrality}); + // --- TProfile3D: vs DeltaPhi vs Mass vs Centrality --- + histos.add((folder + "/p3dRingObservableDeltaPhiVsMassVsCent").c_str(), "p3dRingObservableDeltaPhiVsMassVsCent;#Delta#varphi;m_{p#pi};Centrality;<#it{R}>", kTProfile3D, {axisConfigurations.axisDeltaPhi, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisCentrality}); + // --- TProfile3D: vs DeltaTheta vs Mass vs Centrality --- + histos.add((folder + "/p3dRingObservableDeltaThetaVsMassVsCent").c_str(), "p3dRingObservableDeltaThetaVsMassVsCent;#Delta#theta;m_{p#pi};Centrality;<#it{R}>", kTProfile3D, {axisConfigurations.axisDeltaTheta, axisConfigurations.axisLambdaMassSigExtract, axisConfigurations.axisCentrality}); + + // =============================== + // QA histograms - Useful numbers + // =============================== + // (TODO: implement these!) + // (TODO: implement momentum imbalance checks for jets!) + // Added to a separate folder for further control (changed the usage of the "folder" string): + // histos.add(("QA_Numbers/" + folder + "/hValidLeadJets").c_str(), "hValidLeadJets", kTH1D, {{1,0,1}}); + // TODO: Add "frequency of jets per pT" histograms either here or in the TableProducer + }; + // Execute local lambda to register histogram families: + addRingObservableFamily("Ring"); + addRingObservableFamily("RingKinematicCuts"); + addRingObservableFamily("JetKinematicCuts"); + addRingObservableFamily("JetAndLambdaKinematicCuts"); + + histos.add("pRingCuts", "pRingCuts; ;<#it{R}>", kTProfile, {{4, 0, 4}}); + histos.get(HIST("pRingCuts"))->GetXaxis()->SetBinLabel(1, "All #Lambda"); + histos.get(HIST("pRingCuts"))->GetXaxis()->SetBinLabel(2, "p_{T}^{#Lambda}@[0.5,1.5],|y_{#Lambda}|<0.5"); // (v0pt > 0.5 && v0pt < 1.5) && std::abs(lambdaRapidity) < 0.5; + histos.get(HIST("pRingCuts"))->GetXaxis()->SetBinLabel(3, "|Jet_{#eta}|<0.5"); + histos.get(HIST("pRingCuts"))->GetXaxis()->SetBinLabel(4, "#Lambda + Jet cuts"); + + // Same for subleading jet and leading particle: + histos.add("pRingCutsSubLeadingJet", "pRingCutsSubLeadingJet; ;<#it{R}>", kTProfile, {{4, 0, 4}}); + histos.get(HIST("pRingCutsSubLeadingJet"))->GetXaxis()->SetBinLabel(1, "All #Lambda"); + histos.get(HIST("pRingCutsSubLeadingJet"))->GetXaxis()->SetBinLabel(2, "p_{T,#Lambda}@[0.5,1.5],|y_{#Lambda}|<0.5"); + histos.get(HIST("pRingCutsSubLeadingJet"))->GetXaxis()->SetBinLabel(3, "|SubJet_{#eta}|<0.5"); + histos.get(HIST("pRingCutsSubLeadingJet"))->GetXaxis()->SetBinLabel(4, "#Lambda + SubJet cuts"); + + histos.add("pRingCutsLeadingP", "pRingCutsLeadingP; ;<#it{R}>", kTProfile, {{4, 0, 4}}); + histos.get(HIST("pRingCutsLeadingP"))->GetXaxis()->SetBinLabel(1, "All #Lambda"); + histos.get(HIST("pRingCutsLeadingP"))->GetXaxis()->SetBinLabel(2, "p_{T}^{#Lambda}@[0.5,1.5],|y_{#Lambda}|<0.5"); + histos.get(HIST("pRingCutsLeadingP"))->GetXaxis()->SetBinLabel(3, "|LeadP_{#eta}|<0.5"); + histos.get(HIST("pRingCutsLeadingP"))->GetXaxis()->SetBinLabel(4, "#Lambda + LeadP cuts"); + } + + // Helper to get centrality (same from TableProducer, thanks to templating!): + template + auto getCentrality(TCollision const& collision) + { + if (centralityEstimator == kCentFT0M) + return collision.centFT0M(); + else if (centralityEstimator == kCentFT0C) + return collision.centFT0C(); + else if (centralityEstimator == kCentFV0A) + return collision.centFV0A(); + return -1.f; + } + + // Initializing a random number generator for the worker (for perpendicular-to-jet direction QAs): + TRandom3 randomGen{0}; // 0 means we auto-seed from machine entropy. This is called once per device in the pipeline, so we should not see repeated seeds across workers + + // Preslices for correct collisions association: + // (TODO: test using custom grouping) + Preslice perColJets = o2::aod::lambdajetpol::ringCollisionId; + Preslice perColV0s = o2::aod::lambdajetpol::ringCollisionId; + Preslice perColLeadPs = o2::aod::lambdajetpol::ringCollisionId; + void processPolarizationData(o2::aod::RingCollisions const& collisions, o2::aod::RingJets const& jets, o2::aod::RingLaV0s const& v0s, + o2::aod::RingLeadPs const& leadPs) + { + for (auto const& collision : collisions) { + const auto collId = collision.globalIndex(); // The self-index accessor + const double centrality = getCentrality(collision); + + // Slice jets, V0s and leading particle belonging to this collision: + // (global collision indices repeat a lot, but they are unique to a same TimeFrame (TF) subfolder in the derived data) + auto v0sInColl = v0s.sliceBy(perColV0s, collId); + auto leadPsInColl = leadPs.sliceBy(perColLeadPs, collId); + + // Check if there is at least one V0 and one jet in the collision: + // (in the way I fill the table, there is always at least one V0 in + // the stored collision, but the jets table can not be filled for + // that collision, and a collision may not be filled when the jets + // table is. Be mindful of that!) + // 1) Require at least one V0: + if (!v0sInColl.size()) + continue; + + // 2) We require at least a leading particle, then we get the leading jet only if it exists: + // (The goal is to see how diluted the signal gets with events which don't even have a loose FastJet jet) + // (The leading particle is built from all tracks that passed the pseudojet + // selection, so it exists whenever FastJet was run on this collision. + // Events that have a leading jet always have a leading particle too, but + // the converse is not true: events can have a leading particle with no jet + // if no jet survives the pT threshold/the background subtraction) + float leadPPt = -1.; // pT = -1 means "table entry not found for this collision". + float leadPEta = 0.; + float leadPPhi = 0.; + float leadPPx = 0., leadPPy = 0., leadPPz = 0.; + for (auto const& lp : leadPsInColl) { + // Table should contain exactly one entry per collision, + // but we break immediately to be safe: + leadPPt = lp.leadParticlePt(); + leadPEta = lp.leadParticleEta(); + leadPPhi = lp.leadParticlePhi(); + // Using dynamic columns to make code cleaner: + leadPPx = lp.leadParticlePx(); + leadPPy = lp.leadParticlePy(); + leadPPz = lp.leadParticlePz(); + break; + } + // Discard events with no leading particle (FastJet didn't even run in these cases!): + if (leadPPt < 0.) + continue; + + // Build leading particle unit vector, outside the V0 loop for performance: + XYZVector leadPUnitVec = XYZVector(leadPPx, leadPPy, leadPPz).Unit(); + + // 3) Checking if the event has a leading jet: + auto jetsInColl = jets.sliceBy(perColJets, collId); + float leadingJetPt = -1.; + float subleadingJetPt = -1.; + // std::optional avoids undefined behaviour from a default-constructed iterator: + // (essentially, just protection for when we fetch jetEta() and the such) + std::optional leadingJet; + std::optional subleadingJet; + for (auto const& jet : jetsInColl) { + const auto jetpt = jet.jetPt(); + if (jetpt > leadingJetPt) { + // Current leading becomes subleading: + subleadingJetPt = leadingJetPt; + subleadingJet = leadingJet; // may still be std::nullopt on first pass -- that is fine! + // Now update the leading jet: + leadingJetPt = jetpt; + leadingJet = jet; + } else if (jetpt > subleadingJetPt) { // Update subleading only: + subleadingJetPt = jetpt; + subleadingJet = jet; + } + } + + // Some useful bools to check if we have a leading jet and a subleading jet: + const bool hasValidLeadingJet = leadingJetPt > 0.; + const bool hasValidSubJet = subleadingJetPt > 0.; + + // Build jet vectors (only when the corresponding jet exists): + // Dummy initialisations are safe: all jet-dependent fills are gated on hasValidLeadingJet / hasValidSubJet. + float leadingJetEta = 0.; + float leadingJetPhi = 0.; + XYZVector leadingJetUnitVec(1., 0., 0.); // dummy (overwritten below) + if (hasValidLeadingJet) { + leadingJetEta = leadingJet->jetEta(); + leadingJetPhi = leadingJet->jetPhi(); + // Using internal getters to make code cleaner: + leadingJetUnitVec = XYZVector(leadingJet->jetPx(), leadingJet->jetPy(), leadingJet->jetPz()).Unit(); + + // QA block -- Purposefully changing the jet direction (should kill signal, if any): + if (forcePerpToJet) { // Use modified jet direction (done outside loop to guarantee all V0s inside event use same fake jet) + // First, we build a vector perpendicular to the jet by picking an arbitrary vector not parallel to the jet + XYZVector refVec(1., 0., 0.); + if (std::abs(leadingJetUnitVec.Dot(refVec)) > 0.99) + refVec = XYZVector(0., 1., 0.); + // Now we get a perpendicular vector to the jet direction: + XYZVector perpVec = leadingJetUnitVec.Cross(refVec).Unit(); + // Now we rotate around the jet axis by a random angle, just to make sure we are not introducing a bias in the QA: + // We will use Rodrigues' rotation formula (v_rot = v*cos(randomAngle) + (Jet \cross v)*sin(randomAngle)) + double randomAngle = randomGen.Uniform(0., o2::constants::math::TwoPI); + leadingJetUnitVec = perpVec * std::cos(randomAngle) + leadingJetUnitVec.Cross(perpVec) * std::sin(randomAngle); + } else if (forceJetDirectionSmudge) { + // Smear the jet direction by a small random angle to estimate sensitivity to + // jet axis uncertainty. We rotate the jet axis by angle theta around a uniformly + // random perpendicular axis -- this is isotropic and coordinate-independent, + // unlike smearing eta and phi separately (which would break azimuthal symmetry + // around the jet axis and depend on where in eta the jet sits). + + // 1) We pick a uniformly random axis perpendicular to the jet. + // (re-using the same Rodrigues formula as in the forcePerpToJet block above) + XYZVector refVec(1., 0., 0.); + if (std::abs(leadingJetUnitVec.Dot(refVec)) > 0.99) + refVec = XYZVector(0., 1., 0.); + XYZVector perpVec = leadingJetUnitVec.Cross(refVec).Unit(); + // Rotate perpVec around the jet axis by a uniform random azimuth to get + // a uniformly distributed random perpendicular direction (the smear axis): + double smearAzimuth = randomGen.Uniform(0., o2::constants::math::TwoPI); + XYZVector smearAxis = perpVec * std::cos(smearAzimuth) + leadingJetUnitVec.Cross(perpVec) * std::sin(smearAzimuth); + + // Step 2: draw the smearing polar angle from a Gaussian: + // sigma = 0.05 * R --> ~68% of events smeared within 5% of R, + // ~95% of events smeared within 10% of R, + // ~5% see a displacement > 0.1*R (a very "badly determined jet", for our QA purposes) + // std::abs() folds the symmetric Gaussian onto a half-normal ([0, inf)) + // -- R is not really an angle: just gives me a scale for the angular shift I am performing. + // -- This may pose problems for forward jets: a small displacemente in \theta becomes a large displacement in \eta space + double smearSigma = 0.05 * jetRForSmuding; + double smearAngle = std::abs(randomGen.Gaus(0., smearSigma)); + + // Step 3: rotate the jet axis by smearAngle around smearAxis. + // Rodrigues is v_rot = v*cos(theta) + (k \croos v)*sin(theta) + k*(k \cdot v)*(1-cos(theta)) + // But the last term vanishes because smearAxis is perpendicular to leadingJetUnitVec: + leadingJetUnitVec = leadingJetUnitVec * std::cos(smearAngle) + smearAxis.Cross(leadingJetUnitVec) * std::sin(smearAngle); + // Also, rotation preserves the norm, so no re-normalisation is needed for this to be a unit vector. + } + } + + float subleadingJetEta = 0.; + float subleadingJetPhi = 0.; + XYZVector subJetUnitVec(1., 0., 0.); + if (hasValidSubJet) { + subleadingJetEta = subleadingJet->jetEta(); + subleadingJetPhi = subleadingJet->jetPhi(); + // Using internal getters to make code cleaner: + subJetUnitVec = XYZVector(subleadingJet->jetPx(), subleadingJet->jetPy(), subleadingJet->jetPz()).Unit(); + } + + // (jet eta cuts only meaningful when the jet actually exists) + const bool kinematicJetCheck = hasValidLeadingJet && (std::abs(leadingJetEta) < 0.5); + const bool kinematic2ndJetCheck = hasValidSubJet && (std::abs(subleadingJetEta) < 0.5); + const bool kinematicLeadPCheck = std::abs(leadPEta) < 0.5; + + for (auto const& v0 : v0sInColl) { + const bool isLambda = v0.isLambda(); + const bool isAntiLambda = v0.isAntiLambda(); + // For now, removing the ambiguous candidates from the analysis. Derived data permits handling both. + // (From Podolanski-Armenteros plots, the population of ambiguous is ~2% without TOF, and without + // competing mass rejection. From those, ~99% seem to be K0s, so no real gain in considering the + // ambiguous candidates in the analysis) + if (isLambda && isAntiLambda) + continue; + const float v0pt = v0.v0Pt(); + const float v0eta = v0.v0Eta(); + const float v0phi = v0.v0Phi(); + + float v0LambdaLikeMass = 0; // Initialized just to catch any stray behavior + float protonLikePt = 0; + float protonLikeEta = 0; + float protonLikePhi = 0; + if (isLambda) { + if (!analyseLambda) + continue; + v0LambdaLikeMass = v0.massLambda(); + protonLikePt = v0.posPt(); + protonLikeEta = v0.posEta(); + protonLikePhi = v0.posPhi(); + } else if (isAntiLambda) { // (TODO: add a split histogram where you consider Lambda and AntiLambda polarization separately?) + if (!analyseAntiLambda) + continue; + v0LambdaLikeMass = v0.massAntiLambda(); + protonLikePt = v0.negPt(); + protonLikeEta = v0.negEta(); + protonLikePhi = v0.negPhi(); + } + + PtEtaPhiMVector lambdaLike4Vec(v0pt, v0eta, v0phi, v0LambdaLikeMass); + PtEtaPhiMVector protonLike4Vec(protonLikePt, protonLikeEta, protonLikePhi, protonMass); + float lambdaRapidity = lambdaLike4Vec.Rapidity(); // For further kinematic selections + + // Boosting proton into lambda frame: + XYZVector beta = -lambdaLike4Vec.BoostToCM(); // Boost trivector that goes from laboratory frame to the rest frame + auto protonLike4VecStar = ROOT::Math::VectorUtil::boost(protonLike4Vec, beta); + + // Getting unit vectors and 3-components: + XYZVector lambdaLike3Vec = lambdaLike4Vec.Vect(); + XYZVector protonLikeStarUnit3Vec = protonLike4VecStar.Vect().Unit(); + + //////////////////////////////////////////// + // Ring observable: Leading particle proxy + // Always computed -- leading particle existence is guaranteed by the second check above + //////////////////////////////////////////// + // Cross product + XYZVector crossLeadP = leadPUnitVec.Cross(lambdaLike3Vec); + float ringObservableLeadP = protonLikeStarUnit3Vec.Dot(crossLeadP) / crossLeadP.R(); + // Adding the prefactor related to the CP-violating decay (decay constants have different signs) + if (!forcePolSignQA) + ringObservableLeadP *= (isLambda) ? polPrefactorLambda : polPrefactorAntiLambda; + else + ringObservableLeadP *= (isLambda) ? polPrefactorLambda : -1.0 * polPrefactorAntiLambda; + // Angular variables + float deltaPhiLeadP = wrapToPiFast(v0phi - leadPPhi); // Wrapped to [-PI, pi), for convenience + float deltaThetaLeadP = ROOT::Math::VectorUtil::Angle(leadPUnitVec, lambdaLike3Vec); // 3D angular separation + + ////////////////////////////////////////// + // Ring observable: Leading jet proxy + // Only computed when a leading jet exists in this collision. + ////////////////////////////////////////// + float ringObservable = 0.; + float deltaPhiJet = 0.; + float deltaThetaJet = 0.; + if (hasValidLeadingJet) { + // Cross product + XYZVector cross = leadingJetUnitVec.Cross(lambdaLike3Vec); + ringObservable = protonLikeStarUnit3Vec.Dot(cross) / cross.R(); + // Adding prefactor + if (!forcePolSignQA) + ringObservable *= (isLambda) ? polPrefactorLambda : polPrefactorAntiLambda; + else + ringObservable *= (isLambda) ? polPrefactorLambda : -1.0 * polPrefactorAntiLambda; + // Angular variables + deltaPhiJet = wrapToPiFast(v0phi - leadingJetPhi); + deltaThetaJet = ROOT::Math::VectorUtil::Angle(leadingJetUnitVec, lambdaLike3Vec); + } + + ////////////////////////////////////////// + // Ring observable: Subleading jet proxy + // Only computed when a subleading jet exists in this collision. + ////////////////////////////////////////// + float ringObservable2ndJet = 0.; + float deltaPhi2ndJet = 0.; + float deltaTheta2ndJet = 0.; + if (hasValidSubJet) { + XYZVector cross2ndJet = subJetUnitVec.Cross(lambdaLike3Vec); + ringObservable2ndJet = protonLikeStarUnit3Vec.Dot(cross2ndJet) / cross2ndJet.R(); + // Adding prefactor + if (!forcePolSignQA) + ringObservable2ndJet *= (isLambda) ? polPrefactorLambda : polPrefactorAntiLambda; + else + ringObservable2ndJet *= (isLambda) ? polPrefactorLambda : -1.0 * polPrefactorAntiLambda; + // Angular variables + deltaPhi2ndJet = wrapToPiFast(v0phi - subleadingJetPhi); + deltaTheta2ndJet = ROOT::Math::VectorUtil::Angle(subJetUnitVec, lambdaLike3Vec); + } + + // Calculating polarization observables (in the Lambda frame, because that is easier -- does not require boosts): + // To be precise, not actually the polarization, but a part of the summand in P^*_\Lambda = (3/\alpha_\Lambda) * + float PolStarX = 0, PolStarY = 0, PolStarZ = 0; // Dummy initialization: avoid warnings in compile time + if (isLambda) { // Notice there is no need to check analyseLambda again due to previous checks. + PolStarX = polPrefactorLambda * protonLikeStarUnit3Vec.X(); + PolStarY = polPrefactorLambda * protonLikeStarUnit3Vec.Y(); + PolStarZ = polPrefactorLambda * protonLikeStarUnit3Vec.Z(); + } else if (isAntiLambda) { + PolStarX = polPrefactorAntiLambda * protonLikeStarUnit3Vec.X(); + PolStarY = polPrefactorAntiLambda * protonLikeStarUnit3Vec.Y(); + PolStarZ = polPrefactorAntiLambda * protonLikeStarUnit3Vec.Z(); + } + + float v0phiToFillHists = wrapToPiFast(v0phi); // A short wrap to reuse some predefined axes + + // Fill ring histograms: (1D, lambda 2D correlations and jet 2D correlations): + RING_OBSERVABLE_LEADP_FILL_LIST(APPLY_HISTO_FILL, "Ring") // Notice the usage of macros! If you change the variable names, this WILL break the code! + // No, there should NOT be any ";" here! Read the macro definition for an explanation + histos.fill(HIST("pRingCutsLeadingP"), 0, ringObservableLeadP); // First bin of comparison + POLARIZATION_PROFILE_FILL_LIST(APPLY_HISTO_FILL, "Ring") + + if (hasValidLeadingJet) { + RING_OBSERVABLE_FILL_LIST(APPLY_HISTO_FILL, "Ring") + histos.fill(HIST("pRingCuts"), 0, ringObservable); + } + if (hasValidSubJet) { + RING_OBSERVABLE_2NDJET_FILL_LIST(APPLY_HISTO_FILL, "Ring") + histos.fill(HIST("pRingCutsSubLeadingJet"), 0, ringObservable2ndJet); + } + + // Extra kinematic criteria for Lambda candidates (removes polarization background): + const bool kinematicLambdaCheck = (v0pt > 0.5 && v0pt < 1.5) && std::abs(lambdaRapidity) < 0.5; + if (kinematicLambdaCheck) { + RING_OBSERVABLE_LEADP_FILL_LIST(APPLY_HISTO_FILL, "RingKinematicCuts") + histos.fill(HIST("pRingCutsLeadingP"), 1, ringObservableLeadP); + POLARIZATION_PROFILE_FILL_LIST(APPLY_HISTO_FILL, "RingKinematicCuts") + if (hasValidLeadingJet) { + RING_OBSERVABLE_FILL_LIST(APPLY_HISTO_FILL, "RingKinematicCuts") + histos.fill(HIST("pRingCuts"), 1, ringObservable); + } + if (hasValidSubJet) { + RING_OBSERVABLE_2NDJET_FILL_LIST(APPLY_HISTO_FILL, "RingKinematicCuts") + histos.fill(HIST("pRingCutsSubLeadingJet"), 1, ringObservable2ndJet); + } + } + + // Extra selection criteria on jet candidates: + // (redundant for jets with R=0.4, but for jets with R<0.4 the leading jet may be farther in eta) + if (kinematicJetCheck) { // Already includes hasValidLeadingJet in the bool! (no need to check again) + RING_OBSERVABLE_FILL_LIST(APPLY_HISTO_FILL, "JetKinematicCuts") + histos.fill(HIST("pRingCuts"), 2, ringObservable); + POLARIZATION_PROFILE_FILL_LIST(APPLY_HISTO_FILL, "JetKinematicCuts") + } + + // Extra selection criteria on both Lambda and jet candidates: + if (kinematicLambdaCheck && kinematicJetCheck) { + RING_OBSERVABLE_FILL_LIST(APPLY_HISTO_FILL, "JetAndLambdaKinematicCuts") + histos.fill(HIST("pRingCuts"), 3, ringObservable); + POLARIZATION_PROFILE_FILL_LIST(APPLY_HISTO_FILL, "JetAndLambdaKinematicCuts") + } + + // Same variations for the leading particle and for the subleading jet: + if (kinematicLeadPCheck) { + RING_OBSERVABLE_LEADP_FILL_LIST(APPLY_HISTO_FILL, "JetKinematicCuts") + histos.fill(HIST("pRingCutsLeadingP"), 2, ringObservableLeadP); + } + if (kinematic2ndJetCheck) { + RING_OBSERVABLE_2NDJET_FILL_LIST(APPLY_HISTO_FILL, "JetKinematicCuts") + histos.fill(HIST("pRingCutsSubLeadingJet"), 2, ringObservable2ndJet); + } + if (kinematicLambdaCheck && kinematicLeadPCheck) { + RING_OBSERVABLE_LEADP_FILL_LIST(APPLY_HISTO_FILL, "JetAndLambdaKinematicCuts") + histos.fill(HIST("pRingCutsLeadingP"), 3, ringObservableLeadP); + } + if (kinematicLambdaCheck && kinematic2ndJetCheck) { + RING_OBSERVABLE_2NDJET_FILL_LIST(APPLY_HISTO_FILL, "JetAndLambdaKinematicCuts") + histos.fill(HIST("pRingCutsSubLeadingJet"), 3, ringObservable2ndJet); + } + } // end v0s loop + } // end collisions + } + + PROCESS_SWITCH(lambdajetpolarizationionsderived, processPolarizationData, "Process derived data in Run 3 Data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} + +// Avoid macro leakage! +#undef APPLY_HISTO_FILL diff --git a/PWGLF/Tasks/Strangeness/lambdapolarization.cxx b/PWGLF/Tasks/Strangeness/lambdapolarization.cxx index 772b5d04e7f..e098bc622e4 100644 --- a/PWGLF/Tasks/Strangeness/lambdapolarization.cxx +++ b/PWGLF/Tasks/Strangeness/lambdapolarization.cxx @@ -63,7 +63,7 @@ using namespace o2::constants::physics; struct lambdapolarization { // using EventCandidates = soa::Filtered>; - using EventCandidates = soa::Join; + using EventCandidates = soa::Join; using TrackCandidates = soa::Join; using V0TrackCandidate = aod::V0Datas; @@ -84,6 +84,7 @@ struct lambdapolarization { Configurable cfgCentSel{"cfgCentSel", 80., "Centrality selection"}; Configurable cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + Configurable cfgCentEstFT0CVariant2{"cfgCentEstFT0CVariant2", false, "flag to replace the estimator with centFT0CVariant2"}; Configurable cfgPVSel{"cfgPVSel", false, "Additional PV selection flag for syst"}; Configurable cfgPV{"cfgPV", 8.0, "Additional PV selection range for syst"}; @@ -918,6 +919,9 @@ struct lambdapolarization { { if (cfgCentEst == 1) { centrality = collision.centFT0C(); + if (cfgCentEstFT0CVariant2) { + centrality = collision.centFT0CVariant2(); + } } else if (cfgCentEst == 2) { centrality = collision.centFT0M(); } diff --git a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx index c2d50cfbc87..014834942f5 100644 --- a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx +++ b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx @@ -59,6 +59,118 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; +namespace mcacc +{ +// event +template +static inline float cent(const Coll& c) +{ + return c.centmc(); +} + +template +static inline float posz(const Coll& c) +{ + return c.poszmc(); +} + +// pair / v0 candidate +template +static inline int v0Status(const T& t) +{ + return t.v0Statusmc(); +} + +template +static inline bool doubleStatus(const T& t) +{ + return t.doubleStatusmc(); +} + +template +static inline float v0CosPA(const T& t) +{ + return t.v0Cospamc(); +} + +template +static inline float v0Radius(const T& t) +{ + return t.v0Radiusmc(); +} + +template +static inline float dcaPos(const T& t) +{ + return t.dcaPositivemc(); +} + +template +static inline float dcaNeg(const T& t) +{ + return t.dcaNegativemc(); +} + +template +static inline float dcaDau(const T& t) +{ + return t.dcaBetweenDaughtermc(); +} + +template +static inline float lamPt(const T& t) +{ + return t.lambdaPtmc(); +} + +template +static inline float lamEta(const T& t) +{ + return t.lambdaEtamc(); +} + +template +static inline float lamPhi(const T& t) +{ + return t.lambdaPhimc(); +} + +template +static inline float lamMass(const T& t) +{ + return t.lambdaMassmc(); +} + +template +static inline float prPt(const T& t) +{ + return t.protonPtmc(); +} + +template +static inline float prEta(const T& t) +{ + return t.protonEtamc(); +} + +template +static inline float prPhi(const T& t) +{ + return t.protonPhimc(); +} + +template +static inline int prIdx(const T& t) +{ + return t.protonIndexmc(); +} + +template +static inline int piIdx(const T& t) +{ + return t.pionIndexmc(); +} +} // namespace mcacc struct lambdaspincorrderived { // BinningType colBinning; @@ -67,6 +179,10 @@ struct lambdaspincorrderived { Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; } cfgCcdbParam; + struct : ConfigurableGroup { + ConfigurableAxis cfgMixRadiusBins{"cfgMixRadiusBins", {VARIABLE_WIDTH, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 12.0, 15.0, 20.0, 25.0, 30.0}, "Radius bins for V6 radius buffer"}; + } cfgMixRadiusParam; + // Enable access to the CCDB for the offset and correction constants and save them in dedicated variables. Service ccdb; o2::ccdb::CcdbApi ccdbApi; @@ -79,7 +195,9 @@ struct lambdaspincorrderived { TH3D* hweight22; TH3D* hweight32; TH3D* hweight42; + TH2D* hweightCentPair = nullptr; + Configurable ConfWeightPathCentPair{"ConfWeightPathCentPair", "", "Centrality x pair-type weight path"}; Configurable ConfWeightPathLL{"ConfWeightPathLL", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path"}; Configurable ConfWeightPathALAL{"ConfWeightPathALAL", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path"}; Configurable ConfWeightPathLAL{"ConfWeightPathLAL", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path"}; @@ -90,11 +208,36 @@ struct lambdaspincorrderived { Configurable ConfWeightPathLAL2{"ConfWeightPathLAL2", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path 2"}; Configurable ConfWeightPathALL2{"ConfWeightPathALL2", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path 2"}; - // event sel///////// + // Mixing ///////// + struct : ConfigurableGroup { + Configurable nKinematicPt{"nKinematicPt", 1.0, "Number of pT buffer bins"}; + Configurable nKinematicEta{"nKinematicEta", 1.0, "Number of eta buffer bins"}; + Configurable nKinematicPhi{"nKinematicPhi", 1.0, "Number of phi buffer bins"}; + } cfgKinematicBins; + + Configurable ptMinMixBuffer{"ptMinMixBuffer", 0.7, "Minimum V0 pT for mix buffer"}; + Configurable ptMaxMixBuffer{"ptMaxMixBuffer", 4.1, "Maximum V0 pT for mix buffer"}; + Configurable cfgMixLegMode{"cfgMixLegMode", 0, "0=replace leg-1 only, 1=replace leg-2 only, 2=do both one-leg replacements"}; + Configurable cfgV5MassBins{"cfgV5MassBins", 5, "Number of fixed mass bins for V5 mixing"}; + Configurable cfgV5NeighborPt{"cfgV5NeighborPt", 0, "v5: neighbor bins in pT (use symmetric ±N, edge-safe)"}; + Configurable cfgV5NeighborEta{"cfgV5NeighborEta", 0, "v5: neighbor bins in eta (use symmetric ±N, edge-safe)"}; + Configurable cfgV5NeighborPhi{"cfgV5NeighborPhi", 0, "v5: neighbor bins in phi (use symmetric ±N, periodic wrap)"}; + Configurable usePairKineMatch{"usePairKineMatch", true, "Require pair-level matching between (A,B) and (C,B)"}; + Configurable cfgV5MaxMatches{"cfgV5MaxMatches", 50, "v5: max ME replacements per SE pair (after all cuts)"}; + Configurable cfgMixSeed{"cfgMixSeed", 0xdecafbadULL, "RNG seed for downsampling matches (deterministic)"}; Configurable centMin{"centMin", 0, "Minimum Centrality"}; Configurable centMax{"centMax", 80, "Maximum Centrality"}; Configurable rngSeed{"rngSeed", 12345, "Seed for random mixing (reproducible)"}; std::mt19937 rng{12345}; + Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; + ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10}, "Mixing bins - z-vertex"}; + ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0, 110}, "Mixing bins - centrality"}; + Configurable etaMix{"etaMix", 0.1, "Eta cut on event mixing"}; + Configurable ptMix{"ptMix", 0.1, "Pt cut on event mixing"}; + Configurable phiMix{"phiMix", 0.1, "Phi cut on event mixing"}; + Configurable massMix{"massMix", 0.0028, "Masscut on event mixing"}; + Configurable userapidity{"userapidity", 1, "Use Rapidity for mixing"}; + // Lambda selection //////////// Configurable harmonic{"harmonic", 1, "Harmonic phi"}; Configurable harmonicDphi{"harmonicDphi", 2, "Harmonic delta phi"}; @@ -115,17 +258,11 @@ struct lambdaspincorrderived { Configurable MassMin{"MassMin", 1.09, "V0 Mass minimum"}; Configurable MassMax{"MassMax", 1.14, "V0 Mass maximum"}; Configurable rapidity{"rapidity", 0.5, "Rapidity cut on lambda"}; + Configurable v0etaMixBuffer{"v0etaMixBuffer", 0.8, "Eta cut on mix event buffer"}; Configurable v0eta{"v0eta", 0.8, "Eta cut on lambda"}; // Event Mixing Configurable cosDef{"cosDef", 1, "Defination of cos"}; - Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; - ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10}, "Mixing bins - z-vertex"}; - ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0, 110}, "Mixing bins - centrality"}; - Configurable etaMix{"etaMix", 0.1, "Eta cut on event mixing"}; - Configurable ptMix{"ptMix", 0.1, "Pt cut on event mixing"}; - Configurable phiMix{"phiMix", 0.1, "Phi cut on event mixing"}; - Configurable massMix{"massMix", 0.0028, "Masscut on event mixing"}; ConfigurableAxis ax_dphi_h{"ax_dphi_h", {VARIABLE_WIDTH, 0.0, 2.0 * TMath::Pi()}, "Δφ_h"}; ConfigurableAxis ax_deta{"ax_deta", {VARIABLE_WIDTH, -1.0, 1.0}, "Δη"}; @@ -148,6 +285,7 @@ struct lambdaspincorrderived { void init(o2::framework::InitContext&) { + histos.add("hPtRadiusV0", "V0 QA;#it{p}_{T}^{V0} (GeV/#it{c});V0 decay radius (cm)", kTH2F, {{100, 0.0, 10.0}, {120, 0.0, 45.0}}); histos.add("hPtYSame", "hPtYSame", kTH2F, {{100, 0.0, 10.0}, {200, -1.0, 1.0}}); histos.add("hPtYMix", "hPtYMix", kTH2F, {{100, 0.0, 10.0}, {200, -1.0, 1.0}}); histos.add("hCentrality", "Centrality distribution", kTH1F, {{configThnAxisCentrality}}); @@ -156,6 +294,9 @@ struct lambdaspincorrderived { histos.add("ptCent", "ptCent", HistType::kTH2D, {{100, 0.0, 10.0}, {8, 0.0, 80.0}}, true); histos.add("etaCent", "etaCent", HistType::kTH2D, {{32, -0.8, 0.8}, {8, 0.0, 80.0}}, true); + histos.add("hCentPairTypeSE", "SE pair-weighted centrality;Centrality;PairType", kTH2D, {{110, 0.0, 110.0}, {4, -0.5, 3.5}}); + histos.add("hCentPairTypeME", "ME pair-weighted centrality;Centrality;PairType", kTH2D, {{110, 0.0, 110.0}, {4, -0.5, 3.5}}); + // --- 3D SE/ME pair-space maps per category (LL, LAL, ALL, ALAL) histos.add("SE_LL", "SE pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); histos.add("SE_LAL", "SE pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); @@ -246,6 +387,9 @@ struct lambdaspincorrderived { hweight32 = ccdb->getForTimeStamp(ConfWeightPathALL2.value, cfgCcdbParam.nolaterthan.value); hweight42 = ccdb->getForTimeStamp(ConfWeightPathALAL2.value, cfgCcdbParam.nolaterthan.value); } + if (!ConfWeightPathCentPair.value.empty()) { + hweightCentPair = ccdb->getForTimeStamp(ConfWeightPathCentPair.value, cfgCcdbParam.nolaterthan.value); + } } template @@ -288,36 +432,213 @@ struct lambdaspincorrderived { return true; } + template + bool selectionV0Buffer(T const& candidate) + { + auto particle = ROOT::Math::PtEtaPhiMVector(candidate.lambdaPt(), candidate.lambdaEta(), candidate.lambdaPhi(), candidate.lambdaMass()); + + if (std::abs(particle.Rapidity()) > rapidity || std::abs(particle.Eta()) > v0etaMixBuffer) { + return false; + } + if (candidate.lambdaMass() < MassMin || candidate.lambdaMass() > MassMax) { + return false; + } + if (candidate.v0Cospa() < cosPA) { + return false; + } + if (checkDoubleStatus && candidate.doubleStatus()) { + return false; + } + if (candidate.v0Radius() > radiusMax) { + return false; + } + if (candidate.v0Radius() < radiusMin) { + return false; + } + if (candidate.dcaBetweenDaughter() > dcaDaughters) { + return false; + } + if (candidate.v0Status() == 0 && (std::abs(candidate.dcaPositive()) < dcaProton || std::abs(candidate.dcaNegative()) < dcaPion)) { + return false; + } + if (candidate.v0Status() == 1 && (std::abs(candidate.dcaPositive()) < dcaPion || std::abs(candidate.dcaNegative()) < dcaProton)) { + return false; + } + if (candidate.lambdaPt() < ptMinMixBuffer) { + return false; + } + if (candidate.lambdaPt() > ptMaxMixBuffer) { + return false; + } + return true; + } + + template + bool selectionV0BufferMC(T const& candidate) + { + auto particle = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate), + mcacc::lamEta(candidate), + mcacc::lamPhi(candidate), + mcacc::lamMass(candidate)); + + if (std::abs(particle.Rapidity()) > rapidity || std::abs(particle.Eta()) > v0etaMixBuffer) { + return false; + } + if (mcacc::lamMass(candidate) < MassMin || mcacc::lamMass(candidate) > MassMax) { + return false; + } + if (mcacc::v0CosPA(candidate) < cosPA) { + return false; + } + if (checkDoubleStatus && mcacc::doubleStatus(candidate)) { + return false; + } + if (mcacc::v0Radius(candidate) > radiusMax) { + return false; + } + if (mcacc::v0Radius(candidate) < radiusMin) { + return false; + } + if (mcacc::dcaDau(candidate) > dcaDaughters) { + return false; + } + if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < dcaProton || std::abs(mcacc::dcaNeg(candidate)) < dcaPion)) { + return false; + } + if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < dcaPion || std::abs(mcacc::dcaNeg(candidate)) < dcaProton)) { + return false; + } + if (mcacc::lamPt(candidate) < ptMinMixBuffer) { + return false; + } + if (mcacc::lamPt(candidate) > ptMaxMixBuffer) { + return false; + } + return true; + } + template - bool checkKinematics(T1 const& candidate1, T2 const& candidate2) + bool checkKinematics(T1 const& c1, T2 const& c2) { - if (candidate1.v0Status() != candidate2.v0Status()) { + if (c1.v0Status() != c2.v0Status()) { + return false; + } + + if (std::abs(c1.lambdaPt() - c2.lambdaPt()) > ptMix) { + return false; + } + + if (!userapidity) { + if (std::abs(c1.lambdaEta() - c2.lambdaEta()) > etaMix) { + return false; + } + } else { + const auto l1 = ROOT::Math::PtEtaPhiMVector(c1.lambdaPt(), c1.lambdaEta(), c1.lambdaPhi(), c1.lambdaMass()); + const auto l2 = ROOT::Math::PtEtaPhiMVector(c2.lambdaPt(), c2.lambdaEta(), c2.lambdaPhi(), c2.lambdaMass()); + if (std::abs(l1.Rapidity() - l2.Rapidity()) > etaMix) { // etaMix used as Δy + return false; + } + } + + const float dphi = deltaPhiMinusPiToPi((float)c1.lambdaPhi(), (float)c2.lambdaPhi()); + if (std::abs(dphi) > phiMix) { return false; } - if (std::abs(candidate1.lambdaPt() - candidate2.lambdaPt()) > ptMix) { + + if (std::abs(c1.lambdaMass() - c2.lambdaMass()) > massMix) { return false; } - if (std::abs(candidate1.lambdaEta() - candidate2.lambdaEta()) > etaMix) { + + return true; + } + + template + bool checkPairKinematics(TA const& A, TB const& B, TC const& C) + { + if (!usePairKineMatch) { + return true; + } + + const auto lA = ROOT::Math::PtEtaPhiMVector(A.lambdaPt(), A.lambdaEta(), A.lambdaPhi(), A.lambdaMass()); + const auto lB = ROOT::Math::PtEtaPhiMVector(B.lambdaPt(), B.lambdaEta(), B.lambdaPhi(), B.lambdaMass()); + const auto lC = ROOT::Math::PtEtaPhiMVector(C.lambdaPt(), C.lambdaEta(), C.lambdaPhi(), C.lambdaMass()); + + // relative pT inside the pair: |pT1 - pT2| + const float dPtAB = std::abs(A.lambdaPt() - B.lambdaPt()); + const float dPtCB = std::abs(C.lambdaPt() - B.lambdaPt()); + if (std::abs(dPtAB - dPtCB) > ptMix) { return false; } - if (std::abs(RecoDecay::constrainAngle(RecoDecay::constrainAngle(candidate1.lambdaPhi(), 0.f, harmonic) - RecoDecay::constrainAngle(candidate2.lambdaPhi(), 0.f, harmonic), -TMath::Pi(), 1)) > phiMix) { + + // relative longitudinal kinematics: |Δy| or |Δη| + if (userapidity) { + const float dYAB = std::abs(lA.Rapidity() - lB.Rapidity()); + const float dYCB = std::abs(lC.Rapidity() - lB.Rapidity()); + if (std::abs(dYAB - dYCB) > etaMix) { + return false; + } + } else { + const float dEtaAB = std::abs(A.lambdaEta() - B.lambdaEta()); + const float dEtaCB = std::abs(C.lambdaEta() - B.lambdaEta()); + if (std::abs(dEtaAB - dEtaCB) > etaMix) { + return false; + } + } + + // relative azimuth inside the pair: |Δφ| + const float dPhiAB = std::abs(deltaPhiMinusPiToPi((float)A.lambdaPhi(), (float)B.lambdaPhi())); + const float dPhiCB = std::abs(deltaPhiMinusPiToPi((float)C.lambdaPhi(), (float)B.lambdaPhi())); + if (std::abs(dPhiAB - dPhiCB) > phiMix) { return false; } - /*if (std::abs(RecoDecay::constrainAngle(candidate1.lambdaPhi(), 0.0F, harmonic) - RecoDecay::constrainAngle(candidate2.lambdaPhi(), 0.0F, harmonic)) > phiMix) { + + return true; + } + template + bool checkPairKinematicsMC(TA const& A, TB const& B, TC const& C) + { + if (!usePairKineMatch) { + return true; + } + + const auto lA = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(A), mcacc::lamEta(A), mcacc::lamPhi(A), mcacc::lamMass(A)); + const auto lB = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(B), mcacc::lamEta(B), mcacc::lamPhi(B), mcacc::lamMass(B)); + const auto lC = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(C), mcacc::lamEta(C), mcacc::lamPhi(C), mcacc::lamMass(C)); + + const float dPtAB = std::abs(mcacc::lamPt(A) - mcacc::lamPt(B)); + const float dPtCB = std::abs(mcacc::lamPt(C) - mcacc::lamPt(B)); + if (std::abs(dPtAB - dPtCB) > ptMix) { return false; - }*/ - if (std::abs(candidate1.lambdaMass() - candidate2.lambdaMass()) > massMix) { + } + + if (userapidity) { + const float dYAB = std::abs(lA.Rapidity() - lB.Rapidity()); + const float dYCB = std::abs(lC.Rapidity() - lB.Rapidity()); + if (std::abs(dYAB - dYCB) > etaMix) { + return false; + } + } else { + const float dEtaAB = std::abs(mcacc::lamEta(A) - mcacc::lamEta(B)); + const float dEtaCB = std::abs(mcacc::lamEta(C) - mcacc::lamEta(B)); + if (std::abs(dEtaAB - dEtaCB) > etaMix) { + return false; + } + } + + const float dPhiAB = std::abs(deltaPhiMinusPiToPi((float)mcacc::lamPhi(A), (float)mcacc::lamPhi(B))); + const float dPhiCB = std::abs(deltaPhiMinusPiToPi((float)mcacc::lamPhi(C), (float)mcacc::lamPhi(B))); + if (std::abs(dPhiAB - dPhiCB) > phiMix) { return false; } + return true; } void fillHistograms(int tag1, int tag2, const ROOT::Math::PtEtaPhiMVector& particle1, const ROOT::Math::PtEtaPhiMVector& particle2, const ROOT::Math::PtEtaPhiMVector& daughpart1, const ROOT::Math::PtEtaPhiMVector& daughpart2, - int datatype, float mixpairweight) + int datatype, float mixpairweight, int replacedLeg = 1) { - auto lambda1Mass = 0.0; auto lambda2Mass = 0.0; if (!usePDGM) { @@ -327,47 +648,43 @@ struct lambdaspincorrderived { lambda1Mass = o2::constants::physics::MassLambda; lambda2Mass = o2::constants::physics::MassLambda; } + auto particle1Dummy = ROOT::Math::PtEtaPhiMVector(particle1.Pt(), particle1.Eta(), particle1.Phi(), lambda1Mass); auto particle2Dummy = ROOT::Math::PtEtaPhiMVector(particle2.Pt(), particle2.Eta(), particle2.Phi(), lambda2Mass); auto pairDummy = particle1Dummy + particle2Dummy; - ROOT::Math::Boost boostPairToCM{pairDummy.BoostToCM()}; // boosting vector for pair CM + ROOT::Math::Boost boostPairToCM{pairDummy.BoostToCM()}; - // Step1: Boosting both Lambdas to Lambda-Lambda pair rest frame + // Step1: Boost both Lambdas to pair rest frame auto lambda1CM = boostPairToCM(particle1Dummy); auto lambda2CM = boostPairToCM(particle2Dummy); - // Step 2: Boost Each Lambda to its Own Rest Frame + // Step2: Boost each Lambda to its own rest frame ROOT::Math::Boost boostLambda1ToCM{lambda1CM.BoostToCM()}; ROOT::Math::Boost boostLambda2ToCM{lambda2CM.BoostToCM()}; - // Also boost the daughter protons to the same frame - auto proton1pairCM = boostPairToCM(daughpart1); // proton1 to pair CM - auto proton2pairCM = boostPairToCM(daughpart2); // proton2 to pair CM + // Also boost daughter protons to pair CM + auto proton1pairCM = boostPairToCM(daughpart1); + auto proton2pairCM = boostPairToCM(daughpart2); - // Boost protons into their respective Lambda rest frames + // Then into each Lambda rest frame auto proton1LambdaRF = boostLambda1ToCM(proton1pairCM); auto proton2LambdaRF = boostLambda2ToCM(proton2pairCM); - // --- STAR-style Δθ (as written: dot product of proton directions in their own Λ RFs) --- - - // Boost each proton into its parent's rest frame - ROOT::Math::Boost boostL1_LabToRF{particle1Dummy.BoostToCM()}; // Λ1 velocity in lab - ROOT::Math::Boost boostL2_LabToRF{particle2Dummy.BoostToCM()}; // Λ2 velocity in lab + // STAR-style alternative + ROOT::Math::Boost boostL1_LabToRF{particle1Dummy.BoostToCM()}; + ROOT::Math::Boost boostL2_LabToRF{particle2Dummy.BoostToCM()}; auto p1_LRF = boostL1_LabToRF(daughpart1); auto p2_LRF = boostL2_LabToRF(daughpart2); - // Unit 3-vectors (in different rest frames!) TVector3 u1 = TVector3(p1_LRF.Px(), p1_LRF.Py(), p1_LRF.Pz()).Unit(); TVector3 u2 = TVector3(p2_LRF.Px(), p2_LRF.Py(), p2_LRF.Pz()).Unit(); - // Proton unit directions in Λ rest frames TVector3 k1(proton1LambdaRF.Px(), proton1LambdaRF.Py(), proton1LambdaRF.Pz()); k1 = k1.Unit(); TVector3 k2(proton2LambdaRF.Px(), proton2LambdaRF.Py(), proton2LambdaRF.Pz()); k2 = k2.Unit(); - // STAR-style cosΔθ definition double cosDeltaTheta_STAR_naive = u1.Dot(u2); if (cosDeltaTheta_STAR_naive > 1.0) cosDeltaTheta_STAR_naive = 111.0; @@ -380,12 +697,7 @@ struct lambdaspincorrderived { if (cosDeltaTheta_hel < -1.0) cosDeltaTheta_hel = -111.0; - auto cosThetaDiff = -999.0; - if (cosDef == 0) { - cosThetaDiff = cosDeltaTheta_STAR_naive; - } else { - cosThetaDiff = cosDeltaTheta_hel; - } + double cosThetaDiff = (cosDef == 0) ? cosDeltaTheta_STAR_naive : cosDeltaTheta_hel; double pt1 = particle1.Pt(); double dphi1 = RecoDecay::constrainAngle(particle1.Phi(), 0.0F, harmonic); @@ -395,9 +707,7 @@ struct lambdaspincorrderived { double dphi2 = RecoDecay::constrainAngle(particle2.Phi(), 0.0F, harmonic); double deta2 = particle2.Eta(); - // double deta_pair = std::abs(deta1 - deta2); double dphi_pair = RecoDecay::constrainAngle(dphi1 - dphi2, -TMath::Pi(), harmonicDphi); - // double deltaR = TMath::Sqrt(deta_pair * deta_pair + dphi_pair * dphi_pair); double deltaRap = std::abs(particle1.Rapidity() - particle2.Rapidity()); double deltaR = TMath::Sqrt(deltaRap * deltaRap + dphi_pair * dphi_pair); @@ -421,65 +731,103 @@ struct lambdaspincorrderived { } if (datatype == 0) { - mixpairweight = 1.0; - histos.fill(HIST("hPtYSame"), particle1.Pt(), particle1.Rapidity(), mixpairweight); + const double weight = 1.0; + if (tag1 == 0 && tag2 == 0) { - histos.fill(HIST("SE_LL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("SE_LL2"), dphi2, deta2, pt2, mixpairweight); - histos.fill(HIST("hSparseLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); - histos.fill(HIST("hSparseLambdaLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), mixpairweight); + if (!userapidity) { + histos.fill(HIST("hPtYSame"), particle1.Pt(), particle1.Rapidity(), weight); + histos.fill(HIST("SE_LL"), dphi1, deta1, pt1, weight); + histos.fill(HIST("SE_LL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("hPtYSame"), particle1.Pt(), particle1.Rapidity(), weight); + histos.fill(HIST("SE_LL"), dphi1, particle1.Rapidity(), pt1, weight); + histos.fill(HIST("SE_LL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + histos.fill(HIST("hSparseLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + histos.fill(HIST("hSparseLambdaLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { - histos.fill(HIST("hSparseRapLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); - histos.fill(HIST("hSparsePhiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); - histos.fill(HIST("hSparsePairMassLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + histos.fill(HIST("hSparseRapLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } } else if (tag1 == 0 && tag2 == 1) { - histos.fill(HIST("SE_LAL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("SE_LAL2"), dphi2, deta2, pt2, mixpairweight); - histos.fill(HIST("hSparseLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); - histos.fill(HIST("hSparseLambdaAntiLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), mixpairweight); + if (!userapidity) { + histos.fill(HIST("SE_LAL"), dphi1, deta1, pt1, weight); + histos.fill(HIST("SE_LAL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("SE_LAL"), dphi1, particle1.Rapidity(), pt1, weight); + histos.fill(HIST("SE_LAL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + histos.fill(HIST("hSparseLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + histos.fill(HIST("hSparseLambdaAntiLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { - histos.fill(HIST("hSparseRapLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); - histos.fill(HIST("hSparsePhiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); - histos.fill(HIST("hSparsePairMassLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + histos.fill(HIST("hSparseRapLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } } else if (tag1 == 1 && tag2 == 0) { - histos.fill(HIST("hSparseAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); - histos.fill(HIST("hSparseAntiLambdaLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), mixpairweight); - histos.fill(HIST("SE_ALL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("SE_ALL2"), dphi2, deta2, pt2, mixpairweight); + if (!userapidity) { + histos.fill(HIST("SE_ALL"), dphi1, deta1, pt1, weight); + histos.fill(HIST("SE_ALL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("SE_ALL"), dphi1, particle1.Rapidity(), pt1, weight); + histos.fill(HIST("SE_ALL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + histos.fill(HIST("hSparseAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + histos.fill(HIST("hSparseAntiLambdaLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { - histos.fill(HIST("hSparseRapAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); - histos.fill(HIST("hSparsePhiAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); - histos.fill(HIST("hSparsePairMassAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + histos.fill(HIST("hSparseRapAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } } else if (tag1 == 1 && tag2 == 1) { - histos.fill(HIST("hSparseAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); - histos.fill(HIST("hSparseAntiLambdaAntiLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), mixpairweight); - histos.fill(HIST("SE_ALAL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("SE_ALAL2"), dphi2, deta2, pt2, mixpairweight); + if (!userapidity) { + histos.fill(HIST("SE_ALAL"), dphi1, deta1, pt1, weight); + histos.fill(HIST("SE_ALAL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("SE_ALAL"), dphi1, particle1.Rapidity(), pt1, weight); + histos.fill(HIST("SE_ALAL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + histos.fill(HIST("hSparseAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + histos.fill(HIST("hSparseAntiLambdaAntiLambdaAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { - histos.fill(HIST("hSparseRapAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); - histos.fill(HIST("hSparsePhiAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); - histos.fill(HIST("hSparsePairMassAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + histos.fill(HIST("hSparseRapAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } } + } else if (datatype == 1) { double weight = mixpairweight; + if (useweight) { - if (usebothweight) { - weight = mixpairweight / (epsWeight1 * epsWeight2); - } else { - weight = mixpairweight / (epsWeight1); + const double epsWeightReplaced = (replacedLeg == 2) ? epsWeight2 : epsWeight1; + if (!std::isfinite(epsWeightReplaced) || epsWeightReplaced <= 0.0) { + return; } + weight = mixpairweight / epsWeightReplaced; } - if (weight <= 0.0) { - weight = 1.0; + + if (!std::isfinite(weight) || weight <= 0.0) { + return; } - histos.fill(HIST("hPtYMix"), particle1.Pt(), particle1.Rapidity(), weight); + if (tag1 == 0 && tag2 == 0) { - histos.fill(HIST("ME_LL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_LL2"), dphi2, deta2, pt2, mixpairweight); + if (replacedLeg == 1) { + if (!userapidity) { + histos.fill(HIST("hPtYMix"), particle1.Pt(), particle1.Rapidity(), weight); + histos.fill(HIST("ME_LL"), dphi1, deta1, pt1, weight); + } else { + histos.fill(HIST("hPtYMix"), particle1.Pt(), particle1.Rapidity(), weight); + histos.fill(HIST("ME_LL"), dphi1, particle1.Rapidity(), pt1, weight); + } + } else { + if (!userapidity) { + histos.fill(HIST("ME_LL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("ME_LL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + } histos.fill(HIST("hSparseLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); histos.fill(HIST("hSparseLambdaLambdaMixedAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { @@ -487,9 +835,21 @@ struct lambdaspincorrderived { histos.fill(HIST("hSparsePhiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); histos.fill(HIST("hSparsePairMassLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } + } else if (tag1 == 0 && tag2 == 1) { - histos.fill(HIST("ME_LAL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_LAL2"), dphi2, deta2, pt2, mixpairweight); + if (replacedLeg == 1) { + if (!userapidity) { + histos.fill(HIST("ME_LAL"), dphi1, deta1, pt1, weight); + } else { + histos.fill(HIST("ME_LAL"), dphi1, particle1.Rapidity(), pt1, weight); + } + } else { + if (!userapidity) { + histos.fill(HIST("ME_LAL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("ME_LAL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + } histos.fill(HIST("hSparseLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); histos.fill(HIST("hSparseLambdaAntiLambdaMixedAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { @@ -497,9 +857,21 @@ struct lambdaspincorrderived { histos.fill(HIST("hSparsePhiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); histos.fill(HIST("hSparsePairMassLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } + } else if (tag1 == 1 && tag2 == 0) { - histos.fill(HIST("ME_ALL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_ALL2"), dphi2, deta2, pt2, mixpairweight); + if (replacedLeg == 1) { + if (!userapidity) { + histos.fill(HIST("ME_ALL"), dphi1, deta1, pt1, weight); + } else { + histos.fill(HIST("ME_ALL"), dphi1, particle1.Rapidity(), pt1, weight); + } + } else { + if (!userapidity) { + histos.fill(HIST("ME_ALL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("ME_ALL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + } histos.fill(HIST("hSparseAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); histos.fill(HIST("hSparseAntiLambdaLambdaMixedAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { @@ -507,9 +879,21 @@ struct lambdaspincorrderived { histos.fill(HIST("hSparsePhiAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); histos.fill(HIST("hSparsePairMassAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } + } else if (tag1 == 1 && tag2 == 1) { - histos.fill(HIST("ME_ALAL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_ALAL2"), dphi2, deta2, pt2, mixpairweight); + if (replacedLeg == 1) { + if (!userapidity) { + histos.fill(HIST("ME_ALAL"), dphi1, deta1, pt1, weight); + } else { + histos.fill(HIST("ME_ALAL"), dphi1, particle1.Rapidity(), pt1, weight); + } + } else { + if (!userapidity) { + histos.fill(HIST("ME_ALAL2"), dphi2, deta2, pt2, weight); + } else { + histos.fill(HIST("ME_ALAL2"), dphi2, particle2.Rapidity(), pt2, weight); + } + } histos.fill(HIST("hSparseAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); histos.fill(HIST("hSparseAntiLambdaAntiLambdaMixedAnalysis"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, deltaRap, std::abs(dphi_pair), weight); if (useAdditionalHisto) { @@ -520,6 +904,18 @@ struct lambdaspincorrderived { } } } + static inline int pairTypeCode(int tag1, int tag2) + { + if (tag1 == 0 && tag2 == 0) { + return 0; // LL + } else if (tag1 == 0 && tag2 == 1) { + return 1; // LAL + } else if (tag1 == 1 && tag2 == 0) { + return 2; // ALL + } else { + return 3; // ALAL + } + } ROOT::Math::PtEtaPhiMVector lambda0, proton0; ROOT::Math::PtEtaPhiMVector lambda, proton; @@ -537,6 +933,7 @@ struct lambdaspincorrderived { if (!selectionV0(v0)) { continue; } + histos.fill(HIST("hPtRadiusV0"), v0.lambdaPt(), v0.v0Radius()); histos.fill(HIST("ptCent"), v0.lambdaPt(), centrality); histos.fill(HIST("etaCent"), v0.lambdaEta(), centrality); proton = ROOT::Math::PtEtaPhiMVector(v0.protonPt(), v0.protonEta(), v0.protonPhi(), o2::constants::physics::MassProton); @@ -564,6 +961,8 @@ struct lambdaspincorrderived { proton2 = ROOT::Math::PtEtaPhiMVector(v02.protonPt(), v02.protonEta(), v02.protonPhi(), o2::constants::physics::MassProton); lambda2 = ROOT::Math::PtEtaPhiMVector(v02.lambdaPt(), v02.lambdaEta(), v02.lambdaPhi(), v02.lambdaMass()); histos.fill(HIST("deltaPhiSame"), RecoDecay::constrainAngle(v0.lambdaPhi() - v02.lambdaPhi(), -TMath::Pi(), harmonicDphi)); + const int ptype = pairTypeCode(v0.v0Status(), v02.v0Status()); + histos.fill(HIST("hCentPairTypeSE"), collision.cent(), ptype, 1.0); if (v0.v0Status() == 0 && v02.v0Status() == 0) { fillHistograms(0, 0, lambda, lambda2, proton, proton2, 0, 1.0); } @@ -586,283 +985,259 @@ struct lambdaspincorrderived { using BinningType = ColumnBinningPolicy; BinningType colBinning{{CfgVtxBins, CfgMultBins}, true}; Preslice tracksPerCollisionV0 = aod::lambdapair::lambdaeventId; - void processME(EventCandidates const& collisions, AllTrackCandidates const& V0s) + + void processMEV3(EventCandidates const& collisions, AllTrackCandidates const& V0s) { - auto collOldIndex = -999; - std::vector t1Used; - for (auto& [collision1, collision2] : selfCombinations(colBinning, nEvtMixing, -1, collisions, collisions)) { - // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.index(), collision2.index()); - // auto centrality = collision1.cent(); - auto groupV01 = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); - auto groupV02 = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); - auto groupV03 = V0s.sliceBy(tracksPerCollisionV0, collision2.index()); - auto collNewIndex = collision1.index(); - // LOGF(info, "Mixed event collisions: (%d, %d)", collNewIndex, collOldIndex); - if (collOldIndex != collNewIndex) { - t1Used.resize(groupV01.size(), false); - // std::fill(t1Used.begin(), t1Used.end(), false); - // std::vector t1Used(groupV01.size(), false); // <-- reset here - collOldIndex = collNewIndex; + auto nBins = colBinning.getAllBinsCount(); + std::vector>> eventPools(nBins); + + for (auto& collision1 : collisions) { + const int bin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); + if (bin < 0) { + continue; + } + + auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + + // if pool empty, push and continue + if (eventPools[bin].empty()) { + eventPools[bin].emplace_back(collision1.index(), std::move(poolA)); + if ((int)eventPools[bin].size() > nEvtMixing) { + eventPools[bin].pop_front(); + } + continue; } - for (auto& [t1, t3] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV03))) { - if (t1Used[t1.index()]) { + + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0(t1) || !selectionV0(t2)) { continue; } - if (!checkKinematics(t1, t3)) { + if (t2.index() <= t1.index()) { continue; } - if (!selectionV0(t1)) { + + if (t1.protonIndex() == t2.protonIndex()) { continue; } - if (!selectionV0(t3)) { + if (t1.pionIndex() == t2.pionIndex()) { continue; } - t1Used[t1.index()] = true; - for (const auto& t2 : groupV02) { - if (t2.index() <= t1.index()) { - continue; - } - if (!selectionV0(t2)) { - continue; - } - if (t1.protonIndex() == t2.protonIndex()) { - continue; - } - if (t1.pionIndex() == t2.pionIndex()) { - continue; - } - proton = ROOT::Math::PtEtaPhiMVector(t3.protonPt(), t3.protonEta(), t3.protonPhi(), o2::constants::physics::MassProton); - lambda = ROOT::Math::PtEtaPhiMVector(t3.lambdaPt(), t3.lambdaEta(), t3.lambdaPhi(), t3.lambdaMass()); - proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); - lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); - histos.fill(HIST("deltaPhiMix"), RecoDecay::constrainAngle(t3.lambdaPhi() - t2.lambdaPhi(), -TMath::Pi(), harmonicDphi)); - if (t3.v0Status() == 0 && t2.v0Status() == 0) { - fillHistograms(0, 0, lambda, lambda2, proton, proton2, 1, 1.0); - } - if (t3.v0Status() == 0 && t2.v0Status() == 1) { - fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, 1.0); - } - if (t3.v0Status() == 1 && t2.v0Status() == 0) { - fillHistograms(1, 0, lambda, lambda2, proton, proton2, 1, 1.0); - } - if (t3.v0Status() == 1 && t2.v0Status() == 1) { - fillHistograms(1, 1, lambda, lambda2, proton, proton2, 1, 1.0); - } + if (t1.protonIndex() == t2.pionIndex()) { + continue; } - } // replacement track pair - } // collision pair - } - PROCESS_SWITCH(lambdaspincorrderived, processME, "Process data ME", false); - - void processMEV2(EventCandidates const& collisions, AllTrackCandidates const& V0s) - { - auto nBins = colBinning.getAllBinsCount(); - std::vector>> eventPools(nBins); - - for (auto& collision1 : collisions) { - int bin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); - auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); - // float centrality = collision1.cent(); - - // <<< CHANGED: map old collision index → set of (t2.idx, t3.idx) we've already filled - std::unordered_map>> seenMap; - - for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { - if (!selectionV0(t1) || !selectionV0(t2)) - continue; - if (t2.index() <= t1.index()) - continue; - if (t1.protonIndex() == t2.protonIndex()) + if (t1.pionIndex() == t2.protonIndex()) { continue; - if (t1.pionIndex() == t2.pionIndex()) - continue; - - int mixes = 0; - for (auto it = eventPools[bin].rbegin(); it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { - int collision2idx = it->first; - AllTrackCandidates& poolB = it->second; - - int nRepl = 0; - for (auto& t3 : poolB) { - if (selectionV0(t3) && checkKinematics(t1, t3)) { - ++nRepl; - } - } - if (nRepl == 0) - continue; - float invN = 1.0f / static_cast(nRepl); - - for (auto& t3 : poolB) { - if (!(selectionV0(t3) && checkKinematics(t1, t3))) { - continue; - } - if (collision1.index() == collision2idx) { - continue; - } - - // <<< CHANGED: dedupe (t2, t3) pairs per prior collision - auto key = std::make_pair(t2.index(), t3.index()); - auto& seen = seenMap[collision2idx]; - if (!seen.insert(key).second) { - continue; - } - - // reconstruct 4-vectors - proton = ROOT::Math::PtEtaPhiMVector(t3.protonPt(), t3.protonEta(), t3.protonPhi(), o2::constants::physics::MassProton); - lambda = ROOT::Math::PtEtaPhiMVector(t3.lambdaPt(), t3.lambdaEta(), t3.lambdaPhi(), t3.lambdaMass()); - proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); - lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); - - float dPhi = RecoDecay::constrainAngle(RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - RecoDecay::constrainAngle(lambda2.Phi(), 0.0, harmonic), -TMath::Pi(), harmonicDphi); - histos.fill(HIST("deltaPhiMix"), dPhi, invN); - - if (t3.v0Status() == 0 && t2.v0Status() == 0) { - fillHistograms(0, 0, lambda, lambda2, proton, proton2, 1, invN); - } - if (t3.v0Status() == 0 && t2.v0Status() == 1) { - fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, invN); - } - if (t3.v0Status() == 1 && t2.v0Status() == 0) { - fillHistograms(1, 0, lambda, lambda2, proton, proton2, 1, invN); - } - if (t3.v0Status() == 1 && t2.v0Status() == 1) { - fillHistograms(1, 1, lambda, lambda2, proton, proton2, 1, invN); - } - } - } // end mixing-event loop - } // end same-event pair loop - - auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); - eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); - if (static_cast(eventPools[bin].size()) > nEvtMixing) { - eventPools[bin].pop_front(); - } - } // end primary-event loop - } - PROCESS_SWITCH(lambdaspincorrderived, processMEV2, "Process data ME", false); - - void processMEV3(EventCandidates const& collisions, AllTrackCandidates const& V0s) - { - auto nBins = colBinning.getAllBinsCount(); - std::vector>> eventPools(nBins); - - for (auto& collision1 : collisions) { - const int bin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); - - // if pool empty, push and continue - if (eventPools[bin].empty()) { - auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); - eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); - if ((int)eventPools[bin].size() > nEvtMixing) - eventPools[bin].pop_front(); - continue; - } - - // current event slice - auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + } - // loop over SE unordered pairs (t1,t2) - for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { - if (!selectionV0(t1) || !selectionV0(t2)) - continue; - if (t2.index() <= t1.index()) - continue; - if (t1.protonIndex() == t2.protonIndex()) - continue; - if (t1.pionIndex() == t2.pionIndex()) - continue; - if (t1.protonIndex() == t2.pionIndex()) - continue; - if (t1.pionIndex() == t2.protonIndex()) - continue; + const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); + const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); - // scan prior events for replacements for t1 struct PV { AllTrackCandidates* pool; - int nRepl; + int nRepl1 = 0; + int nRepl2 = 0; }; + std::vector usable; int totalRepl = 0; int mixes = 0; - for (auto it = eventPools[bin].rbegin(); - it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { + for (auto it = eventPools[bin].rbegin(); it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { const int collision2idx = it->first; auto& poolB = it->second; - if (collision2idx == collision1.index()) + + if (collision2idx == collision1.index()) { continue; + } + + int nRepl1 = 0; + int nRepl2 = 0; - int nRepl = 0; for (auto& tX : poolB) { - if (!selectionV0(tX)) + if (!selectionV0(tX)) { continue; - if (checkKinematics(t1, tX)) - ++nRepl; + } + + if (doMixLeg1) { + if (checkKinematics(t1, tX) && checkPairKinematics(t1, t2, tX)) { + ++nRepl1; + } + } + + if (doMixLeg2) { + if (checkKinematics(t2, tX) && checkPairKinematics(t2, t1, tX)) { + ++nRepl2; + } + } } - if (nRepl > 0) { - usable.push_back(PV{&poolB, nRepl}); - totalRepl += nRepl; + + if (nRepl1 > 0 || nRepl2 > 0) { + usable.push_back(PV{&poolB, nRepl1, nRepl2}); + totalRepl += nRepl1 + nRepl2; } } - if (totalRepl == 0) + if (totalRepl <= 0) { continue; + } + const float wBase = 1.0f / static_cast(totalRepl); - // emit mixed pairs: tX replaces t1; t2 stays for (auto& pv : usable) { auto& poolB = *pv.pool; + for (auto& tX : poolB) { - if (!selectionV0(tX)) - continue; - if (!checkKinematics(t1, tX)) + if (!selectionV0(tX)) { continue; + } - auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), o2::constants::physics::MassProton); - auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()); - auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); - auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); + // -------- leg-1 replacement: (tX, t2) + if (doMixLeg1) { + if (checkKinematics(t1, tX) && checkPairKinematics(t1, t2, tX)) { + auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), + o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), + tX.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), + o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), + t2.lambdaMass()); + + const float dPhi = RecoDecay::constrainAngle( + RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - + RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), + -TMath::Pi(), harmonicDphi); + + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(tX.v0Status(), t2.v0Status(), + lambda, lambda2, proton, proton2, + 1, wBase, 1); + } + } - const float dPhi = RecoDecay::constrainAngle(RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), -TMath::Pi(), harmonicDphi); - histos.fill(HIST("deltaPhiMix"), dPhi, wBase); - fillHistograms(tX.v0Status(), t2.v0Status(), lambda, lambda2, proton, proton2, 1, wBase); + // -------- leg-2 replacement: (t1, tX) + if (doMixLeg2) { + if (checkKinematics(t2, tX) && checkPairKinematics(t2, t1, tX)) { + auto proton = ROOT::Math::PtEtaPhiMVector(t1.protonPt(), t1.protonEta(), t1.protonPhi(), + o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), + t1.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), + o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), + tX.lambdaMass()); + + const float dPhi = RecoDecay::constrainAngle( + RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - + RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), + -TMath::Pi(), harmonicDphi); + + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(t1.v0Status(), tX.v0Status(), + lambda, lambda2, proton, proton2, + 1, wBase, 2); + } + } } } } + // push current event into pool auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); - if ((int)eventPools[bin].size() > nEvtMixing) + if ((int)eventPools[bin].size() > nEvtMixing) { eventPools[bin].pop_front(); + } } } PROCESS_SWITCH(lambdaspincorrderived, processMEV3, "Process data ME (first-leg, pair-3D maps)", false); static constexpr int N_STATUS = 2; // v0Status ∈ {0,1} + struct MatchRef { + int64_t collisionIdx; + int64_t rowIndex; + }; + + static inline void limitMatchesToNEvents(std::vector& matches, int nMixEvents) + { + if (nMixEvents <= 0 || matches.empty()) { + return; + } + + std::vector kept; + kept.reserve(matches.size()); + + std::unordered_set usedEvents; + usedEvents.reserve(nMixEvents * 2); - struct MixBinner { - // constructed from the task's configurables; φ is assumed already constrained into [0, 2π) + for (const auto& m : matches) { + if (usedEvents.count(m.collisionIdx) || (int)usedEvents.size() < nMixEvents) { + kept.push_back(m); + usedEvents.insert(m.collisionIdx); + } + } + + matches.swap(kept); + } + + struct MixBinnerR { float ptMin, ptMax, ptStep; float etaMin, etaMax, etaStep; float phiMin, phiMax, phiStep; - // Mass binning: [1.09, 1.14) with 50 bins (1e-3 GeV/c^2) - static constexpr float mMin = 1.09f; - static constexpr float mMax = 1.14f; - static constexpr int nM_ = 1; - static constexpr float mStep = (mMax - mMin) / nM_; + float mMin, mMax, mStep; + int nM_; + + std::vector rEdges; + int nR_; int nPt_, nEta_, nPhi_; - MixBinner(float ptMin_, float ptMax_, float ptStep_, - float etaAbsMax, float etaStep_, - float phiStep_) - : ptMin(ptMin_), ptMax(ptMax_), ptStep(ptStep_), etaMin(-etaAbsMax), etaMax(+etaAbsMax), etaStep(etaStep_), phiMin(0.f), phiMax(static_cast(2.0 * TMath::Pi())), phiStep(phiStep_) + MixBinnerR(float ptMin_, float ptMax_, float ptStep_, + float etaAbsMax, float etaStep_, + float phiStep_, + float mMin_, float mMax_, int nMassBins_, + std::vector rEdges_) + : ptMin(ptMin_), + ptMax(ptMax_), + ptStep(ptStep_), + etaMin(-etaAbsMax), + etaMax(+etaAbsMax), + etaStep(etaStep_), + phiMin(-static_cast(TMath::Pi())), + phiMax(+static_cast(TMath::Pi())), + phiStep(phiStep_), + mMin(mMin_), + mMax(mMax_), + mStep(0.f), + nM_(std::max(1, nMassBins_)), + rEdges(std::move(rEdges_)), + nR_(0), + nPt_(0), + nEta_(0), + nPhi_(0) { ptStep = (ptStep > 0.f ? ptStep : 0.1f); etaStep = (etaStep > 0.f ? etaStep : 0.1f); phiStep = (phiStep > 0.f ? phiStep : 0.1f); + if (!(mMax > mMin)) { + mMin = 1.09f; + mMax = 1.14f; + } + mStep = (mMax - mMin) / static_cast(nM_); + if (!(mStep > 0.f)) { + nM_ = 5; + mMin = 1.09f; + mMax = 1.14f; + mStep = (mMax - mMin) / static_cast(nM_); + } + + if (rEdges.size() < 2) { + rEdges = {3.0, 5.0, 7.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0}; + } + nR_ = static_cast(rEdges.size()) - 1; + nPt_ = std::max(1, static_cast(std::floor((ptMax - ptMin) / ptStep + 0.5f))); nEta_ = std::max(1, static_cast(std::floor((etaMax - etaMin) / etaStep + 0.5f))); nPhi_ = std::max(1, static_cast(std::ceil((phiMax - phiMin) / phiStep))); @@ -872,221 +1247,1023 @@ struct lambdaspincorrderived { inline int nEta() const { return nEta_; } inline int nPhi() const { return nPhi_; } inline int nM() const { return nM_; } + inline int nR() const { return nR_; } inline int binFromValue(float v, float vmin, float step, int nBins) const { - if (!std::isfinite(v)) + if (!std::isfinite(v) || !std::isfinite(vmin) || !std::isfinite(step) || step <= 0.f || nBins <= 0) { return -1; + } const float x = (v - vmin) / step; int b = static_cast(std::floor(x + 1e-6f)); - if (b < 0) + if (b < 0) { return -1; - if (b >= nBins) - b = nBins - 1; // clamp exact-top edge + } + if (b >= nBins) { + b = nBins - 1; + } return b; } inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } - inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } // φ already constrained upstream + inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } inline int massBin(float m) const { return binFromValue(m, mMin, mStep, nM_); } - }; - struct BufferCand { - int64_t collisionIdx; // from col.index() - int64_t rowIndex; // global row id in V0s - uint8_t v0Status; - uint16_t ptBin, etaBin, phiBin, mBin; + inline int radiusBin(float r) const + { + if (!std::isfinite(r) || nR_ <= 0) { + return -1; + } + if (r < rEdges.front() || r >= rEdges.back()) { + return -1; + } + auto it = std::upper_bound(rEdges.begin(), rEdges.end(), static_cast(r)); + return static_cast(it - rEdges.begin()) - 1; + } }; - struct MatchRef { + struct BufferCandR { int64_t collisionIdx; int64_t rowIndex; + uint8_t v0Status; + uint16_t ptBin, etaBin, phiBin, mBin, rBin; }; - // 6D key: (colBin, status, pt, eta, phi, mass) - static inline size_t linearKey(int colBin, int statBin, - int ptBin, int etaBin, int phiBin, int mBin, - int nStatus, int nPt, int nEta, int nPhi, int nM) + static inline size_t linearKeyR(int colBin, int statBin, + int ptBin, int etaBin, int phiBin, int mBin, int rBin, + int nStatus, int nPt, int nEta, int nPhi, int nM, int nR) + { + return (((((((static_cast(colBin) * nStatus + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin) * nR + rBin)); + } + + // ------------------------------------- + // 2) MC-only selection + kinematics cuts + // ------------------------------------- + template + bool selectionV0MC(T const& candidate) + { + auto particle = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate), + mcacc::lamEta(candidate), + mcacc::lamPhi(candidate), + mcacc::lamMass(candidate)); + if (std::abs(particle.Rapidity()) > rapidity || std::abs(particle.Eta()) > v0eta) { + return false; + } + if (mcacc::lamMass(candidate) < MassMin || mcacc::lamMass(candidate) > MassMax) { + return false; + } + if (mcacc::v0CosPA(candidate) < cosPA) { + return false; + } + if (checkDoubleStatus && mcacc::doubleStatus(candidate)) { + return false; + } + if (mcacc::v0Radius(candidate) > radiusMax) { + return false; + } + if (mcacc::v0Radius(candidate) < radiusMin) { + return false; + } + if (mcacc::dcaDau(candidate) > dcaDaughters) { + return false; + } + if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < dcaProton || std::abs(mcacc::dcaNeg(candidate)) < dcaPion)) { + return false; + } + if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < dcaPion || std::abs(mcacc::dcaNeg(candidate)) < dcaProton)) { + return false; + } + if (mcacc::lamPt(candidate) < ptMin) { + return false; + } + if (mcacc::lamPt(candidate) > ptMax) { + return false; + } + return true; + } + + template + bool checkKinematicsMC(T1 const& candidate1, T2 const& candidate2) + { + // keep same species/status + if (mcacc::v0Status(candidate1) != mcacc::v0Status(candidate2)) { + return false; + } + + // pT window + if (std::abs(mcacc::lamPt(candidate1) - mcacc::lamPt(candidate2)) > ptMix) { + return false; + } + + // eta or rapidity window (etaMix used as Δη or Δy) + if (!userapidity) { + if (std::abs(mcacc::lamEta(candidate1) - mcacc::lamEta(candidate2)) > etaMix) { + return false; + } + } else { + const auto l1 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate1), mcacc::lamEta(candidate1), + mcacc::lamPhi(candidate1), mcacc::lamMass(candidate1)); + const auto l2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate2), mcacc::lamEta(candidate2), + mcacc::lamPhi(candidate2), mcacc::lamMass(candidate2)); + if (std::abs(l1.Rapidity() - l2.Rapidity()) > etaMix) { + return false; + } + } + + // delta-phi window (wrapped) + const float dphi = deltaPhiMinusPiToPi((float)mcacc::lamPhi(candidate1), + (float)mcacc::lamPhi(candidate2)); + if (std::abs(dphi) > phiMix) { + return false; + } + + // mass window (optional but consistent with data) + if (std::abs(mcacc::lamMass(candidate1) - mcacc::lamMass(candidate2)) > massMix) { + return false; + } + + return true; + } + + // ----------------------------------------- + // 3) MC filter + aliases (distinct from data) + // ----------------------------------------- + Filter centralityFilterMC = (nabs(aod::lambdaeventmc::centmc) < centMax && nabs(aod::lambdaeventmc::centmc) > centMin); + + using EventCandidatesMC = soa::Filtered; + using AllTrackCandidatesMC = aod::LambdaPairmcs; + + // IMPORTANT: MC preslice uses the MC event index column + Preslice tracksPerCollisionV0mc = aod::lambdapairmc::lambdaeventmcId; + + // ----------------------------------------- + // 4) MC Same-event processing (like processData) + // ----------------------------------------- + void processMC(EventCandidatesMC::iterator const& collision, AllTrackCandidatesMC const& V0sMC) + { + const float centrality = mcacc::cent(collision); + + for (const auto& v0 : V0sMC) { + if (!selectionV0MC(v0)) { + continue; + } + histos.fill(HIST("hPtRadiusV0"), mcacc::lamPt(v0), mcacc::v0Radius(v0)); + histos.fill(HIST("ptCent"), mcacc::lamPt(v0), centrality); + histos.fill(HIST("etaCent"), mcacc::lamEta(v0), centrality); + + proton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(v0), mcacc::prEta(v0), mcacc::prPhi(v0), + o2::constants::physics::MassProton); + lambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(v0), mcacc::lamEta(v0), mcacc::lamPhi(v0), + mcacc::lamMass(v0)); + + for (const auto& v02 : V0sMC) { + if (v02.index() <= v0.index()) { + continue; + } + if (!selectionV0MC(v02)) { + continue; + } + + // no shared daughters + if (mcacc::prIdx(v0) == mcacc::prIdx(v02)) { + continue; + } + if (mcacc::piIdx(v0) == mcacc::piIdx(v02)) { + continue; + } + if (mcacc::prIdx(v0) == mcacc::piIdx(v02)) { + continue; + } + if (mcacc::piIdx(v0) == mcacc::prIdx(v02)) { + continue; + } + + proton2 = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(v02), mcacc::prEta(v02), mcacc::prPhi(v02), + o2::constants::physics::MassProton); + lambda2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(v02), mcacc::lamEta(v02), mcacc::lamPhi(v02), + mcacc::lamMass(v02)); + + histos.fill(HIST("deltaPhiSame"), + RecoDecay::constrainAngle(mcacc::lamPhi(v0) - mcacc::lamPhi(v02), + -TMath::Pi(), harmonicDphi)); + + const int ptype = pairTypeCode(mcacc::v0Status(v0), mcacc::v0Status(v02)); + histos.fill(HIST("hCentPairTypeSE"), mcacc::cent(collision), ptype, 1.0); + // datatype=0 (same event) + fillHistograms(mcacc::v0Status(v0), mcacc::v0Status(v02), + lambda, lambda2, proton, proton2, + /*datatype=*/0, /*mixpairweight=*/1.0f); + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processMC, "Process MC (SE)", false); + + void processMCMEV3(EventCandidatesMC const& collisions, AllTrackCandidatesMC const& V0sMC) + { + auto nBins = colBinning.getAllBinsCount(); + std::vector>> eventPools(nBins); + + for (auto& collision1 : collisions) { + const int bin = colBinning.getBin(std::make_tuple(mcacc::posz(collision1), mcacc::cent(collision1))); + if (bin < 0) { + continue; + } + + auto poolA = V0sMC.sliceBy(tracksPerCollisionV0mc, collision1.index()); + + if (eventPools[bin].empty()) { + eventPools[bin].emplace_back(collision1.index(), std::move(poolA)); + if ((int)eventPools[bin].size() > nEvtMixing) { + eventPools[bin].pop_front(); + } + continue; + } + + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0MC(t1) || !selectionV0MC(t2)) { + continue; + } + if (t2.index() <= t1.index()) { + continue; + } + + if (mcacc::prIdx(t1) == mcacc::prIdx(t2)) { + continue; + } + if (mcacc::piIdx(t1) == mcacc::piIdx(t2)) { + continue; + } + if (mcacc::prIdx(t1) == mcacc::piIdx(t2)) { + continue; + } + if (mcacc::piIdx(t1) == mcacc::prIdx(t2)) { + continue; + } + + const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); + const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); + + struct PV { + AllTrackCandidatesMC* pool; + int nRepl1 = 0; + int nRepl2 = 0; + }; + + std::vector usable; + int totalRepl = 0; + + int mixes = 0; + for (auto it = eventPools[bin].rbegin(); it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { + const int collision2idx = it->first; + auto& poolB = it->second; + + if (collision2idx == collision1.index()) { + continue; + } + + int nRepl1 = 0; + int nRepl2 = 0; + + for (auto& tX : poolB) { + if (!selectionV0MC(tX)) { + continue; + } + + if (doMixLeg1) { + if (checkKinematicsMC(t1, tX) && checkPairKinematicsMC(t1, t2, tX)) { + ++nRepl1; + } + } + + if (doMixLeg2) { + if (checkKinematicsMC(t2, tX) && checkPairKinematicsMC(t2, t1, tX)) { + ++nRepl2; + } + } + } + + if (nRepl1 > 0 || nRepl2 > 0) { + usable.push_back(PV{&poolB, nRepl1, nRepl2}); + totalRepl += nRepl1 + nRepl2; + } + } + + if (totalRepl <= 0) { + continue; + } + + const float wBase = 1.0f / static_cast(totalRepl); + + for (auto& pv : usable) { + auto& poolB = *pv.pool; + + for (auto& tX : poolB) { + if (!selectionV0MC(tX)) { + continue; + } + + // -------- leg-1 replacement: (tX, t2) + if (doMixLeg1) { + if (checkKinematicsMC(t1, tX) && checkPairKinematicsMC(t1, t2, tX)) { + auto pX = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(tX), mcacc::prEta(tX), mcacc::prPhi(tX), + o2::constants::physics::MassProton); + auto lX = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(tX), mcacc::lamEta(tX), mcacc::lamPhi(tX), + mcacc::lamMass(tX)); + auto p2 = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(t2), mcacc::prEta(t2), mcacc::prPhi(t2), + o2::constants::physics::MassProton); + auto l2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(t2), mcacc::lamEta(t2), mcacc::lamPhi(t2), + mcacc::lamMass(t2)); + + const float dPhi = RecoDecay::constrainAngle( + RecoDecay::constrainAngle(lX.Phi(), 0.0F, harmonic) - + RecoDecay::constrainAngle(l2.Phi(), 0.0F, harmonic), + -TMath::Pi(), harmonicDphi); + + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(mcacc::v0Status(tX), mcacc::v0Status(t2), + lX, l2, pX, p2, + 1, wBase, 1); + } + } + + // -------- leg-2 replacement: (t1, tX) + if (doMixLeg2) { + if (checkKinematicsMC(t2, tX) && checkPairKinematicsMC(t2, t1, tX)) { + auto p1 = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(t1), mcacc::prEta(t1), mcacc::prPhi(t1), + o2::constants::physics::MassProton); + auto l1 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(t1), mcacc::lamEta(t1), mcacc::lamPhi(t1), + mcacc::lamMass(t1)); + auto pX = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(tX), mcacc::prEta(tX), mcacc::prPhi(tX), + o2::constants::physics::MassProton); + auto lX = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(tX), mcacc::lamEta(tX), mcacc::lamPhi(tX), + mcacc::lamMass(tX)); + + const float dPhi = RecoDecay::constrainAngle( + RecoDecay::constrainAngle(l1.Phi(), 0.0F, harmonic) - + RecoDecay::constrainAngle(lX.Phi(), 0.0F, harmonic), + -TMath::Pi(), harmonicDphi); + + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(mcacc::v0Status(t1), mcacc::v0Status(tX), + l1, lX, p1, pX, + 1, wBase, 2); + } + } + } + } + } + + auto sliced = V0sMC.sliceBy(tracksPerCollisionV0mc, collision1.index()); + eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); + if ((int)eventPools[bin].size() > nEvtMixing) { + eventPools[bin].pop_front(); + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processMCMEV3, "Process MC ME v3 FIFO", false); + static inline float phi0To2Pi(float phi) + { + // harmonic=1, min=0 => [0, 2pi) + return RecoDecay::constrainAngle(phi, 0.0f, 1); + } + + static inline float deltaPhiMinusPiToPi(float phiA, float phiB) { - return ((((((static_cast(colBin) * nStatus + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin)); + // returns in [-pi, pi) + const float d = phi0To2Pi(phiA) - phi0To2Pi(phiB); + return RecoDecay::constrainAngle(d, -TMath::Pi(), 1); } - static inline void collectPhiNeighborBins(int phiB, int nPhi, int nNeighbor, std::vector& out) + static inline float absDeltaPhi(float phiA, float phiB) + { + return std::abs(deltaPhiMinusPiToPi(phiA, phiB)); + } + + // symmetric neighbors for phi: periodic wrap + static inline void collectNeighborBinsPhi(int b, int nPhi, int nNeighbor, std::vector& out) { out.clear(); out.reserve(2 * nNeighbor + 1); for (int d = -nNeighbor; d <= nNeighbor; ++d) { - int b = phiB + d; - // wrap into [0, nPhi-1] - b %= nPhi; - if (b < 0) - b += nPhi; - out.push_back(b); - } - // optional: unique (in case nNeighbor >= nPhi) + int bb = b + d; + bb %= nPhi; + if (bb < 0) { + bb += nPhi; + } + out.push_back(bb); + } std::sort(out.begin(), out.end()); out.erase(std::unique(out.begin(), out.end()), out.end()); } - // ===================== Main mixing (with mass-bin + random unique sampling) ===================== - void processMEV4(EventCandidates const& collisions, AllTrackCandidates const& V0s) + + static inline void collectNeighborBinsClamp(int b, int nBins, int nNeighbor, std::vector& out) { - // Build binner from your existing configurables - MixBinner mb{ - ptMin.value, ptMax.value, ptMix.value, // pT range & step - v0eta.value, etaMix.value, // |eta| max & step - phiMix.value // φ step; φ range fixed to [0, 2π) - }; + out.clear(); + out.reserve(2 * nNeighbor + 1); + for (int d = -nNeighbor; d <= nNeighbor; ++d) { + const int bb = b + d; + if (bb >= 0 && bb < nBins) { + out.push_back(bb); + } + } + } - const int nCol = colBinning.getAllBinsCount(); // event-class bins (vz, centrality) - const int nStat = N_STATUS; // 2 + static inline uint64_t splitmix64(uint64_t x) + { + // simple deterministic hash for reproducible shuffling + x += 0x9e3779b97f4a7c15ULL; + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; + x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; + return x ^ (x >> 31); + } + + void processMEV6(EventCandidates const& collisions, AllTrackCandidates const& V0s) + { + MixBinnerR mb{ + ptMinMixBuffer.value, + ptMaxMixBuffer.value, + static_cast((ptMaxMixBuffer.value - ptMinMixBuffer.value) / cfgKinematicBins.nKinematicPt.value), + v0etaMixBuffer.value, + static_cast((2.0 * v0etaMixBuffer.value) / cfgKinematicBins.nKinematicEta.value), + static_cast((2.0 * TMath::Pi()) / cfgKinematicBins.nKinematicPhi.value), + MassMin.value, + MassMax.value, + cfgV5MassBins.value, + cfgMixRadiusParam.cfgMixRadiusBins.value}; + + const int nCol = colBinning.getAllBinsCount(); + const int nStat = N_STATUS; const int nPt = mb.nPt(); const int nEta = mb.nEta(); const int nPhi = mb.nPhi(); const int nM = mb.nM(); + const int nR = mb.nR(); - const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM; - std::vector> buffer(nKeys); + const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM * nR; + std::vector> buffer(nKeys); - // ---- PASS 1: fill 6D buffer ---- + // -------- PASS 1: fill buffer -------- for (auto const& col : collisions) { const int colBin = colBinning.getBin(std::make_tuple(col.posz(), col.cent())); + if (colBin < 0) { + continue; + } + auto slice = V0s.sliceBy(tracksPerCollisionV0, col.index()); for (auto const& t : slice) { - if (!selectionV0(t)) + if (!selectionV0Buffer(t)) { continue; + } const int status = static_cast(t.v0Status()); - if (status < 0 || status >= nStat) + if (status < 0 || status >= nStat) { continue; + } - // Bin kinematics (φ already constrained via your call-site) const int ptB = mb.ptBin(t.lambdaPt()); - const int etaB = mb.etaBin(t.lambdaEta()); - const int phiB = mb.phiBin(RecoDecay::constrainAngle(t.lambdaPhi(), 0.0F, harmonic)); + + int etaB = mb.etaBin(t.lambdaEta()); + if (userapidity) { + const auto lv = ROOT::Math::PtEtaPhiMVector(t.lambdaPt(), t.lambdaEta(), t.lambdaPhi(), t.lambdaMass()); + etaB = mb.etaBin(lv.Rapidity()); + } + + const int phiB = mb.phiBin(RecoDecay::constrainAngle(t.lambdaPhi(), -TMath::Pi(), harmonic)); const int mB = mb.massBin(t.lambdaMass()); - if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) + const int rB = mb.radiusBin(t.v0Radius()); + + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 || rB < 0) { continue; + } - const size_t key = linearKey(colBin, status, ptB, etaB, phiB, mB, - nStat, nPt, nEta, nPhi, nM); + const size_t key = linearKeyR(colBin, status, ptB, etaB, phiB, mB, rB, + nStat, nPt, nEta, nPhi, nM, nR); - buffer[key].push_back(BufferCand{ + buffer[key].push_back(BufferCandR{ .collisionIdx = static_cast(col.index()), - .rowIndex = static_cast(t.globalIndex()), // adapt accessor if needed + .rowIndex = static_cast(t.globalIndex()), .v0Status = static_cast(status), .ptBin = static_cast(ptB), .etaBin = static_cast(etaB), .phiBin = static_cast(phiB), - .mBin = static_cast(mB)}); + .mBin = static_cast(mB), + .rBin = static_cast(rB)}); } } - // ---- PASS 2: mixing over same-event pairs ---- - for (auto const& collision1 : collisions) { - const int colBin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); - auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + const int nN_pt = std::max(0, cfgV5NeighborPt.value); + const int nN_eta = std::max(0, cfgV5NeighborEta.value); + const int nN_phi = std::max(0, cfgV5NeighborPhi.value); + + std::vector ptBins, etaBins, phiBins; + std::vector matches1, matches2; + matches1.reserve(256); + matches2.reserve(256); + + auto collectMatchesForReplacedLeg = [&](auto const& tRep, auto const& tKeep, int colBin, int64_t curColIdx, std::vector& matches) { + matches.clear(); + + const int status = static_cast(tRep.v0Status()); + if (status < 0 || status >= nStat) { + return; + } + + const int ptB = mb.ptBin(tRep.lambdaPt()); + + int etaB = mb.etaBin(tRep.lambdaEta()); + if (userapidity) { + const auto lv = ROOT::Math::PtEtaPhiMVector(tRep.lambdaPt(), tRep.lambdaEta(), tRep.lambdaPhi(), tRep.lambdaMass()); + etaB = mb.etaBin(lv.Rapidity()); + } + + const int phiB = mb.phiBin(RecoDecay::constrainAngle(tRep.lambdaPhi(), -TMath::Pi(), harmonic)); + const int mB = mb.massBin(tRep.lambdaMass()); + const int rB = mb.radiusBin(tRep.v0Radius()); + + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 || rB < 0) { + return; + } + + collectNeighborBinsClamp(ptB, nPt, nN_pt, ptBins); + collectNeighborBinsClamp(etaB, nEta, nN_eta, etaBins); + collectNeighborBinsPhi(phiB, nPhi, nN_phi, phiBins); + + for (int ptUse : ptBins) { + for (int etaUse : etaBins) { + for (int phiUse : phiBins) { + const auto& vec = buffer[linearKeyR(colBin, status, ptUse, etaUse, phiUse, mB, rB, + nStat, nPt, nEta, nPhi, nM, nR)]; + + for (auto const& bc : vec) { + if (bc.collisionIdx == curColIdx) { + continue; + } + + auto tX = V0s.iteratorAt(static_cast(bc.rowIndex)); + + if (!selectionV0(tX)) { + continue; + } + if (!checkKinematics(tRep, tX)) { + continue; + } + if (!checkPairKinematics(tRep, tKeep, tX)) { + continue; + } + + if (tX.globalIndex() == tRep.globalIndex()) { + continue; + } + if (tX.globalIndex() == tKeep.globalIndex()) { + continue; + } + + matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); + } + } + } + } + + std::sort(matches.begin(), matches.end(), + [](auto const& a, auto const& b) { + return std::tie(a.collisionIdx, a.rowIndex) < std::tie(b.collisionIdx, b.rowIndex); + }); + matches.erase(std::unique(matches.begin(), matches.end(), + [](auto const& a, auto const& b) { + return a.collisionIdx == b.collisionIdx && a.rowIndex == b.rowIndex; + }), + matches.end()); + }; + + auto downsampleMatches = [&](std::vector& matches, uint64_t seedBase) { + if (cfgV5MaxMatches.value > 0 && (int)matches.size() > cfgV5MaxMatches.value) { + uint64_t seed = cfgMixSeed.value ^ splitmix64(seedBase); + const int K = cfgV5MaxMatches.value; + for (int i = 0; i < K; ++i) { + seed = splitmix64(seed); + const int j = i + (int)(seed % (uint64_t)(matches.size() - i)); + std::swap(matches[i], matches[j]); + } + matches.resize(K); + } + }; - for (auto const& [t1, t2] : - soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + // -------- PASS 2: configurable one-leg / two-leg mixing -------- + for (auto const& col1 : collisions) { + const int colBin = colBinning.getBin(std::make_tuple(col1.posz(), col1.cent())); + if (colBin < 0) { + continue; + } + + const int64_t curColIdx = static_cast(col1.index()); + auto poolA = V0s.sliceBy(tracksPerCollisionV0, col1.index()); - if (!selectionV0(t1) || !selectionV0(t2)) + for (auto const& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0(t1) || !selectionV0(t2)) { continue; - if (t2.index() <= t1.index()) + } + if (t2.index() <= t1.index()) { continue; + } - // no shared daughters - if (t1.protonIndex() == t2.protonIndex()) + if (t1.protonIndex() == t2.protonIndex()) { continue; - if (t1.pionIndex() == t2.pionIndex()) + } + if (t1.pionIndex() == t2.pionIndex()) { continue; - if (t1.protonIndex() == t2.pionIndex()) + } + if (t1.protonIndex() == t2.pionIndex()) { continue; - if (t1.pionIndex() == t2.protonIndex()) + } + if (t1.pionIndex() == t2.protonIndex()) { continue; + } - const int status = static_cast(t1.v0Status()); - if (status < 0 || status >= nStat) - continue; + const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); + const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); - // Bin of t1 defines where to search (exact bin, but handle φ wrap at edges) - const int ptB = mb.ptBin(t1.lambdaPt()); - const int etaB = mb.etaBin(t1.lambdaEta()); - const int phiB = mb.phiBin(RecoDecay::constrainAngle(t1.lambdaPhi(), 0.0F, harmonic)); - const int mB = mb.massBin(t1.lambdaMass()); - if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) + if (doMixLeg1) { + collectMatchesForReplacedLeg(t1, t2, colBin, curColIdx, matches1); + limitMatchesToNEvents(matches1, nEvtMixing.value); + downsampleMatches(matches1, (uint64_t)t1.globalIndex() ^ (splitmix64((uint64_t)t2.globalIndex()) + 0x111ULL) ^ splitmix64((uint64_t)curColIdx)); + } else { + matches1.clear(); + } + + if (doMixLeg2) { + collectMatchesForReplacedLeg(t2, t1, colBin, curColIdx, matches2); + limitMatchesToNEvents(matches2, nEvtMixing.value); + downsampleMatches(matches2, (uint64_t)t2.globalIndex() ^ (splitmix64((uint64_t)t1.globalIndex()) + 0x222ULL) ^ splitmix64((uint64_t)curColIdx)); + } else { + matches2.clear(); + } + + const int nReuse = static_cast(matches1.size() + matches2.size()); + if (nReuse <= 0) { continue; + } + + const float wSE = 1.0f / static_cast(nReuse); - // Collect partners from nominal key, plus wrapped neighbor only for φ-edge bins - std::vector matches; - matches.reserve(128); // or keep binVec.size() if you prefer - const int64_t curColIdx = static_cast(collision1.index()); - - auto collectFrom = [&](int phiBinUse) { - const size_t keyUse = linearKey(colBin, status, ptB, etaB, phiBinUse, mB, - nStat, nPt, nEta, nPhi, nM); - auto const& vec = buffer[keyUse]; - for (const auto& bc : vec) { - if (bc.collisionIdx == curColIdx) { - continue; // must be from different event + if (doMixLeg1) { + for (auto const& m : matches1) { + auto tX = V0s.iteratorAt(static_cast(m.rowIndex)); + + auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); + + const int ptype = pairTypeCode(tX.v0Status(), t2.v0Status()); + double centPairWeight = 1.0; + if (hweightCentPair) { + const int bin = hweightCentPair->FindBin(col1.cent(), ptype); + centPairWeight = hweightCentPair->GetBinContent(bin); + if (centPairWeight <= 0.0) { + centPairWeight = 1.0; + } } - auto tX = V0s.iteratorAt(static_cast(bc.rowIndex)); - if (!selectionV0(tX)) { - continue; + + const float meWeight = wSE * centPairWeight; + const float dPhi = deltaPhiMinusPiToPi((float)lambda.Phi(), (float)lambda2.Phi()); + histos.fill(HIST("deltaPhiMix"), dPhi, wSE); + histos.fill(HIST("hCentPairTypeME"), col1.cent(), ptype, wSE); + + fillHistograms(tX.v0Status(), t2.v0Status(), lambda, lambda2, proton, proton2, 1, meWeight, 1); + } + } + + if (doMixLeg2) { + for (auto const& m : matches2) { + auto tY = V0s.iteratorAt(static_cast(m.rowIndex)); + + auto proton = ROOT::Math::PtEtaPhiMVector(t1.protonPt(), t1.protonEta(), t1.protonPhi(), o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(tY.protonPt(), tY.protonEta(), tY.protonPhi(), o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(tY.lambdaPt(), tY.lambdaEta(), tY.lambdaPhi(), tY.lambdaMass()); + + const int ptype = pairTypeCode(t1.v0Status(), tY.v0Status()); + double centPairWeight = 1.0; + if (hweightCentPair) { + const int bin = hweightCentPair->FindBin(col1.cent(), ptype); + centPairWeight = hweightCentPair->GetBinContent(bin); + if (centPairWeight <= 0.0) { + centPairWeight = 1.0; + } } - if (!checkKinematics(t1, tX)) { - continue; + + const float meWeight = wSE * centPairWeight; + const float dPhi = deltaPhiMinusPiToPi((float)lambda.Phi(), (float)lambda2.Phi()); + histos.fill(HIST("deltaPhiMix"), dPhi, wSE); + histos.fill(HIST("hCentPairTypeME"), col1.cent(), ptype, wSE); + + fillHistograms(t1.v0Status(), tY.v0Status(), lambda, lambda2, proton, proton2, 1, meWeight, 2); + } + } + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processMEV6, "Process data ME v6 with radius buffer", false); + void processMCMEV6(EventCandidatesMC const& collisions, AllTrackCandidatesMC const& V0sMC) + { + MixBinnerR mb{ + ptMinMixBuffer.value, + ptMaxMixBuffer.value, + static_cast((ptMaxMixBuffer.value - ptMinMixBuffer.value) / cfgKinematicBins.nKinematicPt.value), + v0etaMixBuffer.value, + static_cast((2.0 * v0etaMixBuffer.value) / cfgKinematicBins.nKinematicEta.value), + static_cast((2.0 * TMath::Pi()) / cfgKinematicBins.nKinematicPhi.value), + MassMin.value, + MassMax.value, + cfgV5MassBins.value, + cfgMixRadiusParam.cfgMixRadiusBins.value}; + + const int nCol = colBinning.getAllBinsCount(); + const int nStat = N_STATUS; + const int nPt = mb.nPt(); + const int nEta = mb.nEta(); + const int nPhi = mb.nPhi(); + const int nM = mb.nM(); + const int nR = mb.nR(); + + const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM * nR; + std::vector> buffer(nKeys); + + // -------- PASS 1: fill buffer -------- + for (auto const& col : collisions) { + const int colBin = colBinning.getBin(std::make_tuple(mcacc::posz(col), mcacc::cent(col))); + if (colBin < 0) { + continue; + } + + auto slice = V0sMC.sliceBy(tracksPerCollisionV0mc, col.index()); + + for (auto const& t : slice) { + if (!selectionV0BufferMC(t)) { + continue; + } + + const int status = mcacc::v0Status(t); + if (status < 0 || status >= nStat) { + continue; + } + + const int ptB = mb.ptBin(mcacc::lamPt(t)); + + int etaB = mb.etaBin(mcacc::lamEta(t)); + if (userapidity) { + const auto lv = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(t), mcacc::lamEta(t), mcacc::lamPhi(t), mcacc::lamMass(t)); + etaB = mb.etaBin(lv.Rapidity()); + } + + const int phiB = mb.phiBin(RecoDecay::constrainAngle(mcacc::lamPhi(t), -TMath::Pi(), harmonic)); + const int mB = mb.massBin(mcacc::lamMass(t)); + const int rB = mb.radiusBin(mcacc::v0Radius(t)); + + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 || rB < 0) { + continue; + } + + const size_t key = linearKeyR(colBin, status, ptB, etaB, phiB, mB, rB, + nStat, nPt, nEta, nPhi, nM, nR); + + buffer[key].push_back(BufferCandR{ + .collisionIdx = static_cast(col.index()), + .rowIndex = static_cast(t.globalIndex()), + .v0Status = static_cast(status), + .ptBin = static_cast(ptB), + .etaBin = static_cast(etaB), + .phiBin = static_cast(phiB), + .mBin = static_cast(mB), + .rBin = static_cast(rB)}); + } + } + + const int nN_pt = std::max(0, cfgV5NeighborPt.value); + const int nN_eta = std::max(0, cfgV5NeighborEta.value); + const int nN_phi = std::max(0, cfgV5NeighborPhi.value); + + std::vector ptBins, etaBins, phiBins; + std::vector matches1, matches2; + matches1.reserve(256); + matches2.reserve(256); + + auto collectMatchesForReplacedLeg = [&](auto const& tRep, auto const& tKeep, int colBin, int64_t curColIdx, std::vector& matches) { + matches.clear(); + + const int status = mcacc::v0Status(tRep); + if (status < 0 || status >= nStat) { + return; + } + + const int ptB = mb.ptBin(mcacc::lamPt(tRep)); + + int etaB = mb.etaBin(mcacc::lamEta(tRep)); + if (userapidity) { + const auto lv = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(tRep), mcacc::lamEta(tRep), mcacc::lamPhi(tRep), mcacc::lamMass(tRep)); + etaB = mb.etaBin(lv.Rapidity()); + } + + const int phiB = mb.phiBin(RecoDecay::constrainAngle(mcacc::lamPhi(tRep), -TMath::Pi(), harmonic)); + const int mB = mb.massBin(mcacc::lamMass(tRep)); + const int rB = mb.radiusBin(mcacc::v0Radius(tRep)); + + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 || rB < 0) { + return; + } + + collectNeighborBinsClamp(ptB, nPt, nN_pt, ptBins); + collectNeighborBinsClamp(etaB, nEta, nN_eta, etaBins); + collectNeighborBinsPhi(phiB, nPhi, nN_phi, phiBins); + + for (int ptUse : ptBins) { + for (int etaUse : etaBins) { + for (int phiUse : phiBins) { + const auto& vec = buffer[linearKeyR(colBin, status, ptUse, etaUse, phiUse, mB, rB, + nStat, nPt, nEta, nPhi, nM, nR)]; + + for (auto const& bc : vec) { + if (bc.collisionIdx == curColIdx) { + continue; + } + + auto tX = V0sMC.iteratorAt(static_cast(bc.rowIndex)); + + if (!selectionV0MC(tX)) { + continue; + } + if (!checkKinematicsMC(tRep, tX)) { + continue; + } + if (!checkPairKinematicsMC(tRep, tKeep, tX)) { + continue; + } + + if (tX.globalIndex() == tRep.globalIndex()) { + continue; + } + if (tX.globalIndex() == tKeep.globalIndex()) { + continue; + } + + matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); } - matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); } - }; + } + } - // 1) nominal φ-bin - collectFrom(phiB); + std::sort(matches.begin(), matches.end(), + [](auto const& a, auto const& b) { + return std::tie(a.collisionIdx, a.rowIndex) < std::tie(b.collisionIdx, b.rowIndex); + }); + matches.erase(std::unique(matches.begin(), matches.end(), + [](auto const& a, auto const& b) { + return a.collisionIdx == b.collisionIdx && a.rowIndex == b.rowIndex; + }), + matches.end()); + }; - // 2) wrap only at boundaries: 0 <-> nPhi-1 - if (phiB == 0) { - collectFrom(nPhi - 1); - } else if (phiB == nPhi - 1) { - collectFrom(0); + auto downsampleMatches = [&](std::vector& matches, uint64_t seedBase) { + if (cfgV5MaxMatches.value > 0 && (int)matches.size() > cfgV5MaxMatches.value) { + uint64_t seed = cfgMixSeed.value ^ splitmix64(seedBase); + const int K = cfgV5MaxMatches.value; + for (int i = 0; i < K; ++i) { + seed = splitmix64(seed); + const int j = i + (int)(seed % (uint64_t)(matches.size() - i)); + std::swap(matches[i], matches[j]); + } + matches.resize(K); + } + }; + + // -------- PASS 2: configurable one-leg / two-leg mixing -------- + for (auto const& col1 : collisions) { + const int colBin = colBinning.getBin(std::make_tuple(mcacc::posz(col1), mcacc::cent(col1))); + if (colBin < 0) { + continue; + } + + const int64_t curColIdx = static_cast(col1.index()); + auto poolA = V0sMC.sliceBy(tracksPerCollisionV0mc, col1.index()); + + for (auto const& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0MC(t1) || !selectionV0MC(t2)) { + continue; + } + if (t2.index() <= t1.index()) { + continue; } - if (matches.empty()) { + if (mcacc::prIdx(t1) == mcacc::prIdx(t2)) { + continue; + } + if (mcacc::piIdx(t1) == mcacc::piIdx(t2)) { + continue; + } + if (mcacc::prIdx(t1) == mcacc::piIdx(t2)) { + continue; + } + if (mcacc::piIdx(t1) == mcacc::prIdx(t2)) { continue; } - // Optional safety: dedupe exact same (collision,row) just in case - std::sort(matches.begin(), matches.end(), - [](auto& a, auto& b) { return std::tie(a.collisionIdx, a.rowIndex) < std::tie(b.collisionIdx, b.rowIndex); }); - matches.erase(std::unique(matches.begin(), matches.end(), - [](auto& a, auto& b) { return a.collisionIdx == b.collisionIdx && a.rowIndex == b.rowIndex; }), - matches.end()); - if (matches.empty()) { + const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); + const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); + + if (doMixLeg1) { + collectMatchesForReplacedLeg(t1, t2, colBin, curColIdx, matches1); + limitMatchesToNEvents(matches1, nEvtMixing.value); + downsampleMatches(matches1, (uint64_t)t1.globalIndex() ^ (splitmix64((uint64_t)t2.globalIndex()) + 0x111ULL) ^ splitmix64((uint64_t)curColIdx)); + } else { + matches1.clear(); + } + if (doMixLeg2) { + collectMatchesForReplacedLeg(t2, t1, colBin, curColIdx, matches2); + limitMatchesToNEvents(matches2, nEvtMixing.value); + downsampleMatches(matches2, (uint64_t)t2.globalIndex() ^ (splitmix64((uint64_t)t1.globalIndex()) + 0x222ULL) ^ splitmix64((uint64_t)curColIdx)); + } else { + matches2.clear(); + } + const int nReuse = static_cast(matches1.size() + matches2.size()); + if (nReuse <= 0) { continue; } - const float wBase = 1.0f / static_cast(matches.size()); + const float wSE = 1.0f / static_cast(nReuse); + + if (doMixLeg1) { + for (auto const& m : matches1) { + auto tX = V0sMC.iteratorAt(static_cast(m.rowIndex)); + + auto pX = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(tX), mcacc::prEta(tX), mcacc::prPhi(tX), + o2::constants::physics::MassProton); + auto lX = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(tX), mcacc::lamEta(tX), mcacc::lamPhi(tX), + mcacc::lamMass(tX)); + auto p2 = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(t2), mcacc::prEta(t2), mcacc::prPhi(t2), + o2::constants::physics::MassProton); + auto l2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(t2), mcacc::lamEta(t2), mcacc::lamPhi(t2), + mcacc::lamMass(t2)); + + const int ptype = pairTypeCode(mcacc::v0Status(tX), mcacc::v0Status(t2)); + double centPairWeight = 1.0; + if (hweightCentPair) { + const int bin = hweightCentPair->FindBin(mcacc::cent(col1), ptype); + centPairWeight = hweightCentPair->GetBinContent(bin); + if (centPairWeight <= 0.0) { + centPairWeight = 1.0; + } + } - for (const auto& m : matches) { - auto tX = V0s.iteratorAt(static_cast(m.rowIndex)); + const float meWeight = wSE * centPairWeight; + const float dPhi = deltaPhiMinusPiToPi((float)lX.Phi(), (float)l2.Phi()); + histos.fill(HIST("deltaPhiMix"), dPhi, wSE); + histos.fill(HIST("hCentPairTypeME"), mcacc::cent(col1), ptype, wSE); - auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), o2::constants::physics::MassProton); - auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()); - auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); - auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); + fillHistograms(mcacc::v0Status(tX), mcacc::v0Status(t2), + lX, l2, pX, p2, + 1, meWeight, 1); + } + } - const float dPhi = RecoDecay::constrainAngle( - RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), - -TMath::Pi(), harmonicDphi); + if (doMixLeg2) { + for (auto const& m : matches2) { + auto tY = V0sMC.iteratorAt(static_cast(m.rowIndex)); + + auto p1 = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(t1), mcacc::prEta(t1), mcacc::prPhi(t1), + o2::constants::physics::MassProton); + auto l1 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(t1), mcacc::lamEta(t1), mcacc::lamPhi(t1), + mcacc::lamMass(t1)); + auto pY = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(tY), mcacc::prEta(tY), mcacc::prPhi(tY), + o2::constants::physics::MassProton); + auto lY = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(tY), mcacc::lamEta(tY), mcacc::lamPhi(tY), + mcacc::lamMass(tY)); + + const int ptype = pairTypeCode(mcacc::v0Status(t1), mcacc::v0Status(tY)); + double centPairWeight = 1.0; + if (hweightCentPair) { + const int bin = hweightCentPair->FindBin(mcacc::cent(col1), ptype); + centPairWeight = hweightCentPair->GetBinContent(bin); + if (centPairWeight <= 0.0) { + centPairWeight = 1.0; + } + } + + const float meWeight = wSE * centPairWeight; + const float dPhi = deltaPhiMinusPiToPi((float)l1.Phi(), (float)lY.Phi()); + histos.fill(HIST("deltaPhiMix"), dPhi, wSE); + histos.fill(HIST("hCentPairTypeME"), mcacc::cent(col1), ptype, wSE); - histos.fill(HIST("deltaPhiMix"), dPhi, wBase); - fillHistograms(tX.v0Status(), t2.v0Status(), lambda, lambda2, proton, proton2, 1, wBase); + fillHistograms(mcacc::v0Status(t1), mcacc::v0Status(tY), + l1, lY, p1, pY, + 1, meWeight, 2); + } } } } } - PROCESS_SWITCH(lambdaspincorrderived, processMEV4, "Process data ME (5d buffer)", false); + PROCESS_SWITCH(lambdaspincorrderived, processMCMEV6, "Process MC ME v6 with radius buffer", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx index 59a460d0324..6639404d334 100644 --- a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx +++ b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx @@ -9,6 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "PWGLF/DataModel/LFNonPromptCascadeTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + #include "Common/Core/RecoDecay.h" #include "Common/Core/Zorro.h" #include "Common/Core/ZorroSummary.h" @@ -34,6 +37,8 @@ #include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "MathUtils/BetheBlochAleph.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/Vertex.h" #include "Math/Vector4D.h" @@ -42,16 +47,12 @@ #include "TParticlePDG.h" #include "TTree.h" +#include #include +#include #include #include #include -// #include "PWGHF/Core/PDG.h" -#include "PWGLF/DataModel/LFNonPromptCascadeTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" - -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; @@ -182,6 +183,7 @@ struct NonPromptCascadeTask { Produces NPCTableMCNT; Produces NPCTableGen; Produces NPPUTable; + Produces NPMCNTable; using TracksExtData = soa::Join; using TracksExtMC = soa::Join; @@ -216,6 +218,7 @@ struct NonPromptCascadeTask { Configurable cfgMaxMult{"cfgMaxMult", 8000.f, "Upper range of multiplicty histo"}; Configurable cfgMaxMultFV0{"cfgMaxMultFV0", 10000.f, "Upper range of multiplicty FV0 histo"}; Configurable cfgPtEdgesdNdeta{"ptEdges", "0,0.2,0.4,0.6,0.8,1,1.2,1.6,2.0,2.4,2.8,3.2,3.6,4,4.5,5,5.5,6,7,8,10", "Pt bin edges (comma-separated)"}; + Configurable cfgDownscaleMB{"cfgDownscaleMB", 1, "Downscaling for pile up study sample"}; Zorro mZorro; OutputObj mZorroSummary{"ZorroSummary"}; @@ -741,7 +744,7 @@ struct NonPromptCascadeTask { { fillCandidatesVector(collisions, tracks, cascades, gCandidatesNT); fillMCtable(mcParticles, collisions, gCandidatesNT); - fillMultHistos(collisions); + // fillMultHistos(collisions); } PROCESS_SWITCH(NonPromptCascadeTask, processCascadesMC, "process cascades: MC analysis", false); @@ -792,7 +795,7 @@ struct NonPromptCascadeTask { zorroAccounting(collisions); fillCandidatesVector(collisions, tracks, cascades, gCandidatesNT); fillDataTable(gCandidatesNT); - fillMultHistos(collisions); + // fillMultHistos(collisions); } PROCESS_SWITCH(NonPromptCascadeTask, processCascadesData, "process cascades: Data analysis", false); @@ -812,7 +815,7 @@ struct NonPromptCascadeTask { std::vector mcMult(mcCollisions.size(), 0); for (auto const& mcp : mcParticles) { int mcid = mcp.mcCollisionId(); - if (mcid < 0 || mcid >= (int)mcMult.size()) + if (mcid < 0 || static_cast(mcid) >= mcMult.size()) continue; // apply your primary/eta/charge definition here @@ -822,7 +825,7 @@ struct NonPromptCascadeTask { continue; int q = 0; if (auto pdg = pdgDB->GetParticle(mcp.pdgCode())) { - q = int(std::round(pdg->Charge() / 3.0)); + q = static_cast(std::round(pdg->Charge() / 3.0)); } if (q == 0) continue; @@ -837,14 +840,14 @@ struct NonPromptCascadeTask { // ------------------------------------------------------------ int maxCollRowId = -1; for (auto const& trk : tracks) { - maxCollRowId = std::max(maxCollRowId, (int)trk.collisionId()); + maxCollRowId = std::max(maxCollRowId, static_cast(trk.collisionId())); } std::vector collRowIdToDense(maxCollRowId + 1, -1); int dense = 0; for (auto const& col : colls) { const int collRowId = col.globalIndex(); // row id in aod::Collisions - if (collRowId >= 0 && collRowId < (int)collRowIdToDense.size()) { + if (collRowId >= 0 && static_cast(collRowId) < collRowIdToDense.size()) { collRowIdToDense[collRowId] = dense; } ++dense; @@ -859,7 +862,7 @@ struct NonPromptCascadeTask { continue; } const int collRowId = trk.collisionId(); - if (collRowId < 0 || collRowId >= (int)collRowIdToDense.size()) { + if (collRowId < 0 || static_cast(collRowId) >= collRowIdToDense.size()) { continue; } const int dIdx = collRowIdToDense[collRowId]; @@ -889,7 +892,7 @@ struct NonPromptCascadeTask { // Map track's collision row id -> dense colls index const int collRowId = trk.collisionId(); - if (collRowId < 0 || collRowId >= (int)collRowIdToDense.size()) { + if (collRowId < 0 || static_cast(collRowId) >= collRowIdToDense.size()) { continue; } const int dIdx = collRowIdToDense[collRowId]; @@ -902,14 +905,14 @@ struct NonPromptCascadeTask { // MC collision id (row index in aod::McCollisions) const int mcCollId = col.mcCollisionId(); - if (mcCollId < 0 || mcCollId >= (int)mcCollisions.size()) { + if (mcCollId < 0 || static_cast(mcCollId) >= mcCollisions.size()) { continue; } mcReconstructed[mcCollId] = 1; // MC particle id (row index in aod::McParticles) const int mcPid = trk.mcParticleId(); - if (mcPid < 0 || mcPid >= (int)mcParticles.size()) { + if (mcPid < 0 || static_cast(mcPid) >= mcParticles.size()) { continue; } @@ -933,7 +936,7 @@ struct NonPromptCascadeTask { int q = 0; if (auto pdgEntry = pdgDB->GetParticle(mcPar.pdgCode())) { - q = int(std::round(pdgEntry->Charge() / 3.0)); + q = static_cast(std::round(pdgEntry->Charge() / 3.0)); } if (q == 0) { continue; @@ -948,27 +951,30 @@ struct NonPromptCascadeTask { const float ptMC = mcPar.pt(); mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRM"), mult, multReco, ptMC, ptReco); + NPMCNTable(ptMC, ptReco, mult, multReco); } // ------------------------------------------------------------ // MC particles with no reco track (iterate by row index) // ------------------------------------------------------------ - for (int pid = 0; pid < (int)mcParticles.size(); ++pid) { + for (int pid = 0; pid < static_cast(mcParticles.size()); ++pid) { if (!isReco[pid]) { auto mcp = mcParticles.rawIteratorAt(pid); mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRMNotInRecoTrk"), isRecoMult[pid], mcp.pt()); + NPMCNTable(mcp.pt(), -1, isRecoMult[pid], -1); } } // ------------------------------------------------------------ // Unreconstructed MC collisions (iterate by row index) // ------------------------------------------------------------ - for (int mcid = 0; mcid < (int)mcCollisions.size(); ++mcid) { + for (int mcid = 0; mcid < static_cast(mcCollisions.size()); ++mcid) { if (!mcReconstructed[mcid]) { std::vector mcptvec; const int mult = mcMult[mcid]; for (auto const& pt : mcptvec) { mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRMNotInRecoCol"), mult, pt); + NPMCNTable(pt, -2, mult, -2); } } } @@ -978,17 +984,34 @@ struct NonPromptCascadeTask { void processPileUp(CollisionCandidatesRun3 const& collisions, aod::BCsWithTimestamps const&) { - std::cout << "Processing pile up" << std::endl; + // std::cout << "Processing pile up" << std::endl; + int ds = 1; + uint32_t orbitO = 0; + bool writeFlag = 0; for (const auto& coll : collisions) { - float centFT0M = coll.centFT0M(); - float multFT0M = coll.multFT0M(); auto bc = coll.template bc_as(); uint64_t globalBC = bc.globalBC(); - NPPUTable(mRunNumber, globalBC, coll.numContrib(), coll.multNTracksGlobal(), centFT0M, multFT0M); - // NPPileUpTable(mRunNumber, globalBC, multNTracks, centFT0M, multFT0M); + uint32_t orbit = globalBC / 3564; + if (orbitO != orbit) { + orbitO = orbit; + if ((ds % cfgDownscaleMB) == 0) { + writeFlag = 1; + } else { + writeFlag = 0; + } + ds++; + } + if (writeFlag) { + if (mRunNumber != bc.runNumber()) { + mRunNumber = bc.runNumber(); + } + float centFT0M = coll.centFT0M(); + float multFT0M = coll.multFT0M(); + NPPUTable(mRunNumber, globalBC, coll.numContrib(), coll.multNTracksGlobal(), centFT0M, multFT0M); + } } }; - PROCESS_SWITCH(NonPromptCascadeTask, processPileUp, "pile up studies", true); + PROCESS_SWITCH(NonPromptCascadeTask, processPileUp, "pile up studies", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx b/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx index 1b25bf8e442..cefeec99ce6 100644 --- a/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx +++ b/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx @@ -133,6 +133,7 @@ struct StrangenessInJetsIons { // Track analysis parameters struct : ConfigurableGroup { + // std::string prefix = "configTracks"; // name in JSON Configurable minITSnCls{"minITSnCls", 4, "Minimum number of ITS clusters"}; Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70, "Minimum number of TPC crossed rows"}; Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "Maximum chi2 per cluster TPC"}; @@ -154,6 +155,7 @@ struct StrangenessInJetsIons { // V0 analysis parameters struct : ConfigurableGroup { + // std::string prefix = "configV0"; // name in JSON Configurable minimumV0Radius{"minimumV0Radius", 1.2f, "Minimum V0 Radius (cm)"}; // Configurable maximumV0Radius{"maximumV0Radius", 40.0f, "Maximum V0 Radius (cm)"}; Configurable v0cospaMin{"v0cospaMin", 0.995f, "Minimum V0 cosine of pointing angle"}; @@ -166,14 +168,21 @@ struct StrangenessInJetsIons { Configurable requireArmenterosCut{"requireArmenterosCut", true, "Require Armenteros Cut"}; Configurable paramArmenterosCut{"paramArmenterosCut", 0.2f, "Parameter Armenteros Cut (K0S only). This parameters multiplies alphaArm (Check if: qtarm >= this * |alphaArm|)"}; Configurable ctauK0s{"ctauK0s", 20.0f, "C tau K0S (cm)"}; + Configurable requireK0sMassCuts{"requireK0sMassCuts", true, "[K0S] Require mass window for K0S selection and for Lambda rejection"}; + Configurable lamRejWindow{"lamRejWindow", 0.005f, "[K0S] Mass window for Lambda rejection"}; + Configurable k0sMassWindow{"k0sMassWindow", 0.1f, "[K0S] Mass window for K0S selection"}; // Lambda/anti-Lambda paramaters Configurable dcaProtonToPVmin{"dcaProtonToPVmin", 0.05f, "Minimum DCA of proton/anti-proton track to primary vertex in Lambda/anti-Lambda decays (cm)"}; Configurable dcaPionToPVmin{"dcaPionToPVmin", 0.2f, "Minimum DCA of pion-/pion+ track to primary vertex in Lambda/anti-Lambda decays (cm)"}; Configurable ctauLambda{"ctauLambda", 30.0f, "C tau Lambda (cm)"}; + Configurable requireLambdaMassCuts{"requireLambdaMassCuts", true, "[Lambda] Require mass window for Lambda selection and for K0S rejection"}; + Configurable k0sRejWindow{"k0sRejWindow", 0.010f, "[Lambda] Mass window for K0S rejection"}; + Configurable lamMassWindow{"lamMassWindow", 0.1f, "[Lambda] Mass window for Lambda selection"}; } configV0; // Cascade analysis parameters struct : ConfigurableGroup { + // std::string prefix = "configCasc"; // name in JSON Configurable minimumCascRadius{"minimumCascRadius", 0.1f, "Minimum cascade radius"}; // Configurable maximumCascRadius{"maximumCascRadius", 40.0f, "Maximum cascade radius"}; Configurable casccospaMin{"casccospaMin", 0.99f, "Minimum cascade cosine of pointing angle"}; @@ -191,6 +200,7 @@ struct StrangenessInJetsIons { ConfigurableAxis multBinning{"multBinning", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, "Binning of the centrality axis"}; struct : ConfigurableGroup { + // std::string prefix = "longLivedOptions"; // name in JSON ConfigurableAxis longLivedBinsNsigma{"longLivedBinsNsigma", {200, -10.f, 10.f}, "Binning of nSigma axis"}; ConfigurableAxis longLivedBinsPt{"longLivedBinsPt", {VARIABLE_WIDTH, -5.0, -4.8, -4.6, -4.4, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.95, -0.9, -0.85, -0.8, -0.75, -0.7, -0.65, -0.6, -0.55, -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.18, -0.16, -0.14, -0.12, -0.1, 0.0, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0}, "Binning of the pT axis"}; ConfigurableAxis longLivedBinsDca{"longLivedBinsDca", {VARIABLE_WIDTH, -3.0, -2.95, -2.9, -2.85, -2.8, -2.75, -2.7, -2.65, -2.6, -2.55, -2.5, -2.45, -2.4, -2.35, -2.3, -2.25, -2.2, -2.15, -2.1, -2.05, -2.0, -1.975, -1.95, -1.925, -1.9, -1.875, -1.85, -1.825, -1.8, -1.775, -1.75, -1.725, -1.7, -1.675, -1.65, -1.625, -1.6, -1.575, -1.55, -1.525, -1.5, -1.475, -1.45, -1.425, -1.4, -1.375, -1.35, -1.325, -1.3, -1.275, -1.25, -1.225, -1.2, -1.175, -1.15, -1.125, -1.1, -1.075, -1.05, -1.025, -1.0, -0.99, -0.98, -0.97, -0.96, -0.95, -0.94, -0.93, -0.92, -0.91, -0.9, -0.89, -0.88, -0.87, -0.86, -0.85, -0.84, -0.83, -0.82, -0.81, -0.8, -0.79, -0.78, -0.77, -0.76, -0.75, -0.74, -0.73, -0.72, -0.71, -0.7, -0.69, -0.68, -0.67, -0.66, -0.65, -0.64, -0.63, -0.62, -0.61, -0.6, -0.59, -0.58, -0.57, -0.56, -0.55, -0.54, -0.53, -0.52, -0.51, -0.5, -0.49, -0.48, -0.47, -0.46, -0.45, -0.44, -0.43, -0.42, -0.41, -0.4, -0.396, -0.392, -0.388, -0.384, -0.38, -0.376, -0.372, -0.368, -0.364, -0.36, -0.356, -0.352, -0.348, -0.344, -0.34, -0.336, -0.332, -0.328, -0.324, -0.32, -0.316, -0.312, -0.308, -0.304, -0.3, -0.296, -0.292, -0.288, -0.284, -0.28, -0.276, -0.272, -0.268, -0.264, -0.26, -0.256, -0.252, -0.248, -0.244, -0.24, -0.236, -0.232, -0.228, -0.224, -0.22, -0.216, -0.212, -0.208, -0.204, -0.2, -0.198, -0.196, -0.194, -0.192, -0.19, -0.188, -0.186, -0.184, -0.182, -0.18, -0.178, -0.176, -0.174, -0.172, -0.17, -0.168, -0.166, -0.164, -0.162, -0.16, -0.158, -0.156, -0.154, -0.152, -0.15, -0.148, -0.146, -0.144, -0.142, -0.14, -0.138, -0.136, -0.134, -0.132, -0.13, -0.128, -0.126, -0.124, -0.122, -0.12, -0.118, -0.116, -0.114, -0.112, -0.11, -0.108, -0.106, -0.104, -0.102, -0.1, -0.099, -0.098, -0.097, -0.096, -0.095, -0.094, -0.093, -0.092, -0.091, -0.09, -0.089, -0.088, -0.087, -0.086, -0.085, -0.084, -0.083, -0.082, -0.081, -0.08, -0.079, -0.078, -0.077, -0.076, -0.075, -0.074, -0.073, -0.072, -0.071, -0.07, -0.069, -0.068, -0.067, -0.066, -0.065, -0.064, -0.063, -0.062, -0.061, -0.06, -0.059, -0.058, -0.057, -0.056, -0.055, -0.054, -0.053, -0.052, -0.051, -0.05, -0.049, -0.048, -0.047, -0.046, -0.045, -0.044, -0.043, -0.042, -0.041, -0.04, -0.039, -0.038, -0.037, -0.036, -0.035, -0.034, -0.033, -0.032, -0.031, -0.03, -0.029, -0.028, -0.027, -0.026, -0.025, -0.024, -0.023, -0.022, -0.021, -0.02, -0.019, -0.018, -0.017, -0.016, -0.015, -0.014, -0.013, -0.012, -0.011, -0.01, -0.009, -0.008, -0.007, -0.006, -0.005, -0.004, -0.003, -0.002, -0.001, -0.0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.029, 0.03, 0.031, 0.032, 0.033, 0.034, 0.035, 0.036, 0.037, 0.038, 0.039, 0.04, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046, 0.047, 0.048, 0.049, 0.05, 0.051, 0.052, 0.053, 0.054, 0.055, 0.056, 0.057, 0.058, 0.059, 0.06, 0.061, 0.062, 0.063, 0.064, 0.065, 0.066, 0.067, 0.068, 0.069, 0.07, 0.071, 0.072, 0.073, 0.074, 0.075, 0.076, 0.077, 0.078, 0.079, 0.08, 0.081, 0.082, 0.083, 0.084, 0.085, 0.086, 0.087, 0.088, 0.089, 0.09, 0.091, 0.092, 0.093, 0.094, 0.095, 0.096, 0.097, 0.098, 0.099, 0.1, 0.102, 0.104, 0.106, 0.108, 0.11, 0.112, 0.114, 0.116, 0.118, 0.12, 0.122, 0.124, 0.126, 0.128, 0.13, 0.132, 0.134, 0.136, 0.138, 0.14, 0.142, 0.144, 0.146, 0.148, 0.15, 0.152, 0.154, 0.156, 0.158, 0.16, 0.162, 0.164, 0.166, 0.168, 0.17, 0.172, 0.174, 0.176, 0.178, 0.18, 0.182, 0.184, 0.186, 0.188, 0.19, 0.192, 0.194, 0.196, 0.198, 0.2, 0.204, 0.208, 0.212, 0.216, 0.22, 0.224, 0.228, 0.232, 0.236, 0.24, 0.244, 0.248, 0.252, 0.256, 0.26, 0.264, 0.268, 0.272, 0.276, 0.28, 0.284, 0.288, 0.292, 0.296, 0.3, 0.304, 0.308, 0.312, 0.316, 0.32, 0.324, 0.328, 0.332, 0.336, 0.34, 0.344, 0.348, 0.352, 0.356, 0.36, 0.364, 0.368, 0.372, 0.376, 0.38, 0.384, 0.388, 0.392, 0.396, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0, 1.025, 1.05, 1.075, 1.1, 1.125, 1.15, 1.175, 1.2, 1.225, 1.25, 1.275, 1.3, 1.325, 1.35, 1.375, 1.4, 1.425, 1.45, 1.475, 1.5, 1.525, 1.55, 1.575, 1.6, 1.625, 1.65, 1.675, 1.7, 1.725, 1.75, 1.775, 1.8, 1.825, 1.85, 1.875, 1.9, 1.925, 1.95, 1.975, 2.0, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3.0}, "Binning of DCA xy and z axis"}; @@ -227,6 +237,8 @@ struct StrangenessInJetsIons { AxisSpec multAxis = {multBinning, multAxTitle}; const AxisSpec ptAxis{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptJetAxis{101, 0.0, 100.0, "#it{p}_{T,jet} (GeV/#it{c})"}; + const AxisSpec numJets{21, -0.5, 20.5, "Number of jets per collision"}; const AxisSpec invMassK0sAxis{200, 0.44, 0.56, "m_{#pi#pi} (GeV/#it{c}^{2})"}; const AxisSpec invMassLambdaAxis{200, 1.09, 1.14, "m_{p#pi} (GeV/#it{c}^{2})"}; const AxisSpec invMassXiAxis{200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}; @@ -255,7 +267,7 @@ struct StrangenessInJetsIons { } // Histograms for checks - registryQC.add("V0_type", "V0_type", HistType::kTH1F, {{10, -0.5, 9.5, "V0 type"}}); + // registryQC.add("V0_type", "V0_type", HistType::kTH1F, {{10, -0.5, 9.5, "V0 type"}}); // Histograms for real data if (doprocessData) { @@ -273,8 +285,12 @@ struct StrangenessInJetsIons { registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(7, "No empty events"); registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(8, "At least one jet"); + // Jet counters + registryData.add("n_jets_vs_mult_pT", "n_jets_vs_mult_pT", HistType::kTH2F, {multAxis, ptJetAxis}); + registryData.add("n_jets_vs_mult", "n_jets_vs_mult", HistType::kTH2F, {multAxis, numJets}); + // Armenteros-Podolanski plot - registryQC.add("ArmenterosPreSel_DATA", "ArmenterosPreSel_DATA", HistType::kTH2F, {alphaArmAxis, qtarmAxis}); + // registryQC.add("ArmenterosPreSel_DATA", "ArmenterosPreSel_DATA", HistType::kTH2F, {alphaArmAxis, qtarmAxis}); // Histograms for analysis of strange hadrons if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { @@ -323,6 +339,10 @@ struct StrangenessInJetsIons { // Add histogram to store multiplicity of the event registryMC.add("number_of_events_vsmultiplicity_gen", "number of events vs multiplicity", HistType::kTH1D, {{101, -0.5, 100.5, "Multiplicity percentile"}}); + // Jet counters + registryMC.add("n_jets_vs_mult_pT_mc_gen", "n_jets_vs_mult_pT_mc_gen", HistType::kTH2F, {multAxis, ptJetAxis}); + registryMC.add("n_jets_vs_mult_mc_gen", "n_jets_vs_mult_mc_gen", HistType::kTH2F, {multAxis, numJets}); + // Histograms for analysis if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { registryMC.add("K0s_generated_jet", "K0s_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); @@ -331,6 +351,11 @@ struct StrangenessInJetsIons { registryMC.add("Lambda_generated_ue", "Lambda_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("AntiLambda_generated_jet", "AntiLambda_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("AntiLambda_generated_ue", "AntiLambda_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + + // Histograms for the full event (without jets) + registryMC.add("K0s_generated_MB", "K0s_generated_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_generated_MB", "Lambda_generated_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_generated_MB", "AntiLambda_generated_MB", HistType::kTH2F, {multAxis, ptAxis}); } if (particleOfInterestDict[ParticleOfInterest::kCascades]) { registryMC.add("XiPos_generated_jet", "XiPos_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); @@ -341,18 +366,42 @@ struct StrangenessInJetsIons { registryMC.add("OmegaPos_generated_ue", "OmegaPos_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("OmegaNeg_generated_jet", "OmegaNeg_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("OmegaNeg_generated_ue", "OmegaNeg_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + + // Histograms for the full event (without jets) + registryMC.add("XiPos_generated_MB", "XiPos_generated_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiNeg_generated_MB", "XiNeg_generated_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaPos_generated_MB", "OmegaPos_generated_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaNeg_generated_MB", "OmegaNeg_generated_MB", HistType::kTH2F, {multAxis, ptAxis}); } if (particleOfInterestDict[ParticleOfInterest::kPions]) { - registryMC.add("Pion_generated_jet", "Pion_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); - registryMC.add("Pion_generated_ue", "Pion_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("PionPos_generated_jet", "PionPos_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("PionNeg_generated_jet", "PionNeg_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("PionPos_generated_ue", "PionPos_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("PionNeg_generated_ue", "PionNeg_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + + // Histograms for the full event (without jets) + registryMC.add("PionPos_generated_MB", "PionPos_generated_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("PionNeg_generated_MB", "PionNeg_generated_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); } if (particleOfInterestDict[ParticleOfInterest::kKaons]) { - registryMC.add("Kaon_generated_jet", "Kaon_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); - registryMC.add("Kaon_generated_ue", "Kaon_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("KaonPos_generated_jet", "KaonPos_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("KaonNeg_generated_jet", "KaonNeg_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("KaonPos_generated_ue", "KaonPos_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("KaonNeg_generated_ue", "KaonNeg_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + + // Histograms for the full event (without jets) + registryMC.add("KaonPos_generated_MB", "KaonPos_generated_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("KaonNeg_generated_MB", "KaonNeg_generated_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); } if (particleOfInterestDict[ParticleOfInterest::kProtons]) { - registryMC.add("Proton_generated_jet", "Proton_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); - registryMC.add("Proton_generated_ue", "Proton_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("ProtonPos_generated_jet", "ProtonPos_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("ProtonNeg_generated_jet", "ProtonNeg_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("ProtonPos_generated_ue", "ProtonPos_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("ProtonNeg_generated_ue", "ProtonNeg_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + + // Histograms for the full event (without jets) + registryMC.add("ProtonPos_generated_MB", "ProtonPos_generated_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("ProtonNeg_generated_MB", "ProtonNeg_generated_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); } } @@ -373,8 +422,12 @@ struct StrangenessInJetsIons { // Add histogram to store multiplicity of the event registryMC.add("number_of_events_vsmultiplicity_rec", "number of events vs multiplicity", HistType::kTH1D, {{101, -0.5, 100.5, "Multiplicity percentile"}}); + // Jet counters + registryMC.add("n_jets_vs_mult_pT_mc_rec", "n_jets_vs_mult_pT_mc_rec", HistType::kTH2F, {multAxis, ptJetAxis}); + registryMC.add("n_jets_vs_mult_mc_rec", "n_jets_vs_mult_mc_rec", HistType::kTH2F, {multAxis, numJets}); + // Armenteros-Podolanski plot - registryQC.add("ArmenterosPreSel_REC", "ArmenterosPreSel_REC", HistType::kTH2F, {alphaArmAxis, qtarmAxis}); + // registryQC.add("ArmenterosPreSel_REC", "ArmenterosPreSel_REC", HistType::kTH2F, {alphaArmAxis, qtarmAxis}); // Histograms for analysis if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { @@ -384,6 +437,7 @@ struct StrangenessInJetsIons { registryMC.add("Lambda_reconstructed_ue", "Lambda_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("AntiLambda_reconstructed_jet", "AntiLambda_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("AntiLambda_reconstructed_ue", "AntiLambda_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + // Histograms for secondary hadrons registryMC.add("K0s_reconstructed_jet_incl", "K0s_reconstructed_jet_incl", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("K0s_reconstructed_ue_incl", "K0s_reconstructed_ue_incl", HistType::kTH2F, {multAxis, ptAxis}); @@ -391,6 +445,19 @@ struct StrangenessInJetsIons { registryMC.add("Lambda_reconstructed_ue_incl", "Lambda_reconstructed_ue_incl", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("AntiLambda_reconstructed_jet_incl", "AntiLambda_reconstructed_jet_incl", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("AntiLambda_reconstructed_ue_incl", "AntiLambda_reconstructed_ue_incl", HistType::kTH2F, {multAxis, ptAxis}); + + // Histograms for generated particles in reconstructed events + registryMC.add("K0s_gen_recoEvent_jet", "K0s_gen_recoEvent_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("K0s_gen_recoEvent_ue", "K0s_gen_recoEvent_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_gen_recoEvent_jet", "Lambda_gen_recoEvent_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_gen_recoEvent_ue", "Lambda_gen_recoEvent_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_gen_recoEvent_jet", "AntiLambda_gen_recoEvent_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_gen_recoEvent_ue", "AntiLambda_gen_recoEvent_ue", HistType::kTH2F, {multAxis, ptAxis}); + + // Histograms for the full event (without jets) + registryMC.add("K0s_reconstructed_MB", "K0s_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_reconstructed_MB", "Lambda_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_reconstructed_MB", "AntiLambda_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxis}); } if (particleOfInterestDict[ParticleOfInterest::kCascades]) { registryMC.add("XiPos_reconstructed_jet", "XiPos_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); @@ -401,71 +468,39 @@ struct StrangenessInJetsIons { registryMC.add("OmegaPos_reconstructed_ue", "OmegaPos_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("OmegaNeg_reconstructed_jet", "OmegaNeg_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); registryMC.add("OmegaNeg_reconstructed_ue", "OmegaNeg_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + + // Histograms for the full event (without jets) + registryMC.add("XiPos_reconstructed_MB", "XiPos_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiNeg_reconstructed_MB", "XiNeg_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaPos_reconstructed_MB", "OmegaPos_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaNeg_reconstructed_MB", "OmegaNeg_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxis}); } if (particleOfInterestDict[ParticleOfInterest::kPions]) { registryMC.add("Pion_reconstructed_jet", "Pion_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); registryMC.add("Pion_reconstructed_ue", "Pion_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + + // Histograms for the full event (without jets) + registryMC.add("PionPos_reconstructed_MB", "PionPos_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("PionNeg_reconstructed_MB", "PionNeg_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); } if (particleOfInterestDict[ParticleOfInterest::kKaons]) { registryMC.add("Kaon_reconstructed_jet", "Kaon_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); registryMC.add("Kaon_reconstructed_ue", "Kaon_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + + // Histograms for the full event (without jets) + registryMC.add("KaonPos_reconstructed_MB", "KaonPos_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("KaonNeg_reconstructed_MB", "KaonNeg_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); } if (particleOfInterestDict[ParticleOfInterest::kProtons]) { registryMC.add("Proton_reconstructed_jet", "Proton_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); registryMC.add("Proton_reconstructed_ue", "Proton_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); - } - } - } - - /* - // Calculation of perpendicular axes - void getPerpendicularAxis(TVector3 p, TVector3& u, double sign) - { - // initialization - double ux(0), uy(0), uz(0); - - // components of vector p - const double px = p.X(); - const double py = p.Y(); - const double pz = p.Z(); - - // protection 1 - if (px == 0 && py != 0) { - uy = -(pz * pz) / py; - ux = sign * std::sqrt(py * py - (pz * pz * pz * pz) / (py * py)); - uz = pz; - u.SetXYZ(ux, uy, uz); - return; - } - - // protection 2 - if (py == 0 && px != 0) { - ux = -(pz * pz) / px; - uy = sign * std::sqrt(px * px - (pz * pz * pz * pz) / (px * px)); - uz = pz; - u.SetXYZ(ux, uy, uz); - return; - } - - // equation parameters - const double a = px * px + py * py; - const double b = 2.0 * px * pz * pz; - const double c = pz * pz * pz * pz - py * py * py * py - px * px * py * py; - const double delta = b * b - 4.0 * a * c; - // protection agains delta<0 - if (delta < 0) { - return; + // Histograms for the full event (without jets) + registryMC.add("ProtonPos_reconstructed_MB", "ProtonPos_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("ProtonNeg_reconstructed_MB", "ProtonNeg_reconstructed_MB", HistType::kTH2F, {multAxis, ptAxisLongLived}); + } } - - // solutions - ux = (-b + sign * std::sqrt(delta)) / (2.0 * a); - uy = (-pz * pz - px * ux) / py; - uz = pz; - u.SetXYZ(ux, uy, uz); - return; } - */ // Delta phi calculation double getDeltaPhi(double a1, double a2) @@ -649,10 +684,10 @@ struct StrangenessInJetsIons { return false; if (std::fabs(v0.dcanegtopv()) < configV0.dcaPionToPVmin) return false; - if (v0.v0Type() != configV0.v0type && configV0.requireV0type) { - registryQC.fill(HIST("V0_type"), v0.v0Type()); - return false; - } + // if (v0.v0Type() != configV0.v0type && configV0.requireV0type) { + // registryQC.fill(HIST("V0_type"), v0.v0Type()); + // return false; + // } // PID selections (TPC): positive track = proton, negative track = pion if (ptrack.tpcNSigmaPr() < configTracks.nsigmaTPCmin || ptrack.tpcNSigmaPr() > configTracks.nsigmaTPCmax) @@ -660,6 +695,14 @@ struct StrangenessInJetsIons { if (ntrack.tpcNSigmaPi() < configTracks.nsigmaTPCmin || ntrack.tpcNSigmaPi() > configTracks.nsigmaTPCmax) return false; + if (configV0.requireLambdaMassCuts && + std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < configV0.k0sRejWindow) + return false; + + if (configV0.requireLambdaMassCuts && + std::abs(v0.mLambda() - o2::constants::physics::MassLambda) > configV0.lamMassWindow) + return false; + // PID selections (TOF): positive track = proton, negative track = pion if (configTracks.requireTOF) { if (ptrack.tofNSigmaPr() < configTracks.nsigmaTOFmin || ptrack.tofNSigmaPr() > configTracks.nsigmaTOFmax) @@ -702,10 +745,10 @@ struct StrangenessInJetsIons { return false; if (std::fabs(v0.dcanegtopv()) < configV0.dcaProtonToPVmin) return false; - if (v0.v0Type() != configV0.v0type && configV0.requireV0type) { - registryQC.fill(HIST("V0_type"), v0.v0Type()); - return false; - } + // if (v0.v0Type() != configV0.v0type && configV0.requireV0type) { + // registryQC.fill(HIST("V0_type"), v0.v0Type()); + // return false; + // } // PID selections (TPC): negative track = proton, positive track = pion if (ptrack.tpcNSigmaPi() < configTracks.nsigmaTPCmin || ptrack.tpcNSigmaPi() > configTracks.nsigmaTPCmax) @@ -713,6 +756,14 @@ struct StrangenessInJetsIons { if (ntrack.tpcNSigmaPr() < configTracks.nsigmaTPCmin || ntrack.tpcNSigmaPr() > configTracks.nsigmaTPCmax) return false; + if (configV0.requireLambdaMassCuts && + std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < configV0.k0sRejWindow) + return false; + + if (configV0.requireLambdaMassCuts && + std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda) > configV0.lamMassWindow) + return false; + // PID selections (TOF): negative track = proton, positive track = pion if (configTracks.requireTOF) { if (ptrack.tofNSigmaPi() < configTracks.nsigmaTOFmin || ptrack.tofNSigmaPi() > configTracks.nsigmaTOFmax) @@ -760,10 +811,10 @@ struct StrangenessInJetsIons { if (v0.qtarm() < (configV0.paramArmenterosCut * std::abs(v0.alpha())) && (configV0.requireArmenterosCut)) return false; - if (v0.v0Type() != configV0.v0type && configV0.requireV0type) { - registryQC.fill(HIST("V0_type"), v0.v0Type()); - return false; - } + // if (v0.v0Type() != configV0.v0type && configV0.requireV0type) { + // registryQC.fill(HIST("V0_type"), v0.v0Type()); + // return false; + // } // PID selections (TPC) if (ptrack.tpcNSigmaPi() < configTracks.nsigmaTPCmin || ptrack.tpcNSigmaPi() > configTracks.nsigmaTPCmax) @@ -771,6 +822,15 @@ struct StrangenessInJetsIons { if (ntrack.tpcNSigmaPi() < configTracks.nsigmaTPCmin || ntrack.tpcNSigmaPi() > configTracks.nsigmaTPCmax) return false; + if (configV0.requireK0sMassCuts && + (std::abs(v0.mLambda() - o2::constants::physics::MassLambda) < configV0.lamRejWindow || + std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda) < configV0.lamRejWindow)) + return false; + + if (configV0.requireK0sMassCuts && + std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > configV0.k0sMassWindow) + return false; + // PID selections (TOF) if (configTracks.requireTOF) { if (ptrack.tofNSigmaPi() < configTracks.nsigmaTOFmin || ptrack.tofNSigmaPi() > configTracks.nsigmaTOFmax) @@ -1053,6 +1113,241 @@ struct StrangenessInJetsIons { return true; } + void FillFullEventHistoMCGEN(aod::McParticle const& particle, + const double& genMultiplicity) + { + if (particle.isPhysicalPrimary()) { + switch (particle.pdgCode()) { + case kK0Short: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kLambda0: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kLambda0Bar: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kXiMinus: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiNeg_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kXiPlusBar: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiPos_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kOmegaMinus: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaNeg_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kOmegaPlusBar: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaPos_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kPiPlus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("PionPos_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kKPlus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("KaonPos_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kProton: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ProtonPos_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kPiMinus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("PionNeg_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kKMinus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("KaonNeg_generated_MB"), genMultiplicity, particle.pt()); + } + break; + case kProtonBar: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ProtonNeg_generated_MB"), genMultiplicity, particle.pt()); + } + break; + default: + break; + } + } + } + + template + void FillFullEventHistoMCREC(MCRecoCollision collision, + aod::McParticles const& mcParticles, + V0PerColl const& v0sPerColl, + CascPerColl const& cascPerColl, + TracksPerColl const& tracksPerColl, + const double& multiplicity) + { + // V0 particles + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + for (const auto& v0 : v0sPerColl) { + const auto& pos = v0.template posTrack_as(); + const auto& neg = v0.template negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + // Get MC particles + if (!pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.template mcParticle_as(); + auto negParticle = neg.template mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers()) + continue; + + // Get Mothers + auto motherPos = mcParticles.iteratorAt(posParticle.mothersIds()[0]); + auto motherNeg = mcParticles.iteratorAt(negParticle.mothersIds()[0]); + if (motherPos != motherNeg) + continue; + if (!motherPos.isPhysicalPrimary()) + continue; + + if (std::abs(motherPos.eta()) > 0.8) + continue; + + // Vertex position vector + TVector3 vtxPos(collision.posX(), collision.posY(), collision.posZ()); + + // K0s + if (passedK0ShortSelection(v0, pos, neg, vtxPos) && motherPos.pdgCode() == kK0Short) { + registryMC.fill(HIST("K0s_reconstructed_MB"), multiplicity, v0.pt()); + } + // Lambda + if (passedLambdaSelection(v0, pos, neg, vtxPos) && motherPos.pdgCode() == kLambda0) { + registryMC.fill(HIST("Lambda_reconstructed_MB"), multiplicity, v0.pt()); + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg, vtxPos) && motherPos.pdgCode() == kLambda0Bar) { + registryMC.fill(HIST("AntiLambda_reconstructed_MB"), multiplicity, v0.pt()); + } + } + } + + // Cascades + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + for (const auto& casc : cascPerColl) { + auto bach = casc.template bachelor_as(); + auto pos = casc.template posTrack_as(); + auto neg = casc.template negTrack_as(); + + // Get MC particles + if (!bach.has_mcParticle() || !pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.template mcParticle_as(); + auto negParticle = neg.template mcParticle_as(); + auto bachParticle = bach.template mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers() || !bachParticle.has_mothers()) + continue; + + // Select particles originating from the same parent + auto motherPos = mcParticles.iteratorAt(posParticle.mothersIds()[0]); + auto motherNeg = mcParticles.iteratorAt(negParticle.mothersIds()[0]); + auto motherBach = mcParticles.iteratorAt(bachParticle.mothersIds()[0]); + if (motherPos != motherNeg) + continue; + if (std::abs(motherPos.pdgCode()) != kLambda0) + continue; + if (!motherBach.isPhysicalPrimary()) + continue; + + if (std::abs(motherPos.eta()) > 0.8) + continue; + + // Xi+ + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && motherBach.pdgCode() == kXiPlusBar) { + registryMC.fill(HIST("XiPos_reconstructed_MB"), multiplicity, casc.pt()); + } + // Xi- + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && motherBach.pdgCode() == kXiMinus) { + registryMC.fill(HIST("XiNeg_reconstructed_MB"), multiplicity, casc.pt()); + } + // Omega+ + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && motherBach.pdgCode() == kOmegaPlusBar) { + registryMC.fill(HIST("OmegaPos_reconstructed_MB"), multiplicity, casc.pt()); + } + // Omega- + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && motherBach.pdgCode() == kOmegaMinus) { + registryMC.fill(HIST("OmegaNeg_reconstructed_MB"), multiplicity, casc.pt()); + } + } + } + + if (particleOfInterestDict[ParticleOfInterest::kPions] || + particleOfInterestDict[ParticleOfInterest::kKaons] || + particleOfInterestDict[ParticleOfInterest::kProtons]) { + for (const auto& trk : tracksPerColl) { + + if (!trk.has_mcParticle()) { + continue; + } + if (!passedSingleTrackSelection(trk)) { + continue; + } + const auto& mcParticle = trk.template mcParticle_as(); + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + if (std::abs(mcParticle.eta()) > 0.8) { + continue; + } + + switch (mcParticle.pdgCode()) { + case kPiPlus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("PionPos_reconstructed_MB"), multiplicity, trk.pt()); + } + break; + case kPiMinus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("PionNeg_reconstructed_MB"), multiplicity, trk.pt()); + } + break; + case kKPlus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("KaonPos_reconstructed_MB"), multiplicity, trk.pt()); + } + break; + case kKMinus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("KaonNeg_reconstructed_MB"), multiplicity, trk.pt()); + } + break; + case kProton: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ProtonPos_reconstructed_MB"), multiplicity, trk.pt()); + } + break; + case kProtonBar: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ProtonNeg_reconstructed_MB"), multiplicity, trk.pt()); + } + break; + default: + break; + } + } + } + } + // Process data void processData(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, aod::CascDataExt const& Cascades, DaughterTracks const& tracks, @@ -1133,6 +1428,7 @@ struct StrangenessInJetsIons { std::vector selectedJet; std::vector ue1; std::vector ue2; + std::vector jetPt; // Loop over reconstructed jets for (const auto& jet : jets) { @@ -1160,6 +1456,7 @@ struct StrangenessInJetsIons { selectedJet.emplace_back(jetAxis); ue1.emplace_back(ueAxis1); ue2.emplace_back(ueAxis2); + jetPt.emplace_back(jetMinusBkg.pt()); } if (!isAtLeastOneJetSelected) return; @@ -1177,9 +1474,14 @@ struct StrangenessInJetsIons { // Fill event multiplicity registryData.fill(HIST("number_of_events_vsmultiplicity"), multiplicity); + registryData.fill(HIST("n_jets_vs_mult"), multiplicity, static_cast(selectedJet.size())); // Loop over selected jets for (int i = 0; i < static_cast(selectedJet.size()); i++) { + + // Fill jet counter + registryData.fill(HIST("n_jets_vs_mult_pT"), multiplicity, jetPt[i]); + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { // V0s for (const auto& v0 : fullV0s) { @@ -1203,7 +1505,7 @@ struct StrangenessInJetsIons { TVector3 vtxPos(collision.posX(), collision.posY(), collision.posZ()); // Fill Armenteros-Podolanski TH2 - registryQC.fill(HIST("ArmenterosPreSel_DATA"), v0.alpha(), v0.qtarm()); + // registryQC.fill(HIST("ArmenterosPreSel_DATA"), v0.alpha(), v0.qtarm()); // K0s if (passedK0ShortSelection(v0, pos, neg, vtxPos)) { @@ -1408,7 +1710,7 @@ struct StrangenessInJetsIons { // Require vertex position within the allowed z range if (std::fabs(collision.posZ()) > zVtx) - return; + continue; // Fill event counter after selection on z-vertex registryMC.fill(HIST("number_of_events_mc_gen"), 1.5); @@ -1431,18 +1733,21 @@ struct StrangenessInJetsIons { for (const auto& particle : mcParticlesPerColl) { // Store properties of strange hadrons int pdgAbs = std::abs(particle.pdgCode()); - if (particle.isPhysicalPrimary() && (pdgAbs == kK0Short || pdgAbs == kLambda0 || pdgAbs == kXiMinus || pdgAbs == kOmegaMinus)) { + if (particle.isPhysicalPrimary() && (pdgAbs == kK0Short || pdgAbs == kLambda0 || pdgAbs == kXiMinus || pdgAbs == kOmegaMinus)) { // TODO: add protons, kaons, pions pdg.emplace_back(particle.pdgCode()); strHadronMomentum.emplace_back(particle.px(), particle.py(), particle.pz()); } - // Select physical primary particles or HF decay products - if (!isPhysicalPrimaryOrFromHF(particle, mcParticles)) - continue; - double minPtParticle = 0.1; + double minPtParticle = 0.1f; if (particle.eta() < configTracks.etaMin || particle.eta() > configTracks.etaMax || particle.pt() < minPtParticle) continue; + FillFullEventHistoMCGEN(particle, genMultiplicity); + + // Select physical primary particles or HF decay products + if (!isPhysicalPrimaryOrFromHF(particle, mcParticles)) + continue; + // Build 4-momentum assuming charged pion mass static constexpr float kMassPionChargedSquared = o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged; const double energy = std::sqrt(particle.p() * particle.p() + kMassPionChargedSquared); @@ -1464,6 +1769,7 @@ struct StrangenessInJetsIons { auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); // Loop over clustered jets + int countSelJet = 0; // number of selected jets for (const auto& jet : jets) { // Jet must be fully contained in acceptance @@ -1477,9 +1783,13 @@ struct StrangenessInJetsIons { // Apply jet pT threshold if (jetMinusBkg.pt() < minJetPt) continue; + countSelJet++; registryMC.fill(HIST("number_of_events_mc_gen"), 3.5); registryMC.fill(HIST("number_of_events_vsmultiplicity_gen"), genMultiplicity); + // Fill jet counter + registryMC.fill(HIST("n_jets_vs_mult_pT_mc_gen"), genMultiplicity, jetMinusBkg.pt()); + // Set up two perpendicular cone axes for underlying event estimation TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); double coneRadius = std::sqrt(jet.area() / PI); @@ -1546,32 +1856,32 @@ struct StrangenessInJetsIons { break; case kPiPlus: if (particleOfInterestDict[ParticleOfInterest::kPions]) { - registryMC.fill(HIST("Pion_generated_jet"), genMultiplicity, hadron.Pt()); + registryMC.fill(HIST("PionPos_generated_jet"), genMultiplicity, hadron.Pt()); } break; case kKPlus: if (particleOfInterestDict[ParticleOfInterest::kKaons]) { - registryMC.fill(HIST("Kaon_generated_jet"), genMultiplicity, hadron.Pt()); + registryMC.fill(HIST("KaonPos_generated_jet"), genMultiplicity, hadron.Pt()); } break; case kProton: if (particleOfInterestDict[ParticleOfInterest::kProtons]) { - registryMC.fill(HIST("Proton_generated_jet"), genMultiplicity, hadron.Pt()); + registryMC.fill(HIST("ProtonPos_generated_jet"), genMultiplicity, hadron.Pt()); } break; case kPiMinus: if (particleOfInterestDict[ParticleOfInterest::kPions]) { - registryMC.fill(HIST("Pion_generated_jet"), genMultiplicity, hadron.Pt() * -1.f); + registryMC.fill(HIST("PionNeg_generated_jet"), genMultiplicity, hadron.Pt()); } break; case kKMinus: if (particleOfInterestDict[ParticleOfInterest::kKaons]) { - registryMC.fill(HIST("Kaon_generated_jet"), genMultiplicity, hadron.Pt() * -1.f); + registryMC.fill(HIST("KaonNeg_generated_jet"), genMultiplicity, hadron.Pt()); } break; case kProtonBar: if (particleOfInterestDict[ParticleOfInterest::kProtons]) { - registryMC.fill(HIST("Proton_generated_jet"), genMultiplicity, hadron.Pt() * -1.f); + registryMC.fill(HIST("ProtonNeg_generated_jet"), genMultiplicity, hadron.Pt()); } break; default: @@ -1619,32 +1929,32 @@ struct StrangenessInJetsIons { break; case kPiPlus: if (particleOfInterestDict[ParticleOfInterest::kPions]) { - registryMC.fill(HIST("Pion_generated_ue"), genMultiplicity, hadron.Pt()); + registryMC.fill(HIST("PionPos_generated_ue"), genMultiplicity, hadron.Pt()); } break; case kKPlus: if (particleOfInterestDict[ParticleOfInterest::kKaons]) { - registryMC.fill(HIST("Kaon_generated_ue"), genMultiplicity, hadron.Pt()); + registryMC.fill(HIST("KaonPos_generated_ue"), genMultiplicity, hadron.Pt()); } break; case kProton: if (particleOfInterestDict[ParticleOfInterest::kProtons]) { - registryMC.fill(HIST("Proton_generated_ue"), genMultiplicity, hadron.Pt()); + registryMC.fill(HIST("ProtonPos_generated_ue"), genMultiplicity, hadron.Pt()); } break; case kPiMinus: if (particleOfInterestDict[ParticleOfInterest::kPions]) { - registryMC.fill(HIST("Pion_generated_ue"), genMultiplicity, hadron.Pt() * -1.f); + registryMC.fill(HIST("PionNeg_generated_ue"), genMultiplicity, hadron.Pt()); } break; case kKMinus: if (particleOfInterestDict[ParticleOfInterest::kKaons]) { - registryMC.fill(HIST("Kaon_generated_ue"), genMultiplicity, hadron.Pt() * -1.f); + registryMC.fill(HIST("KaonNeg_generated_ue"), genMultiplicity, hadron.Pt()); } break; case kProtonBar: if (particleOfInterestDict[ParticleOfInterest::kProtons]) { - registryMC.fill(HIST("Proton_generated_ue"), genMultiplicity, hadron.Pt() * -1.f); + registryMC.fill(HIST("ProtonNeg_generated_ue"), genMultiplicity, hadron.Pt()); } break; default: @@ -1653,6 +1963,8 @@ struct StrangenessInJetsIons { } } } + // Fill jet counter + registryMC.fill(HIST("n_jets_vs_mult_mc_gen"), genMultiplicity, countSelJet); } } PROCESS_SWITCH(StrangenessInJetsIons, processMCgenerated, "Process MC generated events", false); @@ -1661,7 +1973,7 @@ struct StrangenessInJetsIons { void processMCreconstructed(SimCollisions const& collisions, soa::Join const&, DaughterTracksMC const& mcTracks, aod::V0Datas const& fullV0s, - aod::CascDataExt const& Cascades, const aod::McParticles&) + aod::CascDataExt const& Cascades, aod::McParticles const& mcParticles) { // Define per-event containers std::vector fjParticles; @@ -1721,10 +2033,15 @@ struct StrangenessInJetsIons { } else { multiplicity = mcCollision.centFT0M(); } + // Number of V0 and cascades per collision auto v0sPerColl = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); auto cascPerColl = Cascades.sliceBy(perCollisionCasc, collision.globalIndex()); auto tracksPerColl = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex()); + const auto& mcParticlesPerColl = mcParticles.sliceBy(perMCCollision, mcCollision.globalIndex()); + + FillFullEventHistoMCREC(collision, mcParticles, v0sPerColl, + cascPerColl, tracksPerColl, multiplicity); // Loop over reconstructed tracks for (auto const& track : tracksPerColl) { @@ -1748,6 +2065,7 @@ struct StrangenessInJetsIons { // Jet selection bool isAtLeastOneJetSelected = false; + std::vector jetPt; // Loop over clustered jets for (const auto& jet : jets) { @@ -1775,6 +2093,7 @@ struct StrangenessInJetsIons { selectedJet.emplace_back(jetAxis); ue1.emplace_back(ueAxis1); ue2.emplace_back(ueAxis2); + jetPt.emplace_back(jetMinusBkg.pt()); } if (!isAtLeastOneJetSelected) continue; @@ -1782,10 +2101,83 @@ struct StrangenessInJetsIons { // Fill event counter for events with at least one selected jet registryMC.fill(HIST("number_of_events_mc_rec"), 6.5); registryMC.fill(HIST("number_of_events_vsmultiplicity_rec"), multiplicity); + registryMC.fill(HIST("n_jets_vs_mult_mc_rec"), multiplicity, static_cast(selectedJet.size())); // Loop over selected jets for (int i = 0; i < static_cast(selectedJet.size()); i++) { + // Fill jet counter + registryMC.fill(HIST("n_jets_vs_mult_pT_mc_rec"), multiplicity, jetPt[i]); + + // ------------------------------------------------ + // --- Generated hadrons in reconstructed jets ---- + for (auto& particle : mcParticlesPerColl) { + if (!particle.isPhysicalPrimary() || std::abs(particle.eta()) > 0.8) + continue; + + int absPdg = std::abs(particle.pdgCode()); + if (absPdg != kK0Short && absPdg != kLambda0) + continue; + + TVector3 momVec(particle.px(), particle.py(), particle.pz()); + + // Compute distance of particles from jet and UE axes + const double deltaEtaJet = momVec.Eta() - selectedJet[i].Eta(); + const double deltaPhiJet = getDeltaPhi(momVec.Phi(), selectedJet[i].Phi()); + const double deltaRJet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const double deltaEtaUe1 = momVec.Eta() - ue1[i].Eta(); + const double deltaPhiUe1 = getDeltaPhi(momVec.Phi(), ue1[i].Phi()); + const double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const double deltaEtaUe2 = momVec.Eta() - ue2[i].Eta(); + const double deltaPhiUe2 = getDeltaPhi(momVec.Phi(), ue2[i].Phi()); + const double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Select particles inside jet + if (deltaRJet < rJet) { + switch (particle.pdgCode()) { + case kK0Short: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_gen_recoEvent_jet"), multiplicity, momVec.Pt()); + } + break; + case kLambda0: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_gen_recoEvent_jet"), multiplicity, momVec.Pt()); + } + break; + case kLambda0Bar: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_gen_recoEvent_jet"), multiplicity, momVec.Pt()); + } + break; + default: + break; + } + } + if (deltaRUe1 < rJet || deltaRUe2 < rJet) { + switch (particle.pdgCode()) { + case kK0Short: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_gen_recoEvent_ue"), multiplicity, momVec.Pt()); + } + break; + case kLambda0: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_gen_recoEvent_ue"), multiplicity, momVec.Pt()); + } + break; + case kLambda0Bar: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_gen_recoEvent_ue"), multiplicity, momVec.Pt()); + } + break; + default: + break; + } + } + } + // ---------------------------------------- + // V0 particles if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { for (const auto& v0 : v0sPerColl) { @@ -1830,7 +2222,7 @@ struct StrangenessInJetsIons { TVector3 vtxPos(collision.posX(), collision.posY(), collision.posZ()); // Fill Armenteros-Podolanski TH2 - registryQC.fill(HIST("ArmenterosPreSel_REC"), v0.alpha(), v0.qtarm()); + // registryQC.fill(HIST("ArmenterosPreSel_REC"), v0.alpha(), v0.qtarm()); // K0s if (passedK0ShortSelection(v0, pos, neg, vtxPos) && pdgParent == kK0Short && isPhysPrim) { @@ -1978,6 +2370,7 @@ struct StrangenessInJetsIons { } } } + jetPt.clear(); } } PROCESS_SWITCH(StrangenessInJetsIons, processMCreconstructed, "process reconstructed events", false); diff --git a/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx b/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx index 976e0f3a4bf..b3dca4c0a5c 100644 --- a/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx +++ b/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx @@ -15,7 +15,7 @@ /// \author Roman Lietava (roman.lietava@cern.ch) /*Description -This task creates up to 30 histograms that are filled with the V0 invariant mass under the K0, Lambda and Antilambda mass assumption +This task creates up to 30 histograms that are filled with the V0 invariant mass under the K0, Lambda and AntiLambda mass assumption for different pt ranges (constituting bins). The values are inserted as configurable strings for convinience. Also feed-down matrices for the Lambda and Anti-Lambda are produced. This analysis includes three processes, one for Real Data and two for MC at the Generated and Reconstructed level*/ @@ -70,6 +70,7 @@ struct V0PtInvMassPlots { HistogramRegistry rAntilambdaSplitMassPlotsPerPtBin{"AntiLambdaSplitMassPlotsPerPtBin", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rFeeddownMatrices{"FeeddownMatrices", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rMCCorrections{"MCCorrections", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rNchAnalysis{"NchAnalysis", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; // Configurable for histograms Configurable nBins{"nBins", 100, "N bins in all histos"}; @@ -81,6 +82,7 @@ struct V0PtInvMassPlots { Configurable nSigmaTPCProton{"nSigmaTPCProton", 4, "nSigmaTPCProton"}; Configurable compv0masscut{"compv0masscut", 0.01, "CompetitiveV0masscut (GeV)"}; Configurable etadau{"etadau", 0.8, "Eta Daughters"}; + Configurable etagen{"etagen", 0.8, "Eta Generated"}; Configurable rapidityCut{"rapidityCut", 0.5, "V0 Rapidity Window"}; Configurable itsMinHits{"itsMinHits", 1.0, "Minimum Hits of Daughter Tracks in the ITS"}; @@ -102,7 +104,7 @@ struct V0PtInvMassPlots { Configurable doitsMinHits{"doitsMinHits", true, "Enable ITS Minimum hits"}; // Configurables switches for K0sh selection - Configurable dotruthk0sh{"dotruthk0sh", true, "Enable K0sh MC Matching"}; + Configurable dotruthK0sh{"dotruthK0sh", true, "Enable K0sh MC Matching"}; Configurable doK0shTPCPID{"doK0shTPCPID", true, "Enable K0sh TPC PID"}; Configurable doK0shcomptmasscut{"doK0shcomptmasscut", true, "Enable K0sh Competitive V0 Mass Cut"}; Configurable doK0shMaxct{"doK0shMaxct", true, "Enable K0sh Max ct Cut"}; @@ -125,17 +127,17 @@ struct V0PtInvMassPlots { Configurable doLambdadcaposdautopv{"doLambdadcaposdautopv", true, "Enable Lambda DCA pos daughter to PV Topological Cut"}; Configurable doLambdadcanegdautopv{"doLambdadcanegdautopv", true, "Enable Lambda DCA neg daughter to PV Topological Cut"}; - // Configurables switches for Lambda selection - Configurable dotruthAntilambda{"dotruthAntilambda", true, "Enable Antilambda MC Matching"}; - Configurable doAntilambdaTPCPID{"doAntilambdaTPCPID", true, "Enable Antilambda TPC PID"}; - Configurable doAntilambdacomptmasscut{"doAntilambdacomptmasscut", true, "Enable Antilambda Competitive V0 Mass Cut"}; - Configurable doAntilambdaMaxct{"doAntilambdaMaxct", true, "Enable Antilambda Max ct Cut"}; - Configurable doAntilambdaArmenterosCut{"doAntilambdaArmenterosCut", true, "Enable Antilambda Armenteros Cut"}; - Configurable doAntilambdacosPACut{"doAntilambdacosPACut", true, "Enable Antilambda cosPA Topological Cut"}; - Configurable doAntilambdaDCAdauCut{"doAntilambdaDCAdauCut", true, "Enable Antilambda DCA daughters Topological Cut"}; - Configurable doAntilambdav0radiusCut{"doAntilambdav0radiusCut", true, "Enable Antilambda v0radius Topological Cut"}; - Configurable doAntilambdadcaposdautopv{"doAntilambdadcaposdautopv", true, "Enable Antilambda DCA pos daughter to PV Topological Cut"}; - Configurable doAntilambdadcanegdautopv{"doAntilambdadcanegdautopv", true, "Enable Antilambda DCA neg daughter to PV Topological Cut"}; + // Configurables switches for AntiLambda selection + Configurable dotruthAntiLambda{"dotruthAntiLambda", true, "Enable AntiLambda MC Matching"}; + Configurable doAntilambdaTPCPID{"doAntilambdaTPCPID", true, "Enable AntiLambda TPC PID"}; + Configurable doAntilambdacomptmasscut{"doAntilambdacomptmasscut", true, "Enable AntiLambda Competitive V0 Mass Cut"}; + Configurable doAntilambdaMaxct{"doAntilambdaMaxct", true, "Enable AntiLambda Max ct Cut"}; + Configurable doAntilambdaArmenterosCut{"doAntilambdaArmenterosCut", true, "Enable AntiLambda Armenteros Cut"}; + Configurable doAntilambdacosPACut{"doAntilambdacosPACut", true, "Enable AntiLambda cosPA Topological Cut"}; + Configurable doAntilambdaDCAdauCut{"doAntilambdaDCAdauCut", true, "Enable AntiLambda DCA daughters Topological Cut"}; + Configurable doAntilambdav0radiusCut{"doAntilambdav0radiusCut", true, "Enable AntiLambda v0radius Topological Cut"}; + Configurable doAntilambdadcaposdautopv{"doAntilambdadcaposdautopv", true, "Enable AntiLambda DCA pos daughter to PV Topological Cut"}; + Configurable doAntilambdadcanegdautopv{"doAntilambdadcanegdautopv", true, "Enable AntiLambda DCA neg daughter to PV Topological Cut"}; // Configurable K0sh Cuts (best cuts determined by v0topologicalcuts task) Configurable k0shSettingdcav0dau{"k0shSettingdcav0dau", 0.3, "DCA V0 Daughters"}; @@ -155,24 +157,25 @@ struct V0PtInvMassPlots { Configurable lambdamaxct{"lambdamaxct", 30.00, "Lambda maximum ct value"}; Configurable lambdaparamArmenterosCut{"lambdaparamArmenterosCut", 0.2, "Lambda Armenteros Cut on parameter"}; - // Configurable Antilambda Cuts (best cuts determined by v0topologicalcuts task) + // Configurable AntiLambda Cuts (best cuts determined by v0topologicalcuts task) Configurable antilambdaSettingdcav0dau{"antilambdaSettingdcav0dau", 0.3, "DCA V0 Daughters"}; Configurable antilambdaSettingdcapostopv{"antilambdaSettingdcapostopv", 0.09, "DCA Pos To PV"}; Configurable antilambdaSettingdcanegtopv{"antilambdaSettingdcanegtopv", 0.05, "DCA Neg To PV"}; Configurable antilambdaSettingcosPA{"antilambdaSettingcosPA", 0.98, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0 Configurable antilambdaSettingradius{"antilambdaSettingradius", 0.50, "v0radius"}; - Configurable antilambdamaxct{"antilambdamaxct", 30.00, "Antilambda maximum ct value"}; - Configurable antilambdaparamArmenterosCut{"antilambdaparamArmenterosCut", 0.2, "Antilambda Armenteros Cut on parameter"}; + Configurable antilambdamaxct{"antilambdamaxct", 30.00, "AntiLambda maximum ct value"}; + Configurable antilambdaparamArmenterosCut{"antilambdaparamArmenterosCut", 0.2, "AntiLambda Armenteros Cut on parameter"}; - // Configurables for Specific V0s analysis - Configurable kzeroAnalysis{"kzeroAnalysis", true, "Enable Kzerosh Pt Analysis"}; + // Configurables for Specific Analysis + Configurable kzeroAnalysis{"kzeroAnalysis", true, "Enable K0sh Pt Analysis"}; Configurable lambdaAnalysis{"lambdaAnalysis", true, "Enable Lambda Pt Analysis"}; - Configurable antiLambdaAnalysis{"antiLambdaAnalysis", true, "Enable Antilambda Pt Analysis"}; + Configurable antiLambdaAnalysis{"antiLambdaAnalysis", true, "Enable AntiLambda Pt Analysis"}; + Configurable doNchAnalysis{"doNchAnalysis", true, "Enable Nch vs Centrality Analysis"}; // Configurable string for Different Pt Bins - Configurable kzeroSettingPtBinsString{"kzeroSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "Kzero Pt Bin Values"}; + Configurable kzeroSettingPtBinsString{"kzeroSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "K0sh Pt Bin Values"}; Configurable lambdaSettingPtBinsString{"lambdaSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "Lambda Pt Bin Values"}; - Configurable antilambdaSettingPtBinsString{"antilambdaSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "Antilambda Pt Bin Values"}; + Configurable antilambdaSettingPtBinsString{"antilambdaSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "AntiLambda Pt Bin Values"}; void init(InitContext const&) { @@ -188,10 +191,10 @@ struct V0PtInvMassPlots { pthistos::kaonPt.resize(nKaonHistograms); // number of Kaon Pt histograms to expect pthistos::lambdaPt.resize(nLambdaHistograms); // number of Lambda histograms to expect - pthistos::antilambdaPt.resize(nAntilambdaHistograms); // number of Antilambda histograms to expect + pthistos::antilambdaPt.resize(nAntilambdaHistograms); // number of AntiLambda histograms to expect pthistos::kaonSplit.resize(nKaonHistograms); // number of Kaon Split Pt histograms to expect pthistos::lambdaSplit.resize(nLambdaHistograms); // number of Lambda Split Pt histograms to expect - pthistos::antilambdaSplit.resize(nAntilambdaHistograms); // number of Antilambda Split Pt histograms to expect + pthistos::antilambdaSplit.resize(nAntilambdaHistograms); // number of AntiLambda Split Pt histograms to expect // initialize and convert tokenized strings into vector of doubles for AxisSpec std::vector kaonptedgevalues(pthistos::kaonPtBins.size()); @@ -215,6 +218,7 @@ struct V0PtInvMassPlots { AxisSpec lambdaPtAxis = {lambdaptedgevalues, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec antilambdaPtAxis = {antilambdaptedgevalues, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec centAxis = {100, 0.0f, 100.0f, "#it{Centrality} (%)"}; + AxisSpec nchAxis = {100, 0.0f, 100.0f, "#it{N}_{ch} (%)"}; AxisSpec armenterosQtAxis = {nBinsArmenteros, 0.0f, 0.3f, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec armenterosasymAxis = {nBinsArmenteros, -1.f, 1.f, "#it{p}^{+}_{||}-#it{p}^{-}_{||}/#it{p}^{+}_{||}+#it{p}^{-}_{||}"}; AxisSpec vertexZAxis = {nBins, -11.0f, 11.0f, "vrtx_{Z} [cm]"}; @@ -257,7 +261,7 @@ struct V0PtInvMassPlots { rPtAnalysis.add("hV0EtaDaughters", "hV0EtaDaughters", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); rPtAnalysis.add("V0Rapidity", "V0Rapidity", {HistType::kTH1F, {{nBins, -1.0f, 1.0f}}}); - // Adding Kzerosh Histograms to registry + // Adding K0sh Histograms to registry if (kzeroAnalysis == true) { rPtAnalysis.add("hMassK0ShortvsCuts", "hMassK0ShortvsCuts", {HistType::kTH2F, {{partCutsAxis}, {k0ShortMassAxis}}}); rPtAnalysis.add("hArmenterosPodolanskiPlotK0sh", "hArmenterosPodolanskiPlotK0sh", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); @@ -277,7 +281,7 @@ struct V0PtInvMassPlots { } // Adding Lambda Histograms if (lambdaAnalysis == true) { - // same method as in Kzerosh above + // same method as in K0sh above rPtAnalysis.add("hMassLambdavsCuts", "hMassLambdavsCuts", {HistType::kTH2F, {{partCutsAxis}, {k0ShortMassAxis}}}); rPtAnalysis.add("hArmenterosPodolanskiPlotLambda", "hArmenterosPodolanskiPlotLambda", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); rPtAnalysis.add("hNSigmaPosProtonFromLambdas", "hNSigmaPosProtonFromLambdas", {HistType::kTH2F, {{100, -5.f, 5.f}, {lambdaPtAxis}}}); @@ -298,9 +302,9 @@ struct V0PtInvMassPlots { rFeeddownMatrices.add("hLambdaXiZeroFeeddownMatrix", "hLambdaXiZeroFeeddownMatrix", {HistType::kTH3D, {lambdaPtAxis, lambdaPtAxis, centAxis}}); rFeeddownMatrices.add("hLambdaOmegaFeeddownMatrix", "hLambdaOmegaFeeddownMatrix", {HistType::kTH3D, {lambdaPtAxis, lambdaPtAxis, centAxis}}); } - // Adding Antilambda Histograms + // Adding AntiLambda Histograms if (antiLambdaAnalysis == true) { - // same method as in Lambda and Kzerosh above + // same method as in Lambda and K0sh above rPtAnalysis.add("hMassAntiLambdavsCuts", "hMassAntiLambdavsCuts", {HistType::kTH2F, {{partCutsAxis}, {k0ShortMassAxis}}}); rPtAnalysis.add("hArmenterosPodolanskiPlotAntiLambda", "hArmenterosPodolanskiPlotAntiLambda", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); rPtAnalysis.add("hNSigmaPosPionFromAntiLambdas", "hNSigmaPosPionFromAntiLambdas", {HistType::kTH2F, {{100, -5.f, 5.f}, {antilambdaPtAxis}}}); @@ -344,6 +348,12 @@ struct V0PtInvMassPlots { rMCCorrections.add("hAntiXiZeroGeneratedPtSpectrum", "hAntiXiZeroGeneratedPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); rMCCorrections.add("hAntiOmegaGeneratedPtSpectrum", "hAntiOmegaGeneratedPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); rMCCorrections.add("hPhiGeneratedPtSpectrum", "hPhiGeneratedPtSpectrum", {HistType::kTH2D, {k0ShortPtAxis, centAxis}}); + rMCCorrections.add("hGenPartcles", "hGenPartcles", {HistType::kTH2D, {nchAxis, centAxis}}); + + // NCh Analysis + rNchAnalysis.add("hNchCentralityGenerated", "hNchCentralityGenerated", {HistType::kTH2D, {centAxis, nchAxis}}); // Nch vs Centrality Generated + rNchAnalysis.add("hNchCentralityGeneratedAfterEventSelection", "hNchCentralityGeneratedAfterEventSelection", {HistType::kTH2D, {centAxis, nchAxis}}); // Nch vs Centrality Generated After Event Selection + rNchAnalysis.add("hNchCentrality", "hNchCentrality", {HistType::kTH2D, {centAxis, nchAxis}}); // Nch vs Centrality } // Event selection function @@ -388,6 +398,39 @@ struct V0PtInvMassPlots { return true; } + // Charged Particle Selection Function + template + bool acceptGeneratedParticle(TParticle const& particle, TCollision const& mcCollision) + { + rMCCorrections.fill(HIST("hGenPartcles"), 0.5, mcCollision.centFT0M()); + rMCCorrections.get(HIST("hGenPartcles"))->GetXaxis()->SetBinLabel(1, "All Gen Particles"); + if (!particle.isPhysicalPrimary()) { // Daughters Pseudorapidity Cut + return false; + } + rMCCorrections.fill(HIST("hGenPartcles"), 1.5, mcCollision.centFT0M()); + rMCCorrections.get(HIST("hGenPartcles"))->GetXaxis()->SetBinLabel(2, "Physical Primary"); + if (!particle.producedByGenerator()) { + return false; + } + rMCCorrections.fill(HIST("hGenPartcles"), 2.5, mcCollision.centFT0M()); + rMCCorrections.get(HIST("hGenPartcles"))->GetXaxis()->SetBinLabel(3, "Produced by Generator"); + if (std::abs(particle.eta()) > etagen) { // Eta cut + return false; + } + rMCCorrections.fill(HIST("hGenPartcles"), 3.5, mcCollision.centFT0M()); + rMCCorrections.get(HIST("hGenPartcles"))->GetXaxis()->SetBinLabel(4, "Eta Cut"); + auto pdgParticle = pdgDB->GetParticle(particle.pdgCode()); + if (pdgParticle == nullptr) { + return false; + } + if (std::abs(pdgParticle->Charge()) < 3) { + return false; + } + rMCCorrections.fill(HIST("hGenPartcles"), 4.5, mcCollision.centFT0M()); + rMCCorrections.get(HIST("hGenPartcles"))->GetXaxis()->SetBinLabel(4, "Charge Cut"); + return true; + } + // V0 selection function template bool acceptV0(TV0 const& v0, Track const& posDaughterTrack, Track const& negDaughterTrack, TCollision const& collision) @@ -436,7 +479,7 @@ struct V0PtInvMassPlots { rPtAnalysis.fill(HIST("hNK0sh"), 2.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(3, "TPC_PID"); rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 2.5, v0.mK0Short()); - if (doK0shcomptmasscut && ((std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < compv0masscut) || (std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < compv0masscut))) { // Kzero competitive v0 mass cut (cut out Lambdas and Anti-Lambdas) + if (doK0shcomptmasscut && ((std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < compv0masscut) || (std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < compv0masscut))) { // K0sh competitive v0 mass cut (cut out Lambdas and Anti-Lambdas) return false; } rPtAnalysis.fill(HIST("hNK0sh"), 3.5, collision.centFT0M()); @@ -580,7 +623,7 @@ struct V0PtInvMassPlots { return true; } - // Antilambda selection function + // AntiLambda selection function template bool acceptAntilambda(TV0 const& v0, Track const& posDaughterTrack, Track const& negDaughterTrack, TCollision const& collision) { @@ -600,64 +643,64 @@ struct V0PtInvMassPlots { rPtAnalysis.fill(HIST("hNAntiLambda"), 2.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(3, "TPC_PID"); rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 2.5, v0.mAntiLambda()); - if (doAntilambdacomptmasscut && ((std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < compv0masscut) || (std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < compv0masscut))) { // Antilambda competitive v0 mass cut (cut out Kaons) + if (doAntilambdacomptmasscut && ((std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < compv0masscut) || (std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < compv0masscut))) { // AntiLambda competitive v0 mass cut (cut out Kaons) return false; } rPtAnalysis.fill(HIST("hNAntiLambda"), 3.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(4, "Compt_Mass"); rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 3.5, v0.mAntiLambda()); - if (doAntilambdaMaxct && (v0.v0radius() > antilambdamaxct)) { // Antilambda max ct + if (doAntilambdaMaxct && (v0.v0radius() > antilambdamaxct)) { // AntiLambda max ct return false; } rPtAnalysis.fill(HIST("hNAntiLambda"), 4.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(5, "Max_ct"); rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 4.5, v0.mAntiLambda()); - if (doAntilambdaArmenterosCut && (v0.qtarm() < (antilambdaparamArmenterosCut * std::abs(v0.alpha())))) { // Antilambda Armenteros Cut + if (doAntilambdaArmenterosCut && (v0.qtarm() < (antilambdaparamArmenterosCut * std::abs(v0.alpha())))) { // AntiLambda Armenteros Cut return false; } rPtAnalysis.fill(HIST("hNAntiLambda"), 5.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(6, "Armenteros"); rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 5.5, v0.mAntiLambda()); - if (doAntilambdacosPACut && (v0.v0cosPA() < antilambdaSettingcosPA)) { // Antilambda cosPA Topological Cut + if (doAntilambdacosPACut && (v0.v0cosPA() < antilambdaSettingcosPA)) { // AntiLambda cosPA Topological Cut return false; } rPtAnalysis.fill(HIST("hNAntiLambda"), 6.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(7, "cosPA"); rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 6.5, v0.mAntiLambda()); - if (doAntilambdaDCAdauCut && (v0.dcaV0daughters() > antilambdaSettingdcav0dau)) { // Antilambda DCAdaughters Topological Cut + if (doAntilambdaDCAdauCut && (v0.dcaV0daughters() > antilambdaSettingdcav0dau)) { // AntiLambda DCAdaughters Topological Cut return false; } rPtAnalysis.fill(HIST("hNAntiLambda"), 7.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(8, "DCAdau"); rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 7.5, v0.mAntiLambda()); - if (doAntilambdav0radiusCut && (v0.v0radius() < antilambdaSettingradius)) { // Antilambda v0radius Topological Cut + if (doAntilambdav0radiusCut && (v0.v0radius() < antilambdaSettingradius)) { // AntiLambda v0radius Topological Cut return false; } rPtAnalysis.fill(HIST("hNAntiLambda"), 8.5, collision.centFT0M()); rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(9, "v0radius"); rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 8.5, v0.mAntiLambda()); - if (doAntilambdadcaposdautopv && (std::abs(v0.dcapostopv()) < antilambdaSettingdcapostopv)) { // Antilambda DCAPosDaughterToPV Topological Cut + if (doAntilambdadcaposdautopv && (std::abs(v0.dcapostopv()) < antilambdaSettingdcapostopv)) { // AntiLambda DCAPosDaughterToPV Topological Cut return false; } - rPtAnalysis.fill(HIST("hNAntilambda"), 9.5, collision.centFT0M()); - rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(10, "DCAPosDautoPV"); - rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 9.5, v0.mAntiLambda()); - if (doAntilambdadcanegdautopv && (std::abs(v0.dcanegtopv()) < antilambdaSettingdcanegtopv)) { // Antilambda DCANegDaughterToPV Topological Cut + rPtAnalysis.fill(HIST("hNAntiLambda"), 9.5, collision.centFT0M()); + rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(10, "DCAPosDautoPV"); + rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 9.5, v0.mAntiLambda()); + if (doAntilambdadcanegdautopv && (std::abs(v0.dcanegtopv()) < antilambdaSettingdcanegtopv)) { // AntiLambda DCANegDaughterToPV Topological Cut return false; } - rPtAnalysis.fill(HIST("hNAntilambda"), 10.5, collision.centFT0M()); - rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(11, "DCANegDautoPV"); - rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 10.5, v0.mAntiLambda()); + rPtAnalysis.fill(HIST("hNAntiLambda"), 10.5, collision.centFT0M()); + rPtAnalysis.get(HIST("hNAntiLambda"))->GetXaxis()->SetBinLabel(11, "DCANegDautoPV"); + rPtAnalysis.fill(HIST("hMassAntiLambdavsCuts"), 10.5, v0.mAntiLambda()); // Cut plots - rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotAntilambda"), v0.alpha(), v0.qtarm()); + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotAntiLambda"), v0.alpha(), v0.qtarm()); // rPtAnalysis.fill(HIST("hNSigmaPosPionFromAntilambdas"), posDaughterTrack.tpcNSigmaPr(), posDaughterTrack.tpcInnerParam()); // rPtAnalysis.fill(HIST("hNSigmaNegProtonFromAntilambdas"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); - rPtAnalysis.fill(HIST("hAntilambdacosPA"), v0.v0cosPA()); - rPtAnalysis.fill(HIST("hAntilambdaV0radius"), v0.v0radius()); - rPtAnalysis.fill(HIST("hAntilambdaDCAV0Daughters"), v0.dcaV0daughters()); - rPtAnalysis.fill(HIST("hAntilambdaDCAPosDaughter"), v0.dcapostopv()); - rPtAnalysis.fill(HIST("hAntilambdaDCANegDaughter"), v0.dcanegtopv()); + rPtAnalysis.fill(HIST("hAntiLambdacosPA"), v0.v0cosPA()); + rPtAnalysis.fill(HIST("hAntiLambdaV0radius"), v0.v0radius()); + rPtAnalysis.fill(HIST("hAntiLambdaDCAV0Daughters"), v0.dcaV0daughters()); + rPtAnalysis.fill(HIST("hAntiLambdaDCAPosDaughter"), v0.dcapostopv()); + rPtAnalysis.fill(HIST("hAntiLambdaDCANegDaughter"), v0.dcanegtopv()); rPtAnalysis.fill(HIST("V0Rapidity"), v0.rapidity(2)); return true; } @@ -697,7 +740,7 @@ struct V0PtInvMassPlots { // This is the process for Generated Particles void genMCProcess(soa::Join::iterator const& mcCollision, - soa::SmallGroups> const& collisions, + soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles) { // Event Efficiency, Event Split and V0 Signal Loss Corrections @@ -710,20 +753,21 @@ struct V0PtInvMassPlots { return; } rMCCorrections.fill(HIST("hNEvents_Corrections"), 1.5, mcCollision.centFT0M()); // Event Efficiency Denominator + int NParticlesPerCollision = 0; // Counter for the number of particles per collision for the Nch analysis // Particles (of interest) Generated Pt Spectrum and Signal Loss Denominator Loop for (const auto& mcParticle : mcParticles) { if (std::abs(mcParticle.y()) < rapidityCut) { if (mcParticle.isPhysicalPrimary()) { rMCCorrections.fill(HIST("GenParticleRapidity"), mcParticle.y()); - if (mcParticle.pdgCode() == kK0Short) // kzero matched + if (mcParticle.pdgCode() == kK0Short) // K0sh matched { rMCCorrections.fill(HIST("hK0shGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); } - if (mcParticle.pdgCode() == kLambda0) // lambda matched + if (mcParticle.pdgCode() == kLambda0) // Lambda matched { rMCCorrections.fill(HIST("hLambdaGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); } - if (mcParticle.pdgCode() == kLambda0Bar) // antilambda matched + if (mcParticle.pdgCode() == kLambda0Bar) // AntiLambda matched { rMCCorrections.fill(HIST("hAntiLambdaGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); } @@ -757,7 +801,11 @@ struct V0PtInvMassPlots { } } } + if (acceptGeneratedParticle(mcParticle, mcCollision)) { + NParticlesPerCollision++; + } } + rNchAnalysis.fill(HIST("hNchCentralityGenerated"), mcCollision.centFT0M(), NParticlesPerCollision); // Signal Loss Numenator Loop for (const auto& collision : collisions) { rMCCorrections.fill(HIST("hNEvents_Corrections"), 2.5, mcCollision.centFT0M()); // Number of Events Reconsctructed @@ -766,6 +814,9 @@ struct V0PtInvMassPlots { } rMCCorrections.fill(HIST("hNEvents_Corrections"), 3.5, mcCollision.centFT0M()); // Event Split Denomimator and Event Efficiency Numenator for (const auto& mcParticle : mcParticles) { + if (acceptGeneratedParticle(mcParticle, mcCollision)) { + NParticlesPerCollision++; // Counter to fill the NchCerntralityPlot after the loop + } if (!mcParticle.isPhysicalPrimary()) { continue; } @@ -786,10 +837,12 @@ struct V0PtInvMassPlots { } } } + rNchAnalysis.fill(HIST("hNchCentralityGeneratedAfterEventSelection"), mcCollision.centFT0M(), NParticlesPerCollision); // End of Signal Loss Numenator Loop } // This is the Process for the MC reconstructed Data - void recMCProcess(soa::Join::iterator const& collision, + // void recMCProcess(soa::Join::iterator const& collision, + void recMCProcess(soa::Join::iterator const& collision, soa::Join const& /*mcCollisions*/, soa::Join const& V0s, DaughterTracks const&, // no need to define a variable for tracks, if we don't access them directly @@ -826,7 +879,8 @@ struct V0PtInvMassPlots { if (!acceptEvent(collision)) { // Event Selection return; } - rPtAnalysis.fill(HIST("hNRecEvents"), 0.5, mcCollision.centFT0M()); // Event Split Numenator + rPtAnalysis.fill(HIST("hNRecEvents"), 0.5, mcCollision.centFT0M()); // Event Split Numenator + rNchAnalysis.fill(HIST("hNchCentrality"), mcCollision.centFT0M(), collision.multNTracksGlobal()); // Nch vs Centrality for (const auto& v0 : V0s) { // Checking that the V0 is a true K0s/Lambdas/Antilambdas and then filling the parameter histograms and the invariant mass plots for different cuts (which are taken from namespace) const auto& posDaughterTrack = v0.template posTrack_as(); @@ -846,7 +900,7 @@ struct V0PtInvMassPlots { // K0sh Signla Split Numerator End if (v0.has_mcParticle()) { auto v0mcParticle = v0.mcParticle(); - if (dotruthk0sh && (v0mcParticle.pdgCode() == kK0Short)) { // kzero matched + if (dotruthK0sh && (v0mcParticle.pdgCode() == kK0Short)) { // kzero matched if (v0mcParticle.isPhysicalPrimary()) { for (int i = 0; i < nKaonHistograms; i++) { if (kaonptedgevalues[i] <= v0.pt() && v0.pt() < kaonptedgevalues[i + 1]) { // finding v0s with pt within the range of our bin edges @@ -910,17 +964,17 @@ struct V0PtInvMassPlots { } // antilambda analysis if (antiLambdaAnalysis == true) { - if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, mcCollision)) { // Antilambda Selections - // Antilambda Signal Split Numerator End + if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, mcCollision)) { // AntiLambda Selections + // AntiLambda Signal Split Numerator End for (int i = 0; i < nAntilambdaHistograms; i++) { if (antilambdaptedgevalues[i] <= v0.pt() && v0.pt() < antilambdaptedgevalues[i + 1]) { pthistos::antilambdaSplit[i]->Fill(v0.mAntiLambda(), mcCollision.centFT0M()); } } - // Antilambda Signal Split Numerator End + // AntiLambda Signal Split Numerator End if (v0.has_mcParticle()) { auto v0mcParticle = v0.mcParticle(); - if (dotruthAntilambda && (v0mcParticle.pdgCode() == kLambda0Bar)) { // antilambda matched + if (dotruthAntiLambda && (v0mcParticle.pdgCode() == kLambda0Bar)) { // antilambda matched if (v0mcParticle.isPhysicalPrimary()) { for (int i = 0; i < nAntilambdaHistograms; i++) { if (antilambdaptedgevalues[i] <= v0.pt() && v0.pt() < antilambdaptedgevalues[i + 1]) { @@ -951,7 +1005,7 @@ struct V0PtInvMassPlots { } } // This is the process for Real Data - void dataProcess(soa::Join::iterator const& collision, + void dataProcess(soa::Join::iterator const& collision, aod::V0Datas const& V0s, DaughterTracks const&) { @@ -980,11 +1034,11 @@ struct V0PtInvMassPlots { for (int i = 0; i < nAntilambdaHistograms + 1; i++) { antilambdaptedgevalues[i] = std::stod(pthistos::antilambdaPtBins[i]); } - - // if (!acceptEvent(collision)) { // Event Selection - // return; - // } - rPtAnalysis.fill(HIST("hNRecEvents"), 0.5, collision.centFT0M()); // Number of recorded events + if (!acceptEvent(collision)) { // Event Selection + return; + } + rPtAnalysis.fill(HIST("hNRecEvents"), 0.5, collision.centFT0M()); // Number of recorded events + rNchAnalysis.fill(HIST("hNchCentrality"), collision.centFT0M(), collision.multNTracksGlobal()); // Nch vs Centrality for (const auto& v0 : V0s) { // Checking that the V0 is a true K0s/Lambdas/Antilambdas and then filling the parameter histograms and the invariant mass plots for different cuts (which are taken from namespace) const auto& posDaughterTrack = v0.template posTrack_as(); @@ -992,7 +1046,7 @@ struct V0PtInvMassPlots { if (!acceptV0(v0, posDaughterTrack, negDaughterTrack, collision)) { // V0 Selection continue; } - // kzero analysis + // K0sh analysis if (kzeroAnalysis == true) { if (acceptK0sh(v0, posDaughterTrack, negDaughterTrack, collision)) { // K0sh Selection for (int i = 0; i < nKaonHistograms; i++) { @@ -1002,7 +1056,7 @@ struct V0PtInvMassPlots { } } } - // lambda analysis + // Lambda analysis if (lambdaAnalysis == true) { if (acceptLambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // Lambda Selection for (int i = 0; i < nLambdaHistograms; i++) { @@ -1012,9 +1066,9 @@ struct V0PtInvMassPlots { } } } - // anti-lambda analysis + // Anti-Lambda analysis if (antiLambdaAnalysis == true) { - if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // Antilambda Selection + if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // AntiLambda Selection for (int i = 0; i < nAntilambdaHistograms; i++) { if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { pthistos::antilambdaPt[i]->Fill(v0.mAntiLambda(), collision.centFT0M()); @@ -1066,7 +1120,7 @@ struct V0PtInvMassPlots { if (!acceptV0Derived(v0, posDaughterTrack, negDaughterTrack, collision)) { // V0 Selection continue; } - // kzero analysis + // K0sh analysis if (kzeroAnalysis == true) { if (acceptK0sh(v0, posDaughterTrack, negDaughterTrack, collision)) { // K0sh Selection for (int i = 0; i < nKaonHistograms; i++) { @@ -1076,7 +1130,7 @@ struct V0PtInvMassPlots { } } } - // lambda analysis + // Lambda analysis if (lambdaAnalysis == true) { if (acceptLambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // Lambda Selection for (int i = 0; i < nLambdaHistograms; i++) { @@ -1086,9 +1140,9 @@ struct V0PtInvMassPlots { } } } - // anti-lambda analysis + // Anti-Lambda analysis if (antiLambdaAnalysis == true) { - if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // Antilambda Selection + if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // AntiLambda Selection for (int i = 0; i < nAntilambdaHistograms; i++) { if (antilambdaptedgevalues[i] <= v0.pt() && v0.pt() < antilambdaptedgevalues[i + 1]) { pthistos::antilambdaPt[i]->Fill(v0.mAntiLambda(), collision.centFT0M()); @@ -1139,7 +1193,7 @@ struct V0PtInvMassPlots { if (!acceptV0Derived(v0, posDaughterTrack, negDaughterTrack, collision)) { // V0 Selections continue; } - // kzero analysis + // K0sh Analysis if (kzeroAnalysis == true) { if (acceptK0sh(v0, posDaughterTrack, negDaughterTrack, collision)) { // K0sh Selection // K0sh Signal Split Numerator Start @@ -1151,7 +1205,7 @@ struct V0PtInvMassPlots { // K0sh SignaL Split Numerator End if (v0.has_v0MCCore()) { auto v0mcParticle = v0.v0MCCore_as(); - if (dotruthk0sh && (v0mcParticle.pdgCode() == kK0Short)) { // kzero matched + if (dotruthK0sh && (v0mcParticle.pdgCode() == kK0Short)) { // kzero matched if (v0mcParticle.isPhysicalPrimary()) { for (int i = 0; i < nKaonHistograms; i++) { if (kaonptedgevalues[i] <= v0.ptMC() && v0.ptMC() < kaonptedgevalues[i + 1]) { // finding v0s with pt within the range of our bin edges @@ -1170,7 +1224,7 @@ struct V0PtInvMassPlots { } } } - // lambda analysis + // Lambda analysis if (lambdaAnalysis == true) { if (acceptLambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // Lambda Selections // Lambda Signal Split Numerator Start @@ -1207,19 +1261,19 @@ struct V0PtInvMassPlots { } } } - // antilambda analysis + // AntiLambda analysis if (antiLambdaAnalysis == true) { - if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // Antilambda Selections - // Antilambda Signal Split Numerator End + if (acceptAntilambda(v0, posDaughterTrack, negDaughterTrack, collision)) { // AntiLambda Selections + // AntiLambda Signal Split Numerator End for (int i = 0; i < nAntilambdaHistograms; i++) { if (antilambdaptedgevalues[i] <= v0.ptMC() && v0.ptMC() < antilambdaptedgevalues[i + 1]) { pthistos::antilambdaSplit[i]->Fill(v0.mAntiLambda(), collision.centFT0M()); } } - // Antilambda Signal Split Numerator End + // AntiLambda Signal Split Numerator End if (v0.has_v0MCCore()) { auto v0mcParticle = v0.v0MCCore_as(); - if (dotruthAntilambda && (v0mcParticle.pdgCode() == kLambda0Bar)) { // antilambda matched + if (dotruthAntiLambda && (v0mcParticle.pdgCode() == kLambda0Bar)) { // antilambda matched if (v0mcParticle.isPhysicalPrimary()) { for (int i = 0; i < nAntilambdaHistograms; i++) { if (antilambdaptedgevalues[i] <= v0.ptMC() && v0.ptMC() < antilambdaptedgevalues[i + 1]) { diff --git a/PWGLF/Tasks/Strangeness/zdccalderived.cxx b/PWGLF/Tasks/Strangeness/zdccalderived.cxx index 5d8776345d1..f92540cca05 100644 --- a/PWGLF/Tasks/Strangeness/zdccalderived.cxx +++ b/PWGLF/Tasks/Strangeness/zdccalderived.cxx @@ -116,8 +116,8 @@ struct zdccalderived { Configurable useShift{"useShift", false, "shift histograms"}; Configurable ispolarization{"ispolarization", false, "Flag to check polarization"}; Configurable followpub{"followpub", true, "flag to use alphaZDC"}; - Configurable useGainCallib{"useGainCallib", false, "use gain calibration"}; - Configurable useCallibvertex{"useCallibvertex", false, "use calibration for vxy"}; + // Configurable useGainCallib{"useGainCallib", false, "use gain calibration"}; + // Configurable useCallibvertex{"useCallibvertex", false, "use calibration for vxy"}; Configurable coarse1{"coarse1", false, "RE1"}; Configurable fine1{"fine1", false, "REfine1"}; Configurable coarse2{"coarse2", false, "RE2"}; @@ -133,8 +133,6 @@ struct zdccalderived { Configurable useRecentereSp{"useRecentereSp", false, "use Recentering with Sparse or THn"}; Configurable useRecenterefineSp{"useRecenterefineSp", false, "use fine Recentering with THn"}; - Configurable confGainPath{"confGainPath", "Users/p/prottay/My/Object/NewPbPbpass4_10092024/gaincallib", "Path to gain calibration"}; - Configurable confGainPathVxy{"confGainPathVxy", "Users/p/prottay/My/Object/swapcoords/PbPbpass4_20112024/recentervert", "Path to gain calibration for vxy"}; Configurable confRecentereSp{"confRecentereSp", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn path for recentering"}; Configurable confRecentereSp2{"confRecentereSp2", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn path for recentering 2"}; Configurable confRecentereSp3{"confRecentereSp3", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn path for recentering 3"}; @@ -354,20 +352,20 @@ struct zdccalderived { auto vx = collision.vx(); auto vy = collision.vy(); - float psiZDCC = -99; - float psiZDCA = -99; - auto qxZDCA = 0.0; - auto qxZDCC = 0.0; - auto qyZDCA = 0.0; - auto qyZDCC = 0.0; - auto sumA = 0.0; - auto sumC = 0.0; + double psiZDCC = -99; + double psiZDCA = -99; + auto qxZDCA = collision.qxA(); + auto qxZDCC = collision.qxC(); + auto qyZDCA = collision.qyA(); + auto qyZDCC = collision.qyC(); + // auto sumA = 0.0; + // auto sumC = 0.0; auto timestamps = ccdb->getRunDuration(currentRunNumber, true); /// fatalise if timestamps are not found int64_t sorTimestamp = timestamps.first; // timestamp of the SOR/SOX/STF in ms int64_t eorTimestamp = timestamps.second; // timestamp of the EOR/EOX/ETF in ms int64_t ts = eorTimestamp / 2 + sorTimestamp / 2; // timestamp of the middle of the run - + /* std::array znaEnergy = { collision.znaE0(), collision.znaE1(), @@ -442,14 +440,14 @@ struct zdccalderived { qyZDCC = 0.0; return; } - + */ histos.fill(HIST("hEvtSelInfo"), 8.5); histos.fill(HIST("hCentrality"), centrality); histos.fill(HIST("Vz"), vz); histos.fill(HIST("AvgVxy"), 0.5, vx); histos.fill(HIST("AvgVxy"), 1.5, vy); - + /* if (useCallibvertex && (currentRunNumber != lastRunNumber)) { gainprofilevxy = ccdb->getForTimeStamp(confGainPathVxy.value, ts); } @@ -458,7 +456,7 @@ struct zdccalderived { vx = vx - gainprofilevxy->GetBinContent(1); vy = vy - gainprofilevxy->GetBinContent(2); } - + */ bool res = 0; bool resfine = 0; int check = 1; diff --git a/PWGLF/Utils/EventSelectionFlagsMapping.def b/PWGLF/Utils/EventSelectionFlagsMapping.def index 3e23ba89cdd..06b4cb5c03a 100644 --- a/PWGLF/Utils/EventSelectionFlagsMapping.def +++ b/PWGLF/Utils/EventSelectionFlagsMapping.def @@ -49,6 +49,7 @@ EVSEL_FLAG(kNoITSROFrameBorder, applyNoITSROBorderCut, false, kFlagITSROFrameBor // Vertex quality EVSEL_FLAG(kIsVertexITSTPC, applyITSTPCvertex, false, kFlagVertexITSTPC, setApplyITSTPCvertex, ApplyITSTPCvertex, "IsVertexITSTPC", "Apply ITS-TPC vertex") EVSEL_FLAG(kIsGoodZvtxFT0vsPV, applyZvertexTimedifference, false, kFlagZvtxFT0vsPV, setApplyZvertexTimedifference, ApplyZvertexTimedifference, "IsGoodZvtxFT0vsPV", "Apply Z-vertex time difference") +EVSEL_FLAG(kIsVertexTOFmatched, applyVertexTOFmatched, false, kFlagVertexTOFmatched, setApplyVertexTOFmatched, ApplyVertexTOFmatched, "IsVertexTOFmatched", "Vertex has TOF-matched track") EVSEL_FLAG(kIsVertexTRDmatched, applyVertexTRDmatched, false, kFlagVertexTRDmatched, setApplyVertexTRDmatched, ApplyVertexTRDmatched, "IsVertexTRDmatched", "Vertex has TRD-matched track") // Pileup rejection @@ -74,5 +75,4 @@ EVSEL_FLAG(kIsBBT0A, applyBBT0A, false, kFlagBBT0A, setApplyBBT0A, ApplyBBT0A, " EVSEL_FLAG(kIsBBT0C, applyBBT0C, false, kFlagBBT0C, setApplyBBT0C, ApplyBBT0C, "IsBBT0C", "T0C in beam-beam window") // Future flags can be easily added here, for example: -// EVSEL_FLAG(kIsVertexTOFmatched, applyVertexTOFmatched, false, kFlagVertexTOFmatched, setApplyVertexTOFmatched, ApplyVertexTOFmatched, "IsVertexTOFmatched", "Apply vertex TOF matched") // EVSEL_FLAG(kNoCollInTimeRangeStrict, applyCollInTimeRangeStrict, false, kNoCollInTimeRangeStrict, setApplyCollInTimeRangeStrict, ApplyCollInTimeRangeStrict, "NoCollInTimeRangeStrict", "Apply NoCollInTimeRangeStrict") diff --git a/PWGLF/Utils/collisionCuts.h b/PWGLF/Utils/collisionCuts.h index 7b23620ee64..ebb6fd34436 100644 --- a/PWGLF/Utils/collisionCuts.h +++ b/PWGLF/Utils/collisionCuts.h @@ -46,11 +46,11 @@ class CollisonCuts kFlagTrigerTVX, kFlagTimeFrameBorder, kFlagITSROFrameBorder, - kFlagSel8, kFlagVertexITSTPC, - kFlagBunchPileup, kFlagZvtxFT0vsPV, - kFlagOccupancy, + kFlagVertexTOFmatched, + kFlagVertexTRDmatched, + kFlagBunchPileup, kNoCollInTimeRangeStandard, kNoCollInTimeRangeNarrow, kNoCollInTimeRangeStrict, @@ -60,9 +60,10 @@ class CollisonCuts kIsGoodITSLayersAll, kIsGoodITSLayer3, kIsGoodITSLayer0123, - kFlagVertexTRDmatched, kFlagBBT0A, kFlagBBT0C, + kFlagSel8, + kFlagOccupancy, kAllpassed }; @@ -111,9 +112,9 @@ class CollisonCuts mHistogramRegistry->add("Event/posZ", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); // z-vertex histogram after event selections mHistogramRegistry->add("Event/posZ_noCut", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); // z-vertex histogram before all selections if (mCheckIsRun3) { - mHistogramRegistry->add("Event/CentFT0M", "; vCentT0M; Entries", o2::framework::kTH1F, {{110, 0, 110}}); - mHistogramRegistry->add("Event/CentFT0C", "; vCentT0C; Entries", o2::framework::kTH1F, {{110, 0, 110}}); - mHistogramRegistry->add("Event/CentFT0A", "; vCentT0A; Entries", o2::framework::kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/CentFT0M", "; FT0M Percentile; Entries", o2::framework::kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/CentFT0C", "; FT0C Percentile; Entries", o2::framework::kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/CentFT0A", "; FT0A Percentile; Entries", o2::framework::kTH1F, {{110, 0, 110}}); mHistogramRegistry->add("Event/posZ_ITSOnly", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); mHistogramRegistry->add("Event/posZ_ITSTPC", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); mHistogramRegistry->add("Event/trackOccupancyInTimeRange_noCut", "; Occupancy; Entries", o2::framework::kTH1F, {{500, 0., 20000.}}); @@ -131,6 +132,7 @@ class CollisonCuts mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagSel8), "sel8"); mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagOccupancy), "LowOccupancy"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagVertexTOFmatched), "VertexTOFmatched"); mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kAllpassed), "Allpassed"); } @@ -268,6 +270,13 @@ class CollisonCuts setSelection(EvtSel::kNoHighMultCollInPrevRof, apply); } + /// Set the VertexTOFmatched cut + void setApplyVertexTOFmatched(bool apply) + { + mApplyVertexTOFmatched = apply; + setSelection(EvtSel::kFlagVertexTOFmatched, apply); + } + /// Set the VertexTRDmatched cut void setApplyVertexTRDmatched(bool apply) { @@ -531,6 +540,7 @@ class CollisonCuts bool mApplyCollInRofStandard = false; ///< Apply NoCollInRofStandard selection bool mApplyCollInRofStrict = false; ///< Apply NoCollInRofStrict selection bool mApplyHighMultCollInPrevRof = false; ///< Apply NoHighMultCollInPrevRof selection + bool mApplyVertexTOFmatched = false; ///< Apply vertex TOF matched selection bool mApplyVertexTRDmatched = false; ///< Apply vertex TRD matched selection bool mApplyBBT0A = false; ///< Apply T0A beam-beam timing selection bool mApplyBBT0C = false; ///< Apply T0C beam-beam timing selection diff --git a/PWGLF/Utils/strangenessBuilderModule.h b/PWGLF/Utils/strangenessBuilderModule.h index 136f93be492..06c2f969817 100644 --- a/PWGLF/Utils/strangenessBuilderModule.h +++ b/PWGLF/Utils/strangenessBuilderModule.h @@ -897,6 +897,9 @@ class BuilderModule // handle TPC-only tracks properly (photon conversions) if (v0BuilderOpts.moveTPCOnlyTracks) { + if (collision.has_bc()) { + mVDriftMgr.update(collision.template bc_as().timestamp()); + } if (isPosTPCOnly) { // Nota bene: positive is TPC-only -> this entire V0 merits treatment as photon candidate posTrackPar.setPID(o2::track::PID::Electron); @@ -1368,6 +1371,9 @@ class BuilderModule pvX = collision.posX(); pvY = collision.posY(); pvZ = collision.posZ(); + if (v0BuilderOpts.generatePhotonCandidates && v0BuilderOpts.moveTPCOnlyTracks && collision.has_bc()) { + mVDriftMgr.update(collision.template bc_as().timestamp()); + } } auto const& posTrack = tracks.rawIteratorAt(v0.posTrackId); auto const& negTrack = tracks.rawIteratorAt(v0.negTrackId); diff --git a/PWGMM/Lumi/Tasks/lumiStabilityLightIons.cxx b/PWGMM/Lumi/Tasks/lumiStabilityLightIons.cxx index a43b13b530a..8ad19ef30a6 100644 --- a/PWGMM/Lumi/Tasks/lumiStabilityLightIons.cxx +++ b/PWGMM/Lumi/Tasks/lumiStabilityLightIons.cxx @@ -12,7 +12,8 @@ /// \file lumiStabilityLightIons.cxx /// \brief Analysis over BCs to study the luminosity stability along time /// -/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt, Stefanie Mrozinski (stefanie.mrozinski@cern.ch) - Goethe University Frankfurt +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// \author Stefanie Mrozinski (stefanie.mrozinski@cern.ch) - Goethe University Frankfurt #include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/MetadataHelper.h" @@ -27,8 +28,11 @@ #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" +#include +#include #include #include +#include #include #include @@ -36,7 +40,7 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -o2::common::core::MetadataHelper metadataInfo; // Metadata helper +o2::common::core::MetadataHelper metadataInfo; namespace o2::aod { @@ -49,7 +53,13 @@ DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); DECLARE_SOA_COLUMN(AmplitudeZNA, amplitudeZNA, float); DECLARE_SOA_COLUMN(AmplitudeZNC, amplitudeZNC, float); } // namespace myBc_aod -DECLARE_SOA_TABLE(MyBCaod, "AOD", "MYBCAOD", myBc_aod::Timestamp, myBc_aod::BCid, myBc_aod::TimeZNA, myBc_aod::TimeZNC, myBc_aod::AmplitudeZNA, myBc_aod::AmplitudeZNC); +DECLARE_SOA_TABLE(MyBCaod, "AOD", "MYBCAOD", + myBc_aod::Timestamp, + myBc_aod::BCid, + myBc_aod::TimeZNA, + myBc_aod::TimeZNC, + myBc_aod::AmplitudeZNA, + myBc_aod::AmplitudeZNC); } // namespace o2::aod using MyBCs = soa::Join; @@ -62,102 +72,156 @@ struct LumiStabilityLightIons { Configurable cfgDoFDD{"cfgDoFDD", true, "Create and fill histograms for the FDD trigger"}; Configurable cfgDo1ZNC{"cfgDo1ZNC", true, "Create and fill histograms for the 1ZNC trigger"}; - Configurable cfgDoBCA{"cfgDoBCA", false, "Create and fill histograms for the BCs of type A"}; + Configurable cfgDoBCA{"cfgDoBCA", true, "Create and fill histograms for the BCs of type A"}; Configurable cfgDoBCB{"cfgDoBCB", true, "Create and fill histograms for the BCs of type B"}; - Configurable cfgDoBCC{"cfgDoBCC", false, "Create and fill histograms for the BCs of type C"}; - Configurable cfgDoBCE{"cfgDoBCE", false, "Create and fill histograms for the BCs of type E"}; - Configurable cfgDoBCL{"cfgDoBCL", false, "Create and fill histograms for leading BCs of type B"}; - Configurable cfgDoBCSL{"cfgDoBCSL", false, "Create and fill histograms for super-leading BCs (no preceding FT0/FDD activity) of type B"}; - - Configurable cfgRequireZDCTriggerForZDCQA{"cfgRequireZDCTriggerForZDCQA", false, "Require ZDC trigger (1ZNC) for filling QA histograms"}; - Configurable cfgRequireTVXTriggerForZDCQA{"cfgRequireTVXTriggerForZDCQA", false, "Require FT0 vertex trigger (MTVX) for filling ZDC QA histograms"}; - Configurable cfgRequireZEDTriggerForZDCQA{"cfgRequireZEDTriggerForZDCQA", false, "Require ZED trigger (1ZNC||1ZNA) for filling QA histograms"}; + Configurable cfgDoBCC{"cfgDoBCC", true, "Create and fill histograms for the BCs of type C"}; + Configurable cfgDoBCE{"cfgDoBCE", true, "Create and fill histograms for the BCs of type E"}; + Configurable cfgDoBCL{"cfgDoBCL", true, "Create and fill histograms for leading BCs of type B (non-B BCs before)"}; + Configurable cfgDoBCLE{"cfgDoBCLE", true, "Create and fill histograms for leading BCs of type B (strictly empty BCs before)"}; + Configurable cfgDoBCNL{"cfgDoBCNL", true, "Create and fill histograms for non-leading BCs of type B (complement of BCL)"}; + Configurable cfgDoBCNLE{"cfgDoBCNLE", true, "Create and fill histograms for non-leading BCs of type B (complement of BCLE)"}; + Configurable cfgDoBCSLFDD{"cfgDoBCSLFDD", true, "Create and fill histograms for super-leading BCs w.r.t. FDD activity"}; + Configurable cfgDoBCSLFT0{"cfgDoBCSLFT0", true, "Create and fill histograms for super-leading BCs w.r.t. FT0 activity"}; + Configurable cfgDoBCNSLFDD{"cfgDoBCNSLFDD", true, "Create and fill histograms for non-super-leading BCs w.r.t. FDD activity"}; + Configurable cfgDoBCNSLFT0{"cfgDoBCNSLFT0", true, "Create and fill histograms for non-super-leading BCs w.r.t. FT0 activity"}; + + Configurable cfgRequireZDCTriggerForZDCQA{"cfgRequireZDCTriggerForZDCQA", true, "Require ZDC trigger (1ZNC) for filling QA histograms"}; + Configurable cfgRequireTVXTriggerForZDCQA{"cfgRequireTVXTriggerForZDCQA", true, "Require FT0 vertex trigger (MTVX) for filling ZDC QA histograms"}; + Configurable cfgRequireZEDTriggerForZDCQA{"cfgRequireZEDTriggerForZDCQA", true, "Require ZED trigger (1ZNC||1ZNA) for filling QA histograms"}; Configurable cfgRequireNoT0ForSLBC{"cfgRequireNoT0ForSLBC", false, "Require no T0 signal for definition of super leading BC (otherwise only no FDD)"}; - Configurable cfgEmptyBCsBeforeLeadingBC{"cfgEmptyBCsBeforeLeadingBC", 5, "Minimum number of empty BCs before a leading BC to identify it as such"}; + Configurable cfgEmptyBCsBeforeLeadingBC{"cfgEmptyBCsBeforeLeadingBC", 5, "Minimum number of non-B BCs before a BCL leading BC"}; + Configurable cfgEmptyBCsBeforeLeadingBCLE{"cfgEmptyBCsBeforeLeadingBCLE", 5, "Minimum number of strictly empty (E-type) BCs before a BCLE leading BC"}; + Configurable cfgBCsBeforeSuperLeading{"cfgBCsBeforeSuperLeading", 5, "Minimum number of BCs without FDD/FT0 activity before a super-leading BC"}; - // Configurables specific to VdM analysis: output ao2d with timestamps and ZDC times Configurable cfgFillBCao2d{"cfgFillBCao2d", false, "Fill BC ao2d with timestamps and ZDC times"}; Configurable cfgTstampStartFillingBCao2d{"cfgTstampStartFillingBCao2d", 0, "Minimum value of timestamp for output bc ao2d to be filled"}; Configurable cfgTstampEndFillingBCao2d{"cfgTstampEndFillingBCao2d", 0, "Maximum value of timestamp for output bc ao2d to be filled"}; - std::bitset beamPatternA, beamPatternC; - std::bitset bcPatternA, bcPatternC, bcPatternB, bcPatternE, bcPatternL; + Configurable cfgBcShiftFDDForData2023{"cfgBcShiftFDDForData2023", 7, "Number of BCs to shift FDD, applied for 2023 data only"}; - std::string strLPMProductionTag = ""; // MC production tag to be retrieved from AO2D metadata + std::bitset beamPatternA, beamPatternC; + std::bitset bcPatternA, bcPatternC, bcPatternB, bcPatternE; + std::bitset bcPatternL; + std::bitset bcPatternLE; + std::string strLPMProductionTag = ""; const int nBCsPerOrbit = 3564; parameters::GRPLHCIFData* mLHCIFdata = nullptr; int mRunNumber = -1; + bool isData23 = false; + int mBcShiftFDD = 0; ctpRateFetcher mRateFetcher; - bool isLeadingBC = false; HistogramRegistry mHistManager{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - const int nTriggers = 5; - enum TriggerAliases { kAllBCs = 0, - kFT0Vtx = 1, - kFT0CE = 2, - kFDD = 3, - k1ZNC = 4 }; - - const int nBCCategories = 6; - enum BCCategories { kBCA = 0, // A side BCs (bunch-crossings that had beam only from A side) - kBCB = 1, // B type BCs (bunch-crossings that had beam from both sides) - kBCC = 2, // C side BCs (bunch-crossings that had beam only from C side) - kBCE = 3, // empty BCs (bunch-crossings that did not have beam from either side) - kBCL = 4, // leading BCs (bunch-crossings that did not have interacting bunches for a configurable number of preceding BCs) - kBCSL = 5 }; // super-leading BCs (bunch-crossings that did not have FDD/FT0 activity for a configurable number of preceding BCs) - - static constexpr std::string_view NBCsVsTimeHistNames[5][6] = - {{"AllBCs/BC_A/nBCsVsTime", "AllBCs/BC_B/nBCsVsTime", "AllBCs/BC_C/nBCsVsTime", "AllBCs/BC_E/nBCsVsTime", "AllBCs/BC_L/nBCsVsTime", "AllBCs/BC_SL/nBCsVsTime"}, - {"FT0VTx/BC_A/nBCsVsTime", "FT0VTx/BC_B/nBCsVsTime", "FT0VTx/BC_C/nBCsVsTime", "FT0VTx/BC_E/nBCsVsTime", "FT0VTx/BC_L/nBCsVsTime", "FT0VTx/BC_SL/nBCsVsTime"}, - {"FT0CE/BC_A/nBCsVsTime", "FT0CE/BC_B/nBCsVsTime", "FT0CE/BC_C/nBCsVsTime", "FT0CE/BC_E/nBCsVsTime", "FT0CE/BC_L/nBCsVsTime", "FT0CE/BC_SL/nBCsVsTime"}, - {"FDD/BC_A/nBCsVsTime", "FDD/BC_B/nBCsVsTime", "FDD/BC_C/nBCsVsTime", "FDD/BC_E/nBCsVsTime", "FDD/BC_L/nBCsVsTime", "FDD/BC_SL/nBCsVsTime"}, - {"1ZNC/BC_A/nBCsVsTime", "1ZNC/BC_B/nBCsVsTime", "1ZNC/BC_C/nBCsVsTime", "1ZNC/BC_E/nBCsVsTime", "1ZNC/BC_L/nBCsVsTime", "1ZNC/BC_SL/nBCsVsTime"}}; - - static constexpr std::string_view NBCsVsBCIDHistNames[5][6] = - {{"AllBCs/BC_A/nBCsVsBCID", "AllBCs/BC_B/nBCsVsBCID", "AllBCs/BC_C/nBCsVsBCID", "AllBCs/BC_E/nBCsVsBCID", "AllBCs/BC_L/nBCsVsBCID", "AllBCs/BC_SL/nBCsVsBCID"}, - {"FT0VTx/BC_A/nBCsVsBCID", "FT0VTx/BC_B/nBCsVsBCID", "FT0VTx/BC_C/nBCsVsBCID", "FT0VTx/BC_E/nBCsVsBCID", "FT0VTx/BC_L/nBCsVsBCID", "FT0VTx/BC_SL/nBCsVsBCID"}, - {"FT0CE/BC_A/nBCsVsBCID", "FT0CE/BC_B/nBCsVsBCID", "FT0CE/BC_C/nBCsVsBCID", "FT0CE/BC_E/nBCsVsBCID", "FT0CE/BC_L/nBCsVsBCID", "FT0CE/BC_SL/nBCsVsBCID"}, - {"FDD/BC_A/nBCsVsBCID", "FDD/BC_B/nBCsVsBCID", "FDD/BC_C/nBCsVsBCID", "FDD/BC_E/nBCsVsBCID", "FDD/BC_L/nBCsVsBCID", "FDD/BC_SL/nBCsVsBCID"}, - {"1ZNC/BC_A/nBCsVsBCID", "1ZNC/BC_B/nBCsVsBCID", "1ZNC/BC_C/nBCsVsBCID", "1ZNC/BC_E/nBCsVsBCID", "1ZNC/BC_L/nBCsVsBCID", "1ZNC/BC_SL/nBCsVsBCID"}}; - - int64_t bcSOR; - int nBCsPerTF; + static constexpr int nTriggers = 5; + enum TriggerAliases { + kAllBCs = 0, + kFT0Vtx = 1, + kFT0CE = 2, + kFDD = 3, + k1ZNC = 4 + }; + + static constexpr int nBCCategories = 12; + enum BCCategories { + kBCA = 0, + kBCB = 1, + kBCC = 2, + kBCE = 3, + kBCL = 4, + kBCLE = 5, + kBCNL = 6, + kBCNLE = 7, + kBCSLFDD = 8, + kBCSLFT0 = 9, + kBCNSLFDD = 10, + kBCNSLFT0 = 11 + }; + + static constexpr std::string_view NBCsVsTimeHistNames[6][12] = { + {"AllBCs/BC_A/nBCsVsTime", "AllBCs/BC_B/nBCsVsTime", "AllBCs/BC_C/nBCsVsTime", "AllBCs/BC_E/nBCsVsTime", "AllBCs/BC_L/nBCsVsTime", "AllBCs/BC_LE/nBCsVsTime", "AllBCs/BC_NL/nBCsVsTime", "AllBCs/BC_NLE/nBCsVsTime", "AllBCs/BC_SL_FDD/nBCsVsTime", "AllBCs/BC_SL_FT0/nBCsVsTime", "AllBCs/BC_NSL_FDD/nBCsVsTime", "AllBCs/BC_NSL_FT0/nBCsVsTime"}, + {"FT0VTx/BC_A/nBCsVsTime", "FT0VTx/BC_B/nBCsVsTime", "FT0VTx/BC_C/nBCsVsTime", "FT0VTx/BC_E/nBCsVsTime", "FT0VTx/BC_L/nBCsVsTime", "FT0VTx/BC_LE/nBCsVsTime", "FT0VTx/BC_NL/nBCsVsTime", "FT0VTx/BC_NLE/nBCsVsTime", "FT0VTx/BC_SL_FDD/nBCsVsTime", "FT0VTx/BC_SL_FT0/nBCsVsTime", "FT0VTx/BC_NSL_FDD/nBCsVsTime", "FT0VTx/BC_NSL_FT0/nBCsVsTime"}, + {"FT0CE/BC_A/nBCsVsTime", "FT0CE/BC_B/nBCsVsTime", "FT0CE/BC_C/nBCsVsTime", "FT0CE/BC_E/nBCsVsTime", "FT0CE/BC_L/nBCsVsTime", "FT0CE/BC_LE/nBCsVsTime", "FT0CE/BC_NL/nBCsVsTime", "FT0CE/BC_NLE/nBCsVsTime", "FT0CE/BC_SL_FDD/nBCsVsTime", "FT0CE/BC_SL_FT0/nBCsVsTime", "FT0CE/BC_NSL_FDD/nBCsVsTime", "FT0CE/BC_NSL_FT0/nBCsVsTime"}, + {"FDD/BC_A/nBCsVsTime", "FDD/BC_B/nBCsVsTime", "FDD/BC_C/nBCsVsTime", "FDD/BC_E/nBCsVsTime", "FDD/BC_L/nBCsVsTime", "FDD/BC_LE/nBCsVsTime", "FDD/BC_NL/nBCsVsTime", "FDD/BC_NLE/nBCsVsTime", "FDD/BC_SL_FDD/nBCsVsTime", "FDD/BC_SL_FT0/nBCsVsTime", "FDD/BC_NSL_FDD/nBCsVsTime", "FDD/BC_NSL_FT0/nBCsVsTime"}, + {"1ZNC/BC_A/nBCsVsTime", "1ZNC/BC_B/nBCsVsTime", "1ZNC/BC_C/nBCsVsTime", "1ZNC/BC_E/nBCsVsTime", "1ZNC/BC_L/nBCsVsTime", "1ZNC/BC_LE/nBCsVsTime", "1ZNC/BC_NL/nBCsVsTime", "1ZNC/BC_NLE/nBCsVsTime", "1ZNC/BC_SL_FDD/nBCsVsTime", "1ZNC/BC_SL_FT0/nBCsVsTime", "1ZNC/BC_NSL_FDD/nBCsVsTime", "1ZNC/BC_NSL_FT0/nBCsVsTime"}}; + + static constexpr std::string_view NBCsVsBCIDHistNames[5][12] = { + {"AllBCs/BC_A/nBCsVsBCID", "AllBCs/BC_B/nBCsVsBCID", "AllBCs/BC_C/nBCsVsBCID", "AllBCs/BC_E/nBCsVsBCID", "AllBCs/BC_L/nBCsVsBCID", "AllBCs/BC_LE/nBCsVsBCID", "AllBCs/BC_NL/nBCsVsBCID", "AllBCs/BC_NLE/nBCsVsBCID", "AllBCs/BC_SL_FDD/nBCsVsBCID", "AllBCs/BC_SL_FT0/nBCsVsBCID", "AllBCs/BC_NSL_FDD/nBCsVsBCID", "AllBCs/BC_NSL_FT0/nBCsVsBCID"}, + {"FT0VTx/BC_A/nBCsVsBCID", "FT0VTx/BC_B/nBCsVsBCID", "FT0VTx/BC_C/nBCsVsBCID", "FT0VTx/BC_E/nBCsVsBCID", "FT0VTx/BC_L/nBCsVsBCID", "FT0VTx/BC_LE/nBCsVsBCID", "FT0VTx/BC_NL/nBCsVsBCID", "FT0VTx/BC_NLE/nBCsVsBCID", "FT0VTx/BC_SL_FDD/nBCsVsBCID", "FT0VTx/BC_SL_FT0/nBCsVsBCID", "FT0VTx/BC_NSL_FDD/nBCsVsBCID", "FT0VTx/BC_NSL_FT0/nBCsVsBCID"}, + {"FT0CE/BC_A/nBCsVsBCID", "FT0CE/BC_B/nBCsVsBCID", "FT0CE/BC_C/nBCsVsBCID", "FT0CE/BC_E/nBCsVsBCID", "FT0CE/BC_L/nBCsVsBCID", "FT0CE/BC_LE/nBCsVsBCID", "FT0CE/BC_NL/nBCsVsBCID", "FT0CE/BC_NLE/nBCsVsBCID", "FT0CE/BC_SL_FDD/nBCsVsBCID", "FT0CE/BC_SL_FT0/nBCsVsBCID", "FT0CE/BC_NSL_FDD/nBCsVsBCID", "FT0CE/BC_NSL_FT0/nBCsVsBCID"}, + {"FDD/BC_A/nBCsVsBCID", "FDD/BC_B/nBCsVsBCID", "FDD/BC_C/nBCsVsBCID", "FDD/BC_E/nBCsVsBCID", "FDD/BC_L/nBCsVsBCID", "FDD/BC_LE/nBCsVsBCID", "FDD/BC_NL/nBCsVsBCID", "FDD/BC_NLE/nBCsVsBCID", "FDD/BC_SL_FDD/nBCsVsBCID", "FDD/BC_SL_FT0/nBCsVsBCID", "FDD/BC_NSL_FDD/nBCsVsBCID", "FDD/BC_NSL_FT0/nBCsVsBCID"}, + {"1ZNC/BC_A/nBCsVsBCID", "1ZNC/BC_B/nBCsVsBCID", "1ZNC/BC_C/nBCsVsBCID", "1ZNC/BC_E/nBCsVsBCID", "1ZNC/BC_L/nBCsVsBCID", "1ZNC/BC_LE/nBCsVsBCID", "1ZNC/BC_NL/nBCsVsBCID", "1ZNC/BC_NLE/nBCsVsBCID", "1ZNC/BC_SL_FDD/nBCsVsBCID", "1ZNC/BC_SL_FT0/nBCsVsBCID", "1ZNC/BC_NSL_FDD/nBCsVsBCID", "1ZNC/BC_NSL_FT0/nBCsVsBCID"}}; + + static constexpr std::string_view NBCsInspectedVsBCIDHistNames[5][12] = { + {"AllBCs/BC_A/nBCsInspectedVsBCID", "AllBCs/BC_B/nBCsInspectedVsBCID", "AllBCs/BC_C/nBCsInspectedVsBCID", "AllBCs/BC_E/nBCsInspectedVsBCID", "AllBCs/BC_L/nBCsInspectedVsBCID", "AllBCs/BC_LE/nBCsInspectedVsBCID", "AllBCs/BC_NL/nBCsInspectedVsBCID", "AllBCs/BC_NLE/nBCsInspectedVsBCID", "AllBCs/BC_SL_FDD/nBCsInspectedVsBCID", "AllBCs/BC_SL_FT0/nBCsInspectedVsBCID", "AllBCs/BC_NSL_FDD/nBCsInspectedVsBCID", "AllBCs/BC_NSL_FT0/nBCsInspectedVsBCID"}, + {"FT0VTx/BC_A/nBCsInspectedVsBCID", "FT0VTx/BC_B/nBCsInspectedVsBCID", "FT0VTx/BC_C/nBCsInspectedVsBCID", "FT0VTx/BC_E/nBCsInspectedVsBCID", "FT0VTx/BC_L/nBCsInspectedVsBCID", "FT0VTx/BC_LE/nBCsInspectedVsBCID", "FT0VTx/BC_NL/nBCsInspectedVsBCID", "FT0VTx/BC_NLE/nBCsInspectedVsBCID", "FT0VTx/BC_SL_FDD/nBCsInspectedVsBCID", "FT0VTx/BC_SL_FT0/nBCsInspectedVsBCID", "FT0VTx/BC_NSL_FDD/nBCsInspectedVsBCID", "FT0VTx/BC_NSL_FT0/nBCsInspectedVsBCID"}, + {"FT0CE/BC_A/nBCsInspectedVsBCID", "FT0CE/BC_B/nBCsInspectedVsBCID", "FT0CE/BC_C/nBCsInspectedVsBCID", "FT0CE/BC_E/nBCsInspectedVsBCID", "FT0CE/BC_L/nBCsInspectedVsBCID", "FT0CE/BC_LE/nBCsInspectedVsBCID", "FT0CE/BC_NL/nBCsInspectedVsBCID", "FT0CE/BC_NLE/nBCsInspectedVsBCID", "FT0CE/BC_SL_FDD/nBCsInspectedVsBCID", "FT0CE/BC_SL_FT0/nBCsInspectedVsBCID", "FT0CE/BC_NSL_FDD/nBCsInspectedVsBCID", "FT0CE/BC_NSL_FT0/nBCsInspectedVsBCID"}, + {"FDD/BC_A/nBCsInspectedVsBCID", "FDD/BC_B/nBCsInspectedVsBCID", "FDD/BC_C/nBCsInspectedVsBCID", "FDD/BC_E/nBCsInspectedVsBCID", "FDD/BC_L/nBCsInspectedVsBCID", "FDD/BC_LE/nBCsInspectedVsBCID", "FDD/BC_NL/nBCsInspectedVsBCID", "FDD/BC_NLE/nBCsInspectedVsBCID", "FDD/BC_SL_FDD/nBCsInspectedVsBCID", "FDD/BC_SL_FT0/nBCsInspectedVsBCID", "FDD/BC_NSL_FDD/nBCsInspectedVsBCID", "FDD/BC_NSL_FT0/nBCsInspectedVsBCID"}, + {"1ZNC/BC_A/nBCsInspectedVsBCID", "1ZNC/BC_B/nBCsInspectedVsBCID", "1ZNC/BC_C/nBCsInspectedVsBCID", "1ZNC/BC_E/nBCsInspectedVsBCID", "1ZNC/BC_L/nBCsInspectedVsBCID", "1ZNC/BC_LE/nBCsInspectedVsBCID", "1ZNC/BC_NL/nBCsInspectedVsBCID", "1ZNC/BC_NLE/nBCsInspectedVsBCID", "1ZNC/BC_SL_FDD/nBCsInspectedVsBCID", "1ZNC/BC_SL_FT0/nBCsInspectedVsBCID", "1ZNC/BC_NSL_FDD/nBCsInspectedVsBCID", "1ZNC/BC_NSL_FT0/nBCsInspectedVsBCID"}}; + + std::array, nBCCategories>, nTriggers> mInspectedHistos{}; + + int64_t bcSOR = 0; + int nBCsPerTF = 0; int64_t currentTFid = -1; + int64_t globalBCIdOfLastBCWithActivityFDD{std::numeric_limits::min() / 2}; + int64_t globalBCIdOfLastBCWithActivityFT0{std::numeric_limits::min() / 2}; + int64_t globalBCLastInspectedBC{-1}; + + using DenomCounter = std::vector, nTriggers>>; + + bool hasAnyFDDTrigger(const std::bitset<64>& ctpInputMask) const + { + return ctpInputMask.test(12) || ctpInputMask.test(14) || ctpInputMask.test(15) || + ctpInputMask.test(16) || ctpInputMask.test(17); + } + + bool hasAnyFT0Trigger(const std::bitset<64>& ctpInputMask) const + { + return ctpInputMask.test(0) || ctpInputMask.test(1) || ctpInputMask.test(2) || + ctpInputMask.test(3) || ctpInputMask.test(4); + } + void init(InitContext&) { - strLPMProductionTag = metadataInfo.get("LPMProductionTag"); // to extract info from ccdb by the tag + strLPMProductionTag = metadataInfo.get("LPMProductionTag"); LOG(info) << "strLPMProductionTag: " << strLPMProductionTag; - AxisSpec timeAxis{1440, 0., 1440., "#bf{t-t_{SOF} (min)}"}, bcIDAxis{3600, 0., 3600., "#bf{BC ID in orbit}"}; + AxisSpec timeAxis{1440, 0., 1440., "#bf{t-t_{SOF} (min)}"}; + AxisSpec bcIDAxis{3600, 0., 3600., "#bf{BC ID in orbit}"}; for (int iTrigger = 0; iTrigger < nTriggers; iTrigger++) { if ((iTrigger == kAllBCs) || (iTrigger == kFT0Vtx && cfgDoFT0Vtx) || (iTrigger == kFT0CE && cfgDoFT0CE) || (iTrigger == kFDD && cfgDoFDD) || (iTrigger == k1ZNC && cfgDo1ZNC)) { for (int iBCCategory = 0; iBCCategory < nBCCategories; iBCCategory++) { - if ((iBCCategory == kBCA && cfgDoBCA) || (iBCCategory == kBCB && cfgDoBCB) || (iBCCategory == kBCC && cfgDoBCC) || (iBCCategory == kBCE && cfgDoBCE) || (iBCCategory == kBCL && cfgDoBCL)) { + if ((iBCCategory == kBCA && cfgDoBCA) || (iBCCategory == kBCB && cfgDoBCB) || (iBCCategory == kBCC && cfgDoBCC) || (iBCCategory == kBCE && cfgDoBCE) || + (iBCCategory == kBCL && cfgDoBCL) || (iBCCategory == kBCLE && cfgDoBCLE) || + (iBCCategory == kBCNL && cfgDoBCNL) || (iBCCategory == kBCNLE && cfgDoBCNLE) || + (iBCCategory == kBCSLFDD && cfgDoBCSLFDD) || (iBCCategory == kBCSLFT0 && cfgDoBCSLFT0) || + (iBCCategory == kBCNSLFDD && cfgDoBCNSLFDD) || (iBCCategory == kBCNSLFT0 && cfgDoBCNSLFT0)) { mHistManager.add(Form("%s", std::string(NBCsVsTimeHistNames[iTrigger][iBCCategory]).c_str()), "Time of triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis}); mHistManager.add(Form("%s", std::string(NBCsVsBCIDHistNames[iTrigger][iBCCategory]).c_str()), "BC ID of triggered BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis}); + mInspectedHistos[iTrigger][iBCCategory] = mHistManager.add( + Form("%s", std::string(NBCsInspectedVsBCIDHistNames[iTrigger][iBCCategory]).c_str()), + "Inspected BC ID (denominator for mu);#bf{BC ID in orbit};#bf{#it{N}_{BC}}", + HistType::kTH1D, {bcIDAxis}); } } - if (cfgDoBCSL && (iTrigger == kFT0Vtx || iTrigger == kFDD || iTrigger == kAllBCs)) { // only for FT0Vtx and FDD fill super-leading BC histograms - mHistManager.add(Form("%s", std::string(NBCsVsTimeHistNames[iTrigger][5]).c_str()), "Time of triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis}); - mHistManager.add(Form("%s", std::string(NBCsVsBCIDHistNames[iTrigger][5]).c_str()), "BC ID of triggered BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis}); - } } } - if (cfgDoBCSL) { + if (cfgDoBCSLFDD || cfgDoBCSLFT0 || cfgDoBCNSLFDD || cfgDoBCNSLFT0) { mHistManager.add("FITQA/BCHasFT0", "Does the BC have FT0?;BC has FT0;TVX triggered according to CTP;#bf{#it{N}_{BC}}", HistType::kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}}); mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetYaxis()->SetBinLabel(1, "No CTP trigger"); mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetYaxis()->SetBinLabel(2, "CTP triggered"); mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetXaxis()->SetBinLabel(1, "No found FT0"); mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetXaxis()->SetBinLabel(2, "Found FT0"); + mHistManager.add("FITQA/BCHasFDD", "Does the BC have FDD?;BC has FDD;FDD triggered according to CTP;#bf{#it{N}_{BC}}", HistType::kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}}); mHistManager.get(HIST("FITQA/BCHasFDD")).get()->GetYaxis()->SetBinLabel(1, "No CTP trigger"); mHistManager.get(HIST("FITQA/BCHasFDD")).get()->GetYaxis()->SetBinLabel(2, "CTP triggered"); @@ -185,18 +249,27 @@ struct LumiStabilityLightIons { void setLHCIFData(const auto& bc) { - if (mRunNumber == bc.runNumber()) + if (mRunNumber == bc.runNumber()) { return; + } auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); uint64_t timeStamp = bc.timestamp(); + const int runStart2023{535069}; + const int runStop2023{543113}; + isData23 = (bc.runNumber() >= runStart2023 && bc.runNumber() <= runStop2023); + mBcShiftFDD = isData23 ? static_cast(cfgBcShiftFDDForData2023) : 0; + std::map metadata; mLHCIFdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); - if (mLHCIFdata == nullptr) + if (mLHCIFdata == nullptr) { LOG(fatal) << "GRPLHCIFData not in database, timestamp:" << timeStamp; + } + mRunNumber = bc.runNumber(); - LOG(info) << "LHCIF data fetched for run " << mRunNumber << " and timestamp " << timeStamp; + LOG(info) << "LHCIF data fetched for run " << mRunNumber << " and timestamp " << timeStamp + << " (isData23=" << isData23 << ", bcShiftFDD=" << mBcShiftFDD << ")"; beamPatternA = mLHCIFdata->getBunchFilling().getBeamPattern(0); beamPatternC = mLHCIFdata->getBunchFilling().getBeamPattern(1); @@ -205,42 +278,60 @@ struct LumiStabilityLightIons { bcPatternB = beamPatternA & beamPatternC; bcPatternE = ~beamPatternA & ~beamPatternC; - // Create bcPatternL: leading BCs of type B that follow at least "cfgEmptyBCsBeforeLeadingBC" empty BCs - bcPatternL.reset(); // Initialize all bits to false - LOG(info) << "Starting to create bcPatternL from bcPatternB"; - LOG(info) << "Total number of BCs to check: " << o2::constants::lhc::LHCMaxBunches; + bcPatternL.reset(); + bcPatternLE.reset(); + + int totalLeadingBCsL = 0; + int totalLeadingBCsLE = 0; - int totalLeadingBCs = 0; for (int iBC = 0; iBC < o2::constants::lhc::LHCMaxBunches; iBC++) { - if (bcPatternB[iBC]) { // Check if current BC is of type B - int emptyBCsBefore = 0; // Count how many consecutive BCs before this one are NOT type B - for (int j = 1; j <= cfgEmptyBCsBeforeLeadingBC; j++) { - int prevBC = (iBC - j + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // Protection for BCs at small indices to check the end of the orbit - if (!bcPatternB[prevBC]) { - emptyBCsBefore++; - } else { - break; // Stop counting if we hit a type B BC - } + if (!bcPatternB[iBC]) { + continue; + } + + int nonBBefore = 0; + int emptyBefore = 0; + + for (int j = 1; j <= cfgEmptyBCsBeforeLeadingBC; j++) { + int prevBC = (iBC - j + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; + if (!bcPatternB[prevBC]) { + nonBBefore++; + } else { + break; } - if (emptyBCsBefore >= cfgEmptyBCsBeforeLeadingBC) { // If we found at least cfgEmptyBCsBeforeLeadingBC empty BCs before this one, mark it as leading - bcPatternL[iBC] = true; - totalLeadingBCs++; + } + + for (int j = 1; j <= cfgEmptyBCsBeforeLeadingBCLE; j++) { + int prevBC = (iBC - j + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; + if (bcPatternE[prevBC]) { + emptyBefore++; + } else { + break; } } + + if (nonBBefore >= cfgEmptyBCsBeforeLeadingBC) { + bcPatternL[iBC] = true; + totalLeadingBCsL++; + } + if (emptyBefore >= cfgEmptyBCsBeforeLeadingBCLE) { + bcPatternLE[iBC] = true; + totalLeadingBCsLE++; + } } - LOG(info) << "bcPatternL creation complete. Total leading BCs found: " << totalLeadingBCs; + + LOG(info) << "bcPatternL (non-B before) complete. Leading BCs found: " << totalLeadingBCsL; + LOG(info) << "bcPatternLE (empty before) complete. Leading BCs found: " << totalLeadingBCsLE; auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), mRunNumber, strLPMProductionTag); - bcSOR = runInfo.orbitSOR * nBCsPerOrbit; // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; LOG(info) << "BC SOR: " << bcSOR << " (orbit SOR: " << runInfo.orbitSOR << ") NBCs per orbit: " << nBCsPerOrbit; - nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; // duration of TF in bcs - - return; + nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; } float getTimeSinceSOF(const auto& bc) { - return (bc.timestamp() - mLHCIFdata->getFillNumberTime()) / 1e3 / 60; // Convert to minutes + return (bc.timestamp() - mLHCIFdata->getFillNumberTime()) / 1e3 / 60.f; } template @@ -250,49 +341,133 @@ struct LumiStabilityLightIons { mHistManager.fill(HIST(NBCsVsBCIDHistNames[iTrigger][iBCCategory]), localBC); } + template + void countInspectedBC(DenomCounter& nBCsPerBcId, + int iLBC, + int iLBCFDD, + int64_t iGBC, + int64_t lastFT0ActivityBC, + int64_t lastFDDActivityBC) + { + if constexpr (iTrigger == kFDD) { + if (bcPatternA[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCA]++; + } + if (bcPatternB[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCB]++; + } + if (bcPatternC[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCC]++; + } + if (bcPatternE[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCE]++; + } + if (bcPatternL[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCL]++; + } + if (bcPatternLE[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCLE]++; + } + if (bcPatternB[iLBCFDD] && !bcPatternL[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCNL]++; + } + if (bcPatternB[iLBCFDD] && !bcPatternLE[iLBCFDD]) { + nBCsPerBcId[iLBCFDD][iTrigger][kBCNLE]++; + } + if (bcPatternB[iLBCFDD]) { + const bool slFDD = ((iGBC + mBcShiftFDD) - lastFDDActivityBC >= cfgBCsBeforeSuperLeading); + nBCsPerBcId[iLBCFDD][iTrigger][slFDD ? kBCSLFDD : kBCNSLFDD]++; + + const bool slFT0 = (iGBC - lastFT0ActivityBC >= cfgBCsBeforeSuperLeading); + nBCsPerBcId[iLBCFDD][iTrigger][slFT0 ? kBCSLFT0 : kBCNSLFT0]++; + } + } else { + if (bcPatternA[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCA]++; + } + if (bcPatternB[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCB]++; + } + if (bcPatternC[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCC]++; + } + if (bcPatternE[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCE]++; + } + if (bcPatternL[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCL]++; + } + if (bcPatternLE[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCLE]++; + } + if (bcPatternB[iLBC] && !bcPatternL[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCNL]++; + } + if (bcPatternB[iLBC] && !bcPatternLE[iLBC]) { + nBCsPerBcId[iLBC][iTrigger][kBCNLE]++; + } + if (bcPatternB[iLBC]) { + const bool slFT0 = (iGBC - lastFT0ActivityBC >= cfgBCsBeforeSuperLeading); + nBCsPerBcId[iLBC][iTrigger][slFT0 ? kBCSLFT0 : kBCNSLFT0]++; + } + if (bcPatternB[iLBCFDD]) { + const bool slFDD = ((iGBC + mBcShiftFDD) - lastFDDActivityBC >= cfgBCsBeforeSuperLeading); + nBCsPerBcId[iLBCFDD][iTrigger][slFDD ? kBCSLFDD : kBCNSLFDD]++; + } + } + } + void processZDCQA(MyBCs const& bcs, aod::Zdcs const&) { - const int maxTimeZDC = 50; // Maximum time the histogram allows before setting a dummy value - const int dummyZDCTime = 42.f; // Time value to indicate missing ZDC time - for (const auto& bc : bcs) { + const int maxTimeZDC = 50; + const float dummyZDCTime = 42.f; + for (const auto& bc : bcs) { std::bitset<64> ctpInputMask(bc.inputMask()); - if (cfgRequireTVXTriggerForZDCQA && !(ctpInputMask.test(2))) // 2 = 3 - 1 -> MTVX + + if (cfgRequireTVXTriggerForZDCQA && !(ctpInputMask.test(2))) { continue; - if (cfgRequireZDCTriggerForZDCQA && !(ctpInputMask.test(25))) // 25 = 26 - 1 -> 1ZNC + } + if (cfgRequireZDCTriggerForZDCQA && !(ctpInputMask.test(25))) { continue; - if (cfgRequireZEDTriggerForZDCQA && !(ctpInputMask.test(24))) // 24 = 25 - 1 -> 1ZED + } + if (cfgRequireZEDTriggerForZDCQA && !(ctpInputMask.test(24))) { continue; + } bool zdcHit = !bc.has_zdc() ? 0 : ((bc.zdc().energyCommonZNC() > -1 && std::abs(bc.zdc().timeZNC()) < 1E5) ? 1 : 0); mHistManager.fill(HIST("ZDCQA/BCHasZDC"), zdcHit, ctpInputMask.test(25) ? 1 : 0); - if (!bc.has_zdc()) + + if (!bc.has_zdc()) { continue; + } - mHistManager.fill(HIST("ZDCQA/ZNCTimeVsEnergy"), bc.zdc().energyCommonZNC() > -1 ? bc.zdc().energyCommonZNC() : -1, std::abs(bc.zdc().timeZNC()) < maxTimeZDC ? bc.zdc().timeZNC() : dummyZDCTime); + mHistManager.fill(HIST("ZDCQA/ZNCTimeVsEnergy"), + bc.zdc().energyCommonZNC() > -1 ? bc.zdc().energyCommonZNC() : -1, + std::abs(bc.zdc().timeZNC()) < maxTimeZDC ? bc.zdc().timeZNC() : dummyZDCTime); float timeZNA = bc.zdc().timeZNA(); float timeZNC = bc.zdc().timeZNC(); if (std::abs(timeZNA) > maxTimeZDC) { - timeZNA = dummyZDCTime; // set dummy value for missing ZDC times to be able to plot them + timeZNA = dummyZDCTime; mHistManager.fill(HIST("ZDCQA/ZNCTime"), timeZNC); } if (std::abs(timeZNC) > maxTimeZDC) { - timeZNC = dummyZDCTime; // set dummy value for missing ZDC times to be able to plot them - if (timeZNA != dummyZDCTime) // If ZNA and ZNC are both missing, do not fill the ZNA histogram with the dummy value + timeZNC = dummyZDCTime; + if (timeZNA != dummyZDCTime) { mHistManager.fill(HIST("ZDCQA/ZNATime"), timeZNA); + } } mHistManager.fill(HIST("ZDCQA/ZDCTimes"), timeZNA, timeZNC); - // For VdM analysis: fill timestamps and ZDC times in output tree, if enabled - // Fill BC idx and ZNA and ZNC amplitudes as well uint64_t timestamp = bc.timestamp(); int64_t globalBC = bc.globalBC(); int localBC = globalBC % nBCsPerOrbit; float amplitudeZNA = bc.zdc().amplitudeZNA(); float amplitudeZNC = bc.zdc().amplitudeZNC(); + if (cfgFillBCao2d && timestamp >= cfgTstampStartFillingBCao2d && timestamp <= cfgTstampEndFillingBCao2d) { BCaod(timestamp, localBC, timeZNA, timeZNC, amplitudeZNA, amplitudeZNC); } @@ -300,140 +475,264 @@ struct LumiStabilityLightIons { } PROCESS_SWITCH(LumiStabilityLightIons, processZDCQA, "process QA for the ZDC triggers (light ions and PbPb)", false); - void processSLBunches(MyBCs const& bcs, aod::FT0s const&, aod::FDDs const&) + void process(MyBCs const& bcs, aod::FT0s const&, aod::FDDs const&) { - int64_t globalBCIdOfLastBCWithActivity = 0; + DenomCounter nBCsPerBcId(nBCsPerOrbit); + for (auto& triggerArr : nBCsPerBcId) { + for (auto& catArr : triggerArr) { + catArr.fill(0); + } + } + for (const auto& bc : bcs) { - if (bc.timestamp() == 0) + if (bc.timestamp() == 0) { continue; + } setLHCIFData(bc); - std::bitset<64> ctpInputMask(bc.inputMask()); + float timeSinceSOF = getTimeSinceSOF(bc); - mHistManager.fill(HIST("FITQA/BCHasFT0"), bc.has_ft0(), ctpInputMask.test(2)); - mHistManager.fill(HIST("FITQA/BCHasFDD"), bc.has_fdd(), ctpInputMask.test(15)); + if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) { + mHistManager.fill(HIST("FT0Vtx_EvSel/nBCsVsTime"), timeSinceSOF); + } int64_t globalBC = bc.globalBC(); + int localBC = static_cast(globalBC % nBCsPerOrbit); - if (globalBC - globalBCIdOfLastBCWithActivity < cfgEmptyBCsBeforeLeadingBC) - continue; // not a super-leading BC + int64_t globalBCFDD = globalBC + mBcShiftFDD; + int localBCFDD = static_cast((globalBCFDD % nBCsPerOrbit + nBCsPerOrbit) % nBCsPerOrbit); - if (bc.has_fdd() || (cfgRequireNoT0ForSLBC && bc.has_ft0())) - globalBCIdOfLastBCWithActivity = globalBC; + int64_t thisTFid = (globalBC - bcSOR) / nBCsPerTF; + if (thisTFid != currentTFid) { + currentTFid = thisTFid; + mHistManager.fill(HIST("TFsPerMinute"), timeSinceSOF); + } - float timeSinceSOF = getTimeSinceSOF(bc); + std::bitset<64> ctpInputMask(bc.inputMask()); - int localBC = globalBC % nBCsPerOrbit; + const bool anyFT0Trigger = hasAnyFT0Trigger(ctpInputMask); + const bool anyFDDTrigger = hasAnyFDDTrigger(ctpInputMask); - if (!bcPatternB[localBC]) - continue; + bool isSuperLeadingBcFDD = bcPatternB[localBCFDD] && + (globalBCFDD - globalBCIdOfLastBCWithActivityFDD >= cfgBCsBeforeSuperLeading); - fillHistograms(timeSinceSOF, localBC); + bool isSuperLeadingBcFT0 = bcPatternB[localBC] && + (globalBC - globalBCIdOfLastBCWithActivityFT0 >= cfgBCsBeforeSuperLeading); - if (ctpInputMask.test(2)) - fillHistograms(timeSinceSOF, localBC); - if (ctpInputMask.test(15)) - fillHistograms(timeSinceSOF, localBC); - } - } - PROCESS_SWITCH(LumiStabilityLightIons, processSLBunches, "process trigger counting of TVX and FDD for bunches without preceding single-arm activity", false); + if (cfgDoBCSLFDD || cfgDoBCSLFT0 || cfgDoBCNSLFDD || cfgDoBCNSLFT0) { + mHistManager.fill(HIST("FITQA/BCHasFT0"), bc.has_ft0(), ctpInputMask.test(2)); + mHistManager.fill(HIST("FITQA/BCHasFDD"), bc.has_fdd(), anyFDDTrigger); + } - void process(MyBCs const& bcs, aod::FT0s const&) - { - for (const auto& bc : bcs) { + int64_t globalBCStart = (globalBCLastInspectedBC >= 0 && globalBCLastInspectedBC < globalBC) ? globalBCLastInspectedBC + 1 : globalBC; + const int64_t maxBcGap = 2LL * nBCsPerOrbit; + if (globalBC - globalBCStart > maxBcGap) { + globalBCStart = globalBC; + } - if (bc.timestamp() == 0) - continue; + for (int64_t iGBC = globalBCStart; iGBC <= globalBC; ++iGBC) { + const int iLBC = static_cast((iGBC % nBCsPerOrbit + nBCsPerOrbit) % nBCsPerOrbit); + const int iLBCFDD = static_cast(((iGBC + mBcShiftFDD) % nBCsPerOrbit + nBCsPerOrbit) % nBCsPerOrbit); - setLHCIFData(bc); + countInspectedBC(nBCsPerBcId, iLBC, iLBCFDD, iGBC, + globalBCIdOfLastBCWithActivityFT0, + globalBCIdOfLastBCWithActivityFDD); - float timeSinceSOF = getTimeSinceSOF(bc); + if (cfgDoFT0Vtx && ctpInputMask.test(2)) { + countInspectedBC(nBCsPerBcId, iLBC, iLBCFDD, iGBC, + globalBCIdOfLastBCWithActivityFT0, + globalBCIdOfLastBCWithActivityFDD); + } - if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) - mHistManager.fill(HIST("FT0Vtx_EvSel/nBCsVsTime"), timeSinceSOF); + if (cfgDoFT0CE && ctpInputMask.test(4)) { + countInspectedBC(nBCsPerBcId, iLBC, iLBCFDD, iGBC, + globalBCIdOfLastBCWithActivityFT0, + globalBCIdOfLastBCWithActivityFDD); + } - int64_t globalBC = bc.globalBC(); - int localBC = globalBC % nBCsPerOrbit; + if (cfgDoFDD && anyFDDTrigger) { + countInspectedBC(nBCsPerBcId, iLBC, iLBCFDD, iGBC, + globalBCIdOfLastBCWithActivityFT0, + globalBCIdOfLastBCWithActivityFDD); + } - int64_t thisTFid = (globalBC - bcSOR) / nBCsPerTF; + if (cfgDo1ZNC && ctpInputMask.test(25)) { + countInspectedBC(nBCsPerBcId, iLBC, iLBCFDD, iGBC, + globalBCIdOfLastBCWithActivityFT0, + globalBCIdOfLastBCWithActivityFDD); + } + } - if (thisTFid != currentTFid) { - currentTFid = thisTFid; - mHistManager.fill(HIST("TFsPerMinute"), timeSinceSOF); + if (anyFDDTrigger) { + globalBCIdOfLastBCWithActivityFDD = globalBCFDD; + } + if (anyFT0Trigger) { + globalBCIdOfLastBCWithActivityFT0 = globalBC; } - std::bitset<64> ctpInputMask(bc.inputMask()); + globalBCLastInspectedBC = globalBC; + + if (cfgDoBCA && bcPatternA[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCB && bcPatternB[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCC && bcPatternC[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCE && bcPatternE[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCL && bcPatternL[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCLE && bcPatternLE[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCNL && bcPatternB[localBC] && !bcPatternL[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCNLE && bcPatternB[localBC] && !bcPatternLE[localBC]) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCSLFDD && isSuperLeadingBcFDD) { + fillHistograms(timeSinceSOF, localBCFDD); + } + if (cfgDoBCSLFT0 && isSuperLeadingBcFT0) { + fillHistograms(timeSinceSOF, localBC); + } + if (cfgDoBCNSLFDD && bcPatternB[localBCFDD] && !isSuperLeadingBcFDD) { + fillHistograms(timeSinceSOF, localBCFDD); + } + if (cfgDoBCNSLFT0 && bcPatternB[localBC] && !isSuperLeadingBcFT0) { + fillHistograms(timeSinceSOF, localBC); + } + + if (cfgDoFT0Vtx && ctpInputMask.test(2)) { + if (cfgDoBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCLE && bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNL && bcPatternB[localBC] && !bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNLE && bcPatternB[localBC] && !bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCSLFDD && isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCSLFT0 && isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNSLFDD && bcPatternB[localBCFDD] && !isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCNSLFT0 && bcPatternB[localBC] && !isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBC); + } + + if (cfgDoFT0CE && ctpInputMask.test(4)) { + if (cfgDoBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCLE && bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNL && bcPatternB[localBC] && !bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNLE && bcPatternB[localBC] && !bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCSLFDD && isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCSLFT0 && isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNSLFDD && bcPatternB[localBCFDD] && !isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCNSLFT0 && bcPatternB[localBC] && !isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBC); + } + + if (cfgDoFDD && anyFDDTrigger) { + if (cfgDoBCA && bcPatternA[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCB && bcPatternB[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCC && bcPatternC[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCE && bcPatternE[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCL && bcPatternL[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCLE && bcPatternLE[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCNL && bcPatternB[localBCFDD] && !bcPatternL[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCNLE && bcPatternB[localBCFDD] && !bcPatternLE[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCSLFDD && isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCSLFT0 && bcPatternB[localBCFDD] && isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCNSLFDD && bcPatternB[localBCFDD] && !isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCNSLFT0 && bcPatternB[localBCFDD] && !isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBCFDD); + } + + if (cfgDo1ZNC && ctpInputMask.test(25)) { + if (cfgDoBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCLE && bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNL && bcPatternB[localBC] && !bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNLE && bcPatternB[localBC] && !bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCSLFDD && isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCSLFT0 && isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBC); + if (cfgDoBCNSLFDD && bcPatternB[localBCFDD] && !isSuperLeadingBcFDD) + fillHistograms(timeSinceSOF, localBCFDD); + if (cfgDoBCNSLFT0 && bcPatternB[localBC] && !isSuperLeadingBcFT0) + fillHistograms(timeSinceSOF, localBC); + } + + mHistManager.fill(HIST("nBCsVsBCID"), localBC); + } - for (int iTrigger = 0; iTrigger < nTriggers; iTrigger++) { - if ((iTrigger == kAllBCs) || (iTrigger == kFT0Vtx && cfgDoFT0Vtx) || (iTrigger == kFT0CE && cfgDoFT0CE) || (iTrigger == kFDD && cfgDoFDD) || (iTrigger == k1ZNC && cfgDo1ZNC)) { - for (int iBCCategory = 0; iBCCategory < nBCCategories - 1; iBCCategory++) { // Don't do SL BCs here - if ((iBCCategory == kBCA && cfgDoBCA) || (iBCCategory == kBCB && cfgDoBCB) || (iBCCategory == kBCC && cfgDoBCC) || (iBCCategory == kBCE && cfgDoBCE) || (iBCCategory == kBCL && cfgDoBCL)) { - if (iTrigger == kAllBCs) { - if (iBCCategory == kBCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC); - } - if (iTrigger == kFT0Vtx && ctpInputMask.test(2)) { - if (iBCCategory == kBCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC); - } - if (iTrigger == kFT0CE && ctpInputMask.test(4)) { - if (iBCCategory == kBCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC); - } - if (iTrigger == kFDD && ctpInputMask.test(15)) { - if (iBCCategory == kBCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC); - } - if (iTrigger == k1ZNC && ctpInputMask.test(25)) { - if (iBCCategory == kBCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC); - if (iBCCategory == kBCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC); - } - } + for (int iT = 0; iT < nTriggers; ++iT) { + for (int iC = 0; iC < nBCCategories; ++iC) { + if (!mInspectedHistos[iT][iC]) { + continue; + } + for (int iBcId = 0; iBcId < nBCsPerOrbit; ++iBcId) { + const int value = nBCsPerBcId[iBcId][iT][iC]; + if (value > 0) { + mInspectedHistos[iT][iC]->Fill(iBcId, value); } } } - mHistManager.fill(HIST("nBCsVsBCID"), localBC); } } }; diff --git a/PWGMM/Lumi/Tasks/lumiStabilityPP.cxx b/PWGMM/Lumi/Tasks/lumiStabilityPP.cxx index 9143f524ff3..2962148c4dc 100644 --- a/PWGMM/Lumi/Tasks/lumiStabilityPP.cxx +++ b/PWGMM/Lumi/Tasks/lumiStabilityPP.cxx @@ -49,16 +49,20 @@ enum TriggerAliases { AllBCs = 0, FT0CE = 2, FDD = 3, NTriggerAliases }; -enum BCCategories { BCA = 0, // A side BCs (bunch-crossings that had beam only from A side) - BCB = 1, // B type BCs (bunch-crossings that had beam from both sides) - BCC = 2, // C side BCs (bunch-crossings that had beam only from C side) - BCE = 3, // empty BCs (bunch-crossings that did not have beam from either side) - BCL = 4, // leading BCs (bunch-crossings that did not have interacting bunches for a configurable number of preceding BCs) - BCSLFDD = 5, // super-leading BCs for FDD (bunch-crossings that had beam from both sides but did not have FDD activity for a configurable number of preceding BCs) - BCSLFT0 = 6, // super-leading BCs for FT0 (bunch-crossings that had beam from both sides but did not have FT0 activity for a configurable number of preceding BCs) - BCNL = 7, // non-leading BCs of type B (bunch-crossings that come after a BCL and are of type B) - BCNSLFDD = 8, // non-super-leading BCs for FDD of type B (bunch-crossings that had beam from both sides but are not SL for FDD activity for a configurable number of preceding BCs) - BCNSLFT0 = 9, // non-super-leading BCs for FT0 of type B (bunch-crossings that had beam from both sides but are not SL for FT0 activity for a configurable number of preceding BCs) + +// SL types must be after all the others +enum BCCategories { BCA = 0, // A side BCs (bunch-crossings that had beam only from A side) + BCB, // B type BCs (bunch-crossings that had beam from both sides) + BCC, // C side BCs (bunch-crossings that had beam only from C side) + BCE, // empty BCs (bunch-crossings that did not have beam from either side) + BCL, // leading BCs (bunch-crossings that have not-B BCs for a configurable number of preceding BCs) + BCLE, // leading BCs (bunch-crossings that did not have interacting bunches for a configurable number of preceding BCs) + BCNL, // non-leading BCs of type B (bunch-crossings that come after a BCL and are of type B) + BCNLE, // non-leading BCs of type B (bunch-crossings that come after a BCLE and are of type B) + BCSLFDD, // super-leading BCs for FDD (bunch-crossings that had beam from both sides but did not have FDD activity for a configurable number of preceding BCs) + BCSLFT0, // super-leading BCs for FT0 (bunch-crossings that had beam from both sides but did not have FT0 activity for a configurable number of preceding BCs) + BCNSLFDD, // non-super-leading BCs for FDD of type B (bunch-crossings that had beam from both sides but are not SL for FDD activity for a configurable number of preceding BCs) + BCNSLFT0, // non-super-leading BCs for FT0 of type B (bunch-crossings that had beam from both sides but are not SL for FT0 activity for a configurable number of preceding BCs) NBCCategories }; } // namespace lumi } // namespace o2 @@ -72,14 +76,15 @@ using BCsWithTimeStamps = soa::Join; struct LumiStabilityPP { - static constexpr int defaulFlags[1][NBCCategories] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; - Configurable> doTypeBC{"doTypeBC", {defaulFlags[0], NBCCategories, {"BCA", "BCB", "BCC", "BCE", "BCL", "BCSLFDD", "BCSLFT0", "BCNL", "BCNSLFDD", "BCNSLFT0"}}, "Create and fill histograms for different BC types"}; + static constexpr int defaulFlags[1][NBCCategories] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; + Configurable> doTypeBC{"doTypeBC", {defaulFlags[0], NBCCategories, {"BCA", "BCB", "BCC", "BCE", "BCL", "BCLE", "BCSLFDD", "BCSLFT0", "BCNL", "BCNLE", "BCNSLFDD", "BCNSLFT0"}}, "Create and fill histograms for different BC types"}; - Configurable numEmptyBCsBeforeLeadingBC{"numEmptyBCsBeforeLeadingBC", 5, "Number of (empty) non-B BCs before a (super)leading BC"}; + static constexpr int defaulNumBCsBeforeLeadingBC[1][3] = {{5, 5, 5}}; + Configurable> numEmptyBCsBeforeLeadingBC{"numEmptyBCsBeforeLeadingBC", {defaulNumBCsBeforeLeadingBC[0], 3, {"BCL", "BCLE", "BCSL"}}, "Create and fill histograms for different BC types"}; Configurable bcShiftFDDForData2023{"bcShiftFDDForData2023", 7, "Number of bc to shift for FDD to be applied for 2023 data only"}; std::bitset beamPatternA, beamPatternC; - std::bitset bcPatternA, bcPatternC, bcPatternB, bcPatternE, bcPatternL; + std::bitset bcPatternA, bcPatternC, bcPatternB, bcPatternE, bcPatternL, bcPatternLE; const int nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; o2::framework::Service ccdb; @@ -93,8 +98,8 @@ struct LumiStabilityPP { std::array>, NBCCategories>, NTriggerAliases> histBcVsTime; std::array>, NBCCategories>, NTriggerAliases> histBcVsBcId; - std::array>, NBCCategories>, NTriggerAliases> histMu; - std::array>, NBCCategories>, NTriggerAliases> histMuPerBcId; + std::array>, NBCCategories>, NTriggerAliases> histBcInspectVsBcId; + std::array>, BCSLFDD> histBcPattern; // undefined for BC(N)SL std::map> histNBcsVsTime; std::map> histNBcsVsBcId; std::map> histTfPerMin; @@ -103,22 +108,24 @@ struct LumiStabilityPP { std::map> histInteractionRate; static constexpr std::string_view NBCsVsTimeHistNames[NTriggerAliases][NBCCategories] = - {{"AllBCs/BC_A/nBCsVsTime", "AllBCs/BC_B/nBCsVsTime", "AllBCs/BC_C/nBCsVsTime", "AllBCs/BC_E/nBCsVsTime", "AllBCs/BC_L/nBCsVsTime", "AllBCs/BC_SL_FDD/nBCsVsTime", "AllBCs/BC_SL_FT0/nBCsVsTime", "AllBCs/BC_NL/nBCsVsTime", "AllBCs/BC_NSL_FT0/nBCsVsTime", "AllBCs/BC_NSL_FDD/nBCsVsTime"}, - {"FT0VTx/BC_A/nBCsVsTime", "FT0VTx/BC_B/nBCsVsTime", "FT0VTx/BC_C/nBCsVsTime", "FT0VTx/BC_E/nBCsVsTime", "FT0VTx/BC_L/nBCsVsTime", "FT0VTx/BC_SL_FDD/nBCsVsTime", "FT0VTx/BC_SL_FT0/nBCsVsTime", "FT0VTx/BC_NL/nBCsVsTime", "FT0VTx/BC_NSL_FT0/nBCsVsTime", "FT0VTx/BC_NSL_FDD/nBCsVsTime"}, - {"FT0CE/BC_A/nBCsVsTime", "FT0CE/BC_B/nBCsVsTime", "FT0CE/BC_C/nBCsVsTime", "FT0CE/BC_E/nBCsVsTime", "FT0CE/BC_L/nBCsVsTime", "FT0CE/BC_SL_FDD/nBCsVsTime", "FT0CE/BC_SL_FT0/nBCsVsTime", "FT0CE/BC_NL/nBCsVsTime", "FT0CE/BC_NSL_FT0/nBCsVsTime", "FT0CE/BC_NSL_FDD/nBCsVsTime"}, - {"FDD/BC_A/nBCsVsTime", "FDD/BC_B/nBCsVsTime", "FDD/BC_C/nBCsVsTime", "FDD/BC_E/nBCsVsTime", "FDD/BC_L/nBCsVsTime", "FDD/BC_SL_FDD/nBCsVsTime", "FDD/BC_SL_FT0/nBCsVsTime", "FDD/BC_NL/nBCsVsTime", "FDD/BC_NSL_FT0/nBCsVsTime", "FDD/BC_NSL_FDD/nBCsVsTime"}}; + {{"AllBCs/BC_A/nBCsVsTime", "AllBCs/BC_B/nBCsVsTime", "AllBCs/BC_C/nBCsVsTime", "AllBCs/BC_E/nBCsVsTime", "AllBCs/BC_L/nBCsVsTime", "AllBCs/BC_LE/nBCsVsTime", "AllBCs/BC_NL/nBCsVsTime", "AllBCs/BC_NLE/nBCsVsTime", "AllBCs/BC_SL_FDD/nBCsVsTime", "AllBCs/BC_SL_FT0/nBCsVsTime", "AllBCs/BC_NSL_FDD/nBCsVsTime", "AllBCs/BC_NSL_FT0/nBCsVsTime"}, + {"FT0VTx/BC_A/nBCsVsTime", "FT0VTx/BC_B/nBCsVsTime", "FT0VTx/BC_C/nBCsVsTime", "FT0VTx/BC_E/nBCsVsTime", "FT0VTx/BC_L/nBCsVsTime", "FT0VTx/BC_LE/nBCsVsTime", "FT0VTx/BC_NL/nBCsVsTime", "FT0VTx/BC_NLE/nBCsVsTime", "FT0VTx/BC_SL_FDD/nBCsVsTime", "FT0VTx/BC_SL_FT0/nBCsVsTime", "FT0VTx/BC_NSL_FDD/nBCsVsTime", "FT0VTx/BC_NSL_FT0/nBCsVsTime"}, + {"FT0CE/BC_A/nBCsVsTime", "FT0CE/BC_B/nBCsVsTime", "FT0CE/BC_C/nBCsVsTime", "FT0CE/BC_E/nBCsVsTime", "FT0CE/BC_L/nBCsVsTime", "FT0CE/BC_LE/nBCsVsTime", "FT0CE/BC_NL/nBCsVsTime", "FT0CE/BC_NLE/nBCsVsTime", "FT0CE/BC_SL_FDD/nBCsVsTime", "FT0CE/BC_SL_FT0/nBCsVsTime", "FT0CE/BC_NSL_FDD/nBCsVsTime", "FT0CE/BC_NSL_FT0/nBCsVsTime"}, + {"FDD/BC_A/nBCsVsTime", "FDD/BC_B/nBCsVsTime", "FDD/BC_C/nBCsVsTime", "FDD/BC_E/nBCsVsTime", "FDD/BC_L/nBCsVsTime", "FDD/BC_LE/nBCsVsTime", "FDD/BC_NL/nBCsVsTime", "FDD/BC_NLE/nBCsVsTime", "FDD/BC_SL_FDD/nBCsVsTime", "FDD/BC_SL_FT0/nBCsVsTime", "FDD/BC_NSL_FDD/nBCsVsTime", "FDD/BC_NSL_FT0/nBCsVsTime"}}; static constexpr std::string_view NBCsVsBCIDHistNames[NTriggerAliases][NBCCategories] = - {{"AllBCs/BC_A/nBCsVsBCID", "AllBCs/BC_B/nBCsVsBCID", "AllBCs/BC_C/nBCsVsBCID", "AllBCs/BC_E/nBCsVsBCID", "AllBCs/BC_L/nBCsVsBCID", "AllBCs/BC_SL_FDD/nBCsVsBCID", "AllBCs/BC_SL_FT0/nBCsVsBCID", "AllBCs/BC_NL/nBCsVsBCID", "AllBCs/BC_NSL_FT0/nBCsVsBCID", "AllBCs/BC_NSL_FDD/nBCsVsBCID"}, - {"FT0VTx/BC_A/nBCsVsBCID", "FT0VTx/BC_B/nBCsVsBCID", "FT0VTx/BC_C/nBCsVsBCID", "FT0VTx/BC_E/nBCsVsBCID", "FT0VTx/BC_L/nBCsVsBCID", "FT0VTx/BC_SL_FDD/nBCsVsBCID", "FT0VTx/BC_SL_FT0/nBCsVsBCID", "FT0VTx/BC_NL/nBCsVsBCID", "FT0VTx/BC_NSL_FT0/nBCsVsBCID", "FT0VTx/BC_NSL_FDD/nBCsVsBCID"}, - {"FT0CE/BC_A/nBCsVsBCID", "FT0CE/BC_B/nBCsVsBCID", "FT0CE/BC_C/nBCsVsBCID", "FT0CE/BC_E/nBCsVsBCID", "FT0CE/BC_L/nBCsVsBCID", "FT0CE/BC_SL_FDD/nBCsVsBCID", "FT0CE/BC_SL_FT0/nBCsVsBCID", "FT0CE/BC_NL/nBCsVsBCID", "FT0CE/BC_NSL_FT0/nBCsVsBCID", "FT0CE/BC_NSL_FDD/nBCsVsBCID"}, - {"FDD/BC_A/nBCsVsBCID", "FDD/BC_B/nBCsVsBCID", "FDD/BC_C/nBCsVsBCID", "FDD/BC_E/nBCsVsBCID", "FDD/BC_L/nBCsVsBCID", "FDD/BC_SL_FDD/nBCsVsBCID", "FDD/BC_SL_FT0/nBCsVsBCID", "FDD/BC_NL/nBCsVsBCID", "FDD/BC_NSL_FT0/nBCsVsBCID", "FDD/BC_NSL_FDD/nBCsVsBCID"}}; + {{"AllBCs/BC_A/nBCsVsBCID", "AllBCs/BC_B/nBCsVsBCID", "AllBCs/BC_C/nBCsVsBCID", "AllBCs/BC_E/nBCsVsBCID", "AllBCs/BC_L/nBCsVsBCID", "AllBCs/BC_LE/nBCsVsBCID", "AllBCs/BC_NL/nBCsVsBCID", "AllBCs/BC_NLE/nBCsVsBCID", "AllBCs/BC_SL_FDD/nBCsVsBCID", "AllBCs/BC_SL_FT0/nBCsVsBCID", "AllBCs/BC_NSL_FDD/nBCsVsBCID", "AllBCs/BC_NSL_FT0/nBCsVsBCID"}, + {"FT0VTx/BC_A/nBCsVsBCID", "FT0VTx/BC_B/nBCsVsBCID", "FT0VTx/BC_C/nBCsVsBCID", "FT0VTx/BC_E/nBCsVsBCID", "FT0VTx/BC_L/nBCsVsBCID", "FT0VTx/BC_LE/nBCsVsBCID", "FT0VTx/BC_NL/nBCsVsBCID", "FT0VTx/BC_NLE/nBCsVsBCID", "FT0VTx/BC_SL_FDD/nBCsVsBCID", "FT0VTx/BC_SL_FT0/nBCsVsBCID", "FT0VTx/BC_NSL_FDD/nBCsVsBCID", "FT0VTx/BC_NSL_FT0/nBCsVsBCID"}, + {"FT0CE/BC_A/nBCsVsBCID", "FT0CE/BC_B/nBCsVsBCID", "FT0CE/BC_C/nBCsVsBCID", "FT0CE/BC_E/nBCsVsBCID", "FT0CE/BC_L/nBCsVsBCID", "FT0CE/BC_LE/nBCsVsBCID", "FT0CE/BC_NL/nBCsVsBCID", "FT0CE/BC_NLE/nBCsVsBCID", "FT0CE/BC_SL_FDD/nBCsVsBCID", "FT0CE/BC_SL_FT0/nBCsVsBCID", "FT0CE/BC_NSL_FDD/nBCsVsBCID", "FT0CE/BC_NSL_FT0/nBCsVsBCID"}, + {"FDD/BC_A/nBCsVsBCID", "FDD/BC_B/nBCsVsBCID", "FDD/BC_C/nBCsVsBCID", "FDD/BC_E/nBCsVsBCID", "FDD/BC_L/nBCsVsBCID", "FDD/BC_LE/nBCsVsBCID", "FDD/BC_NL/nBCsVsBCID", "FDD/BC_NLE/nBCsVsBCID", "FDD/BC_SL_FDD/nBCsVsBCID", "FDD/BC_SL_FT0/nBCsVsBCID", "FDD/BC_NSL_FDD/nBCsVsBCID", "FDD/BC_NSL_FT0/nBCsVsBCID"}}; + + static constexpr std::string_view NBCsInspectVsBCIDHistNames[NTriggerAliases][NBCCategories] = + {{"AllBCs/BC_A/nBCsInspectedVsBCID", "AllBCs/BC_B/nBCsInspectedVsBCID", "AllBCs/BC_C/nBCsInspectedVsBCID", "AllBCs/BC_E/nBCsInspectedVsBCID", "AllBCs/BC_L/nBCsInspectedVsBCID", "AllBCs/BC_LE/nBCsInspectedVsBCID", "AllBCs/BC_NL/nBCsInspectedVsBCID", "AllBCs/BC_NLE/nBCsInspectedVsBCID", "AllBCs/BC_SL_FDD/nBCsInspectedVsBCID", "AllBCs/BC_SL_FT0/nBCsInspectedVsBCID", "AllBCs/BC_NSL_FDD/nBCsInspectedVsBCID", "AllBCs/BC_NSL_FT0/nBCsInspectedVsBCID"}, + {"FT0VTx/BC_A/nBCsInspectedVsBCID", "FT0VTx/BC_B/nBCsInspectedVsBCID", "FT0VTx/BC_C/nBCsInspectedVsBCID", "FT0VTx/BC_E/nBCsInspectedVsBCID", "FT0VTx/BC_L/nBCsInspectedVsBCID", "FT0VTx/BC_LE/nBCsInspectedVsBCID", "FT0VTx/BC_NL/nBCsInspectedVsBCID", "FT0VTx/BC_NLE/nBCsInspectedVsBCID", "FT0VTx/BC_SL_FDD/nBCsInspectedVsBCID", "FT0VTx/BC_SL_FT0/nBCsInspectedVsBCID", "FT0VTx/BC_NSL_FDD/nBCsInspectedVsBCID", "FT0VTx/BC_NSL_FT0/nBCsInspectedVsBCID"}, + {"FT0CE/BC_A/nBCsInspectedVsBCID", "FT0CE/BC_B/nBCsInspectedVsBCID", "FT0CE/BC_C/nBCsInspectedVsBCID", "FT0CE/BC_E/nBCsInspectedVsBCID", "FT0CE/BC_L/nBCsInspectedVsBCID", "FT0CE/BC_LE/nBCsInspectedVsBCID", "FT0CE/BC_NL/nBCsInspectedVsBCID", "FT0CE/BC_NLE/nBCsInspectedVsBCID", "FT0CE/BC_SL_FDD/nBCsInspectedVsBCID", "FT0CE/BC_SL_FT0/nBCsInspectedVsBCID", "FT0CE/BC_NSL_FDD/nBCsInspectedVsBCID", "FT0CE/BC_NSL_FT0/nBCsInspectedVsBCID"}, + {"FDD/BC_A/nBCsInspectedVsBCID", "FDD/BC_B/nBCsInspectedVsBCID", "FDD/BC_C/nBCsInspectedVsBCID", "FDD/BC_E/nBCsInspectedVsBCID", "FDD/BC_L/nBCsInspectedVsBCID", "FDD/BC_LE/nBCsInspectedVsBCID", "FDD/BC_NL/nBCsInspectedVsBCID", "FDD/BC_NLE/nBCsInspectedVsBCID", "FDD/BC_SL_FDD/nBCsInspectedVsBCID", "FDD/BC_SL_FT0/nBCsInspectedVsBCID", "FDD/BC_NSL_FDD/nBCsInspectedVsBCID", "FDD/BC_NSL_FT0/nBCsInspectedVsBCID"}}; - static constexpr std::string_view MuHistNames[NTriggerAliases][NBCCategories] = - {{"AllBCs/BC_A/Mu", "AllBCs/BC_B/Mu", "AllBCs/BC_C/Mu", "AllBCs/BC_E/Mu", "AllBCs/BC_L/Mu", "AllBCs/BC_SL_FDD/Mu", "AllBCs/BC_SL_FT0/Mu", "AllBCs/BC_NL/Mu", "AllBCs/BC_NSL_FT0/Mu", "AllBCs/BC_NSL_FDD/Mu"}, - {"FT0VTx/BC_A/Mu", "FT0VTx/BC_B/Mu", "FT0VTx/BC_C/Mu", "FT0VTx/BC_E/Mu", "FT0VTx/BC_L/Mu", "FT0VTx/BC_SL_FDD/Mu", "FT0VTx/BC_SL_FT0/Mu", "FT0VTx/BC_NL/Mu", "FT0VTx/BC_NSL_FT0/Mu", "FT0VTx/BC_NSL_FDD/Mu"}, - {"FT0CE/BC_A/Mu", "FT0CE/BC_B/Mu", "FT0CE/BC_C/Mu", "FT0CE/BC_E/Mu", "FT0CE/BC_L/Mu", "FT0CE/BC_SL_FDD/Mu", "FT0CE/BC_SL_FT0/Mu", "FT0CE/BC_NL/Mu", "FT0CE/BC_NSL_FT0/Mu", "FT0CE/BC_NSL_FDD/Mu"}, - {"FDD/BC_A/Mu", "FDD/BC_B/Mu", "FDD/BC_C/Mu", "FDD/BC_E/Mu", "FDD/BC_L/Mu", "FDD/BC_SL_FDD/Mu", "FDD/BC_SL_FT0/Mu", "FDD/BC_NL/Mu", "FDD/BC_NSL_FT0/Mu", "FDD/BC_NSL_FDD/Mu"}}; + static constexpr std::string_view PatternHistNames[BCSLFDD] = {"BC_A/BcPattern", "BC_B/BcPattern", "BC_C/BcPattern", "BC_E/BcPattern", "BC_L/BcPattern", "BC_LE/BcPattern", "BC_NL/BcPattern", "BC_NLE/BcPattern"}; const AxisSpec timeAxis{2880, 0., 2880., "#bf{t-t_{SOF} (min)}"}, bcIDAxis{nBCsPerOrbit, -0.5, static_cast(nBCsPerOrbit) - 0.5, "#bf{BC ID in orbit}"}; @@ -146,11 +153,14 @@ struct LumiStabilityPP { if (doTypeBC->get(0u, iBCCategory)) { histBcVsTime[iTrigger][iBCCategory][runNumber] = registry.add(Form("%d/%s", runNumber, std::string(NBCsVsTimeHistNames[iTrigger][iBCCategory]).c_str()), "Time of triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis}); histBcVsBcId[iTrigger][iBCCategory][runNumber] = registry.add(Form("%d/%s", runNumber, std::string(NBCsVsBCIDHistNames[iTrigger][iBCCategory]).c_str()), "BC ID of triggered BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis}); - histMu[iTrigger][iBCCategory][runNumber] = registry.add(Form("%d/%s", runNumber, std::string(MuHistNames[iTrigger][iBCCategory]).c_str()), "pile-up #mu of different triggers;#mu;counts", HistType::kTH1D, {{400, 0., 0.2}}); - histMuPerBcId[iTrigger][iBCCategory][runNumber] = registry.add(Form("%d/%sVsBcId", runNumber, std::string(MuHistNames[iTrigger][iBCCategory]).c_str()), "pile-up #mu of different triggers per BCId;#mu;counts", HistType::kTH2D, {{bcIDAxis}, {400, 0., 0.2}}); + histBcInspectVsBcId[iTrigger][iBCCategory][runNumber] = registry.add(Form("%d/%s", runNumber, std::string(NBCsInspectVsBCIDHistNames[iTrigger][iBCCategory]).c_str()), "BC ID of inspecred BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis}); } } } + + for (int iBCCategory{0}; iBCCategory < BCSLFDD; ++iBCCategory) { + histBcPattern[iBCCategory][runNumber] = registry.add(Form("%d/%s", runNumber, std::string(PatternHistNames[iBCCategory]).c_str()), "BC Pattern;#bf{BC ID in orbit};", HistType::kTH1D, {bcIDAxis}); + } } void setLHCIFData(const auto& bc) @@ -197,14 +207,15 @@ struct LumiStabilityPP { // Create bcPatternL: leading BCs of type B that follow at least "numEmptyBCsBeforeLeadingBC" non-B BCs bcPatternL.reset(); // Initialize all bits to false + bcPatternLE.reset(); LOG(info) << "Starting to create bcPatternL from bcPatternB"; LOG(info) << "Total number of BCs to check: " << o2::constants::lhc::LHCMaxBunches; - int totalLeadingBCs = 0; + std::array totalLeadingBCs = {0, 0}; for (int iBC = 0; iBC < o2::constants::lhc::LHCMaxBunches; iBC++) { if (bcPatternB[iBC]) { // Check if current BC is of type B - int nonBtypeBCsBefore = 0; // Count how many consecutive BCs before this one are non-B - for (int j = 1; j <= numEmptyBCsBeforeLeadingBC; j++) { + int nonBtypeBCsBefore{0}, emptyBCsBefore{0}; // Count how many consecutive BCs before this one are non-B + for (int j = 1; j <= numEmptyBCsBeforeLeadingBC->get(0u, 0u); j++) { int prevBC = (iBC - j + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // Protection for BCs at small indices to check the end of the orbit if (!bcPatternB[prevBC]) { nonBtypeBCsBefore++; @@ -212,13 +223,50 @@ struct LumiStabilityPP { break; // Stop counting if we hit a BCB } } - if (nonBtypeBCsBefore >= numEmptyBCsBeforeLeadingBC) { // If we found at least numEmptyBCsBeforeLeadingBC non-B BCs before this one, mark it as leading + for (int j = 1; j <= numEmptyBCsBeforeLeadingBC->get(0u, 1u); j++) { + int prevBC = (iBC - j + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // Protection for BCs at small indices to check the end of the orbit + if (bcPatternE[prevBC]) { + emptyBCsBefore++; + } else { + break; // Stop counting if we hit a non BCE + } + } + if (nonBtypeBCsBefore >= numEmptyBCsBeforeLeadingBC->get(0u, 0u)) { // If we found at least numEmptyBCsBeforeLeadingBC[0] non-B BCs before this one, mark it as leading bcPatternL[iBC] = true; - totalLeadingBCs++; + totalLeadingBCs[0]++; + } + if (emptyBCsBefore >= numEmptyBCsBeforeLeadingBC->get(0u, 1u)) { // If we found at least numEmptyBCsBeforeLeadingBC[1] empty BCs before this one, mark it as leading + bcPatternLE[iBC] = true; + totalLeadingBCs[1]++; } } + if (bcPatternA[iBC]) { + histBcPattern[BCA][runNumber]->Fill(iBC); + } + if (bcPatternB[iBC]) { + histBcPattern[BCB][runNumber]->Fill(iBC); + if (!bcPatternL[iBC]) { + histBcPattern[BCNL][runNumber]->Fill(iBC); + } + if (!bcPatternLE[iBC]) { + histBcPattern[BCNLE][runNumber]->Fill(iBC); + } + } + if (bcPatternC[iBC]) { + histBcPattern[BCC][runNumber]->Fill(iBC); + } + if (bcPatternE[iBC]) { + histBcPattern[BCE][runNumber]->Fill(iBC); + } + if (bcPatternL[iBC]) { + histBcPattern[BCL][runNumber]->Fill(iBC); + } + if (bcPatternLE[iBC]) { + histBcPattern[BCLE][runNumber]->Fill(iBC); + } } - LOG(info) << "bcPatternL creation complete. Total leading BCs found: " << totalLeadingBCs; + LOG(info) << "bcPatternL creation complete. Total leading BCs found: " << totalLeadingBCs[0]; + LOG(info) << "bcPatternLE creation complete. Total leading BCs found: " << totalLeadingBCs[1]; auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), runNumber, metadataInfo.get("LPMProductionTag")); bcSOR = runInfo.orbitSOR * nBCsPerOrbit; // first bc of the first orbit @@ -233,18 +281,9 @@ struct LumiStabilityPP { return (bc.timestamp() - mLHCIFdata->getFillNumberTime()) / 1e3 / 60; // Convert to minutes } - float getMu(double ntriggers, int nbc) - { - if (nbc == 0) { - return 0.; - } - return -std::log(1.f - ntriggers / nbc); - } - template - void fillHistograms(float timeSinceSOF, int64_t localBC, int& nTriggers) + void fillHistograms(float timeSinceSOF, int64_t localBC) { - nTriggers += 1; histBcVsTime[iTrigger][iBCCategory][runNumber]->Fill(timeSinceSOF); histBcVsBcId[iTrigger][iBCCategory][runNumber]->Fill(localBC); } @@ -257,12 +296,6 @@ struct LumiStabilityPP { std::vector> nBCsPerBcId; nBCsPerBcId.resize(nBCsPerOrbit); std::fill(&nBCsPerBcId[0][0], &nBCsPerBcId[0][0] + (static_cast(nBCsPerOrbit) * static_cast(NBCCategories)), 0); // Initialize to 0 - std::vector, NTriggerAliases>> nTriggersPerBcId; - nTriggersPerBcId.resize(nBCsPerOrbit); - std::fill(&nTriggersPerBcId[0][0][0], &nTriggersPerBcId[0][0][0] + (static_cast(nBCsPerOrbit) * static_cast(NTriggerAliases) * static_cast(NBCCategories)), 0); // Initialize to 0 - - int nTriggersPerDf[NTriggerAliases][NBCCategories]; - std::fill(&nTriggersPerDf[0][0], &nTriggersPerDf[0][0] + (static_cast(NTriggerAliases) * static_cast(NBCCategories)), 0); // Initialize to 0 double rate{-1.}; for (const auto& bc : bcs) { @@ -297,30 +330,23 @@ struct LumiStabilityPP { int localBCFDD = globalBCFDD % nBCsPerOrbit; bool isSuperLeadingBcFDD{true}, isSuperLeadingBcFT0{true}; - if (globalBCFDD - globalBCIdOfLastBCWithActivityFDD < numEmptyBCsBeforeLeadingBC) { + if (globalBCFDD - globalBCIdOfLastBCWithActivityFDD < numEmptyBCsBeforeLeadingBC->get(0u, 2u)) { isSuperLeadingBcFDD = false; // not a super-leading BC for FDD } - if (globalBC - globalBCIdOfLastBCWithActivityFT0 < numEmptyBCsBeforeLeadingBC) { + if (globalBC - globalBCIdOfLastBCWithActivityFT0 < numEmptyBCsBeforeLeadingBC->get(0u, 2u)) { isSuperLeadingBcFT0 = false; // not a super-leading BC for FT0 } - if (ctpInputMask.test(13) || ctpInputMask.test(15) || ctpInputMask.test(16) || ctpInputMask.test(17) || ctpInputMask.test(18)) { // 5 FDD triggers - globalBCIdOfLastBCWithActivityFDD = globalBC; - } - if (ctpInputMask.test(1) || ctpInputMask.test(2) || ctpInputMask.test(3) || ctpInputMask.test(4) || ctpInputMask.test(5)) { // 5 FT0 triggers - globalBCIdOfLastBCWithActivityFT0 = globalBCFDD; + if (!bcPatternB[localBCFDD]) { + isSuperLeadingBcFDD = false; // not a super-leading BC for FDD } - if (!bcPatternB[localBC]) { - isSuperLeadingBcFT0 = false; // not a super-leading BC - } - if (!bcPatternB[localBCFDD]) { - isSuperLeadingBcFDD = false; // not a super-leading BC + isSuperLeadingBcFT0 = false; // not a super-leading BC for FT0 } int64_t globalBCStart = (globalBCLastInspectedBC >= 0 && globalBCLastInspectedBC < globalBC) ? globalBCLastInspectedBC + 1 : globalBC; - int64_t maxBcDiff = (rate > 0) ? 10 * static_cast(nBunchesFillingScheme * constants::lhc::LHCRevFreq / rate / 1.e3) : 1500; - if (globalBC - globalBCStart > maxBcDiff) { // we changed fill, we should not count all BCs between the current and the previous one + int64_t maxBcDiff = (rate > 0) ? 15 * static_cast(nBunchesFillingScheme * constants::lhc::LHCRevFreq / rate / 1.e3) : 1500; + if (globalBC - globalBCStart > maxBcDiff) { // we have a big jump in global BCs, we should not count all BCs between the current and the previous one globalBCStart = globalBC; } for (int64_t iGlobalBC{globalBCStart}; iGlobalBC <= globalBC; ++iGlobalBC) { // we count all BCs in between one and another stored in the AO2Ds @@ -330,12 +356,12 @@ struct LumiStabilityPP { } if (bcPatternB[iLocalBC]) { nBCsPerBcId[iLocalBC][BCB]++; - if (iGlobalBC - globalBCIdOfLastBCWithActivityFDD > numEmptyBCsBeforeLeadingBC) { + if (iGlobalBC - globalBCIdOfLastBCWithActivityFDD >= numEmptyBCsBeforeLeadingBC->get(0u, 2u)) { nBCsPerBcId[iLocalBC][BCSLFDD]++; } else { nBCsPerBcId[iLocalBC][BCNSLFDD]++; } - if (iGlobalBC - globalBCIdOfLastBCWithActivityFT0 > numEmptyBCsBeforeLeadingBC) { + if (iGlobalBC - globalBCIdOfLastBCWithActivityFT0 >= numEmptyBCsBeforeLeadingBC->get(0u, 2u)) { nBCsPerBcId[iLocalBC][BCSLFT0]++; } else { nBCsPerBcId[iLocalBC][BCNSLFT0]++; @@ -343,6 +369,9 @@ struct LumiStabilityPP { if (!bcPatternL[iLocalBC]) { nBCsPerBcId[iLocalBC][BCNL]++; } + if (!bcPatternLE[iLocalBC]) { + nBCsPerBcId[iLocalBC][BCNLE]++; + } } if (bcPatternC[iLocalBC]) { nBCsPerBcId[iLocalBC][BCC]++; @@ -353,6 +382,16 @@ struct LumiStabilityPP { if (bcPatternL[iLocalBC]) { nBCsPerBcId[iLocalBC][BCL]++; } + if (bcPatternLE[iLocalBC]) { + nBCsPerBcId[iLocalBC][BCLE]++; + } + } + + if (ctpInputMask.test(12) || ctpInputMask.test(14) || ctpInputMask.test(15) || ctpInputMask.test(16) || ctpInputMask.test(17)) { // 5 FDD triggers + globalBCIdOfLastBCWithActivityFDD = globalBCFDD; + } + if (ctpInputMask.test(0) || ctpInputMask.test(1) || ctpInputMask.test(2) || ctpInputMask.test(3) || ctpInputMask.test(4)) { // 5 FT0 triggers + globalBCIdOfLastBCWithActivityFT0 = globalBC; } int64_t thisTFid = (globalBC - bcSOR) / nBCsPerTF; @@ -367,91 +406,107 @@ struct LumiStabilityPP { if (doTypeBC->get(0u, iBCCategory)) { if (iTrigger == AllBCs) { if (iBCCategory == BCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == BCLE && bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCSLFDD && isSuperLeadingBcFDD) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCSLFT0 && isSuperLeadingBcFT0) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNL && !bcPatternL[localBC] && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == BCNLE && !bcPatternLE[localBC] && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNSLFDD && !isSuperLeadingBcFDD && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNSLFT0 && !isSuperLeadingBcFT0 && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); } if (iTrigger == FT0Vtx && ctpInputMask.test(2)) { if (iBCCategory == BCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == BCLE && bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCSLFDD && isSuperLeadingBcFDD) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCSLFT0 && isSuperLeadingBcFT0) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNL && !bcPatternL[localBC] && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == BCNLE && !bcPatternLE[localBC] && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNSLFDD && !isSuperLeadingBcFDD && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNSLFT0 && !isSuperLeadingBcFT0 && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); } if (iTrigger == FT0CE && ctpInputMask.test(4)) { if (iBCCategory == BCA && bcPatternA[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCB && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCC && bcPatternC[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCE && bcPatternE[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCL && bcPatternL[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == BCLE && bcPatternLE[localBC]) + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCSLFDD && isSuperLeadingBcFDD) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCSLFT0 && isSuperLeadingBcFT0) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNL && !bcPatternL[localBC] && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == BCNLE && !bcPatternLE[localBC] && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNSLFDD && !isSuperLeadingBcFDD && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); if (iBCCategory == BCNSLFT0 && !isSuperLeadingBcFT0 && bcPatternB[localBC]) - fillHistograms(timeSinceSOF, localBC, nTriggersPerBcId[localBC][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBC); } if (iTrigger == FDD && ctpInputMask.test(15)) { if (iBCCategory == BCA && bcPatternA[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCB && bcPatternB[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCC && bcPatternC[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCE && bcPatternE[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCL && bcPatternL[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); + if (iBCCategory == BCLE && bcPatternLE[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCSLFDD && isSuperLeadingBcFDD) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCSLFT0 && isSuperLeadingBcFT0) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCNL && !bcPatternL[localBCFDD] && bcPatternB[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); + if (iBCCategory == BCNLE && !bcPatternLE[localBCFDD] && bcPatternB[localBCFDD]) + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCNSLFDD && !isSuperLeadingBcFDD && bcPatternB[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); if (iBCCategory == BCNSLFT0 && !isSuperLeadingBcFT0 && bcPatternB[localBCFDD]) - fillHistograms(timeSinceSOF, localBCFDD, nTriggersPerBcId[localBCFDD][iTrigger][iBCCategory]); + fillHistograms(timeSinceSOF, localBCFDD); } } } @@ -467,16 +522,9 @@ struct LumiStabilityPP { for (int iTrigger{0}; iTrigger < NTriggerAliases; ++iTrigger) { for (int iBCCategory{0}; iBCCategory < NBCCategories; ++iBCCategory) { if (doTypeBC->get(0u, iBCCategory)) { - int nTotBCs{0}; - int nTotTriggers{0}; for (int iBcId{0}; iBcId < nBCsPerOrbit; ++iBcId) { - float muPerBcId = getMu(nTriggersPerBcId[iBcId][iTrigger][iBCCategory], nBCsPerBcId[iBcId][iBCCategory]); - histMuPerBcId[iTrigger][iBCCategory][runNumber]->Fill(iBcId, muPerBcId); - nTotBCs += nBCsPerBcId[iBcId][iBCCategory]; - nTotTriggers += nTriggersPerBcId[iBcId][iTrigger][iBCCategory]; + histBcInspectVsBcId[iTrigger][iBCCategory][runNumber]->Fill(iBcId, nBCsPerBcId[iBcId][iBCCategory]); } - float mu = getMu(nTotTriggers, nTotBCs); - histMu[iTrigger][iBCCategory][runNumber]->Fill(mu); } } } diff --git a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx index 4380a7471c6..3b060924ad7 100644 --- a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx +++ b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx @@ -120,7 +120,7 @@ struct DndetaMFTPbPb { std::array, 4> hCollAssoc; std::array, 4> hReAssoc; - std::array, 6> hDCAMc; + std::array, 8> hDCAMc; enum OccupancyEst { TrkITS = 1, Ft0C }; @@ -147,6 +147,7 @@ struct DndetaMFTPbPb { Configurable cfgIRSource{"cfgIRSource", "ZNC hadronic", "Estimator of the interaction rate (Pb-Pb: ZNC hadronic)"}; Configurable cfgUseTrackSel{"cfgUseTrackSel", false, "Flag to apply track selection"}; Configurable cfgUseParticleSel{"cfgUseParticleSel", false, "Flag to apply particle selection"}; + Configurable cfgRemoveTrivialAssoc{"cfgRemoveTrivialAssoc", false, "Skip trivial associations"}; Configurable cfgRemoveReassigned{"cfgRemoveReassigned", false, "Remove reassgined tracks"}; Configurable cfgUseTrackParExtra{"cfgUseTrackParExtra", false, "Use table with refitted track parameters"}; Configurable cfgUseInelgt0{"cfgUseInelgt0", false, "Use INEL > 0 condition"}; @@ -921,6 +922,9 @@ struct DndetaMFTPbPb { } if (doprocessCollAssocMC) { + + registry.add("Events/hNAssocColls", "Number of times generated collisions are reconstructed; N; Counts", HistType::kTH1F, {{10, -0.5, 9.5}}); + // tracks not associated to any collision hCollAssoc[0] = qaregistry.add("TrackToColl/hNonAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis, deltaZAxis, deltaZAxis}); // tracks associasted to a collision @@ -929,17 +933,47 @@ struct DndetaMFTPbPb { hCollAssoc[2] = qaregistry.add("TrackToColl/hGoodAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis, deltaZAxis, deltaZAxis}); // tracks associated to the correct collision considering all ambiguous reco collisions (based on the MC collision index) hCollAssoc[3] = qaregistry.add("TrackToColl/hGoodAssocTracksAmb", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis, deltaZAxis, deltaZAxis}); + qaregistry.add("TrackToColl/histFracTracksFakeMcColl", "Fraction of tracks originating from fake collision; fraction; entries", {HistType::kTH1F, {{101, 0., 1.01}}}); qaregistry.add("TrackToColl/histFracGoodTracks", "Fraction of tracks originating from the correct collision; fraction; entries", {HistType::kTH1F, {{101, 0., 1.01}}}); qaregistry.add("TrackToColl/histAmbTrackNumColls", "Number of collisions associated to an ambiguous track; no. collisions; entries", {HistType::kTH1F, {{30, -0.5, 29.5}}}); + qaregistry.add("TrackToColl/histTrackNumColls", "Number of collisions associated to track; no. collisions; entries", {HistType::kTH1F, {{30, -0.5, 29.5}}}); + qaregistry.add("TrackToColl/histNonAmbTrackNumColls", "Number of collisions associated to non-ambiguous track; no. collisions; entries", {HistType::kTH1F, {{30, -0.5, 29.5}}}); qaregistry.add("TrackToColl/histAmbTrackZvtxRMS", "RMS of #it{Z}^{reco} of collisions associated to a track; RMS(#it{Z}^{reco}) (cm); entries", {HistType::kTH1F, {{100, 0., 0.5}}}); } if (doprocessReAssocMC) { + + registry.add("Events/hNReAssocColls", "Number of times generated collisions are reconstructed; N; Counts", HistType::kTH1F, {{10, -0.5, 9.5}}); + + registry.add("Events/ReAssocMCStatus", ";status", {HistType::kTH1F, {{12, 0.5, 12.5}}}); + auto hstat = registry.get(HIST("Events/ReAssocMCStatus")); + hstat->GetXaxis()->SetBinLabel(1, "All compatible"); + hstat->GetXaxis()->SetBinLabel(2, "Selected"); + hstat->GetXaxis()->SetBinLabel(3, "Has collision"); + hstat->GetXaxis()->SetBinLabel(4, "Reassigned"); + hstat->GetXaxis()->SetBinLabel(5, "Has particle"); + hstat->GetXaxis()->SetBinLabel(6, "Pos z MC cut"); + hstat->GetXaxis()->SetBinLabel(7, "Associated"); + hstat->GetXaxis()->SetBinLabel(8, "Associated true"); + hstat->GetXaxis()->SetBinLabel(9, "Associated wrong"); + hstat->GetXaxis()->SetBinLabel(10, "Reassociated"); + hstat->GetXaxis()->SetBinLabel(11, "Reassociated true"); + hstat->GetXaxis()->SetBinLabel(12, "Reassociated wrong"); + hReAssoc[0] = qaregistry.add("ReAssoc/hAssocBestTrue", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis, deltaZAxis, deltaZAxis}); hReAssoc[1] = qaregistry.add("ReAssoc/hAssocBestWrong", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis, deltaZAxis, deltaZAxis}); hReAssoc[2] = qaregistry.add("ReAssoc/hReAssocBestTrue", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis, deltaZAxis, deltaZAxis}); hReAssoc[3] = qaregistry.add("ReAssoc/hReAssocBestWrong", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis, deltaZAxis, deltaZAxis}); + + hDCAMc[0] = qaregistry.add("ReAssoc/hAssocBestTrueDCAPrim", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); + hDCAMc[1] = qaregistry.add("ReAssoc/hAssocBestTrueDCASec", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); + hDCAMc[2] = qaregistry.add("ReAssoc/hAssocBestWrongDCAPrim", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); + hDCAMc[3] = qaregistry.add("ReAssoc/hAssocBestWrongDCASec", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); + hDCAMc[4] = qaregistry.add("ReAssoc/hReAssocBestTrueDCAPrim", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); + hDCAMc[5] = qaregistry.add("ReAssoc/hReAssocBestTrueDCASec", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); + hDCAMc[6] = qaregistry.add("ReAssoc/hReAssocBestWrongDCAPrim", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); + hDCAMc[7] = qaregistry.add("ReAssoc/hReAssocBestWrongDCASec", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};DCA_{XY} (cm)^{reco}; DCA_{Z} (cm)^{reco}; DCA_{XY} (cm); DCA_{Z} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, dcaxyAxis, dcazAxis}); } if (doprocessEfficiencyInclusive) { @@ -1018,63 +1052,6 @@ struct DndetaMFTPbPb { } } - if (doprocessDCAReassocMcInclusive || doprocessDCAReassocMcCentFT0C) { - auto hNevt = registry.add("Events/hNGenRecCollsReassoc", "Number of generated and reconstructed MC collisions", HistType::kTH1F, {{3, 0.5, 3.5}}); - hNevt->GetXaxis()->SetBinLabel(1, "Reconstructed collisions"); - hNevt->GetXaxis()->SetBinLabel(2, "Generated collisions"); - if (doprocessDCAReassocMcInclusive) { - registry.add({"Events/EvtGenRecReassoc", ";status", {HistType::kTH2F, {{3, 0.5, 3.5}, occupancyAxis}}}); - auto heff = registry.get(HIST("Events/EvtGenRecReassoc")); - auto* h = heff->GetXaxis(); - h->SetBinLabel(1, "All generated"); - h->SetBinLabel(2, "All reconstructed"); - h->SetBinLabel(3, "Selected reconstructed"); - registry.add({"Tracks/THnDCAxyBestRec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestRecFake", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenTruthPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenTruthPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - - registry.add({"Tracks/BestGenPrimDeltaX", ";#Delta X (cm)", {HistType::kTH1F, {deltaZAxis}}}); - registry.add({"Tracks/BestGenSecDeltaX", ";#Delta X (cm)", {HistType::kTH1F, {deltaZAxis}}}); - registry.add({"Tracks/BestGenPrimWrongCollDeltaX", ";#Delta X (cm)", {HistType::kTH1F, {deltaZAxis}}}); - registry.add({"Tracks/BestGenSecWrongCollDeltaX", ";#Delta X (cm)", {HistType::kTH1F, {deltaZAxis}}}); - - registry.add({"Tracks/THnDCAxyBestGenSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenTruthSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenTruthSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenSecWeak", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - registry.add({"Tracks/THnDCAxyBestGenSecMat", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); - } - if (doprocessDCAReassocMcCentFT0C) { - registry.add({"Events/Centrality/EvtGenRecReassoc", ";status;centrality", {HistType::kTHnSparseF, {{3, 0.5, 3.5}, centralityAxis, occupancyAxis}}}); - auto heff = registry.get(HIST("Events/Centrality/EvtGenRecReassoc")); - heff->GetAxis(0)->SetBinLabel(1, "All generated"); - heff->GetAxis(0)->SetBinLabel(2, "All reconstructed"); - heff->GetAxis(0)->SetBinLabel(3, "Selected reconstructed"); - registry.add({"Tracks/Centrality/THnDCAxyBestRec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestRecFake", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - - registry.add({"Tracks/Centrality/BestGenPrimDeltaX", ";#Delta X (cm)", {HistType::kTH2F, {deltaZAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/BestGenSecDeltaX", ";#Delta X (cm)", {HistType::kTH2F, {deltaZAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/BestGenPrimWrongCollDeltaX", ";#Delta X (cm)", {HistType::kTH2F, {deltaZAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/BestGenSecWrongCollDeltaX", ";#Delta X (cm)", {HistType::kTH2F, {deltaZAxis, centralityAxis}}}); - - registry.add({"Tracks/Centrality/THnDCAxyBestGenSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenSecWeak", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - registry.add({"Tracks/Centrality/THnDCAxyBestGenSecMat", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); - } - } - if (doprocessAlignmentInclusive) { for (size_t j = 0; j < mftQuadrant.size(); j++) { const auto& quadrant = mftQuadrant[j]; @@ -1101,7 +1078,6 @@ struct DndetaMFTPbPb { hstat->GetXaxis()->SetBinLabel(9, "Correctly assigned true"); registry.add({"AmbTracks/hVtxzMCrec", " ; Z_{vtx} (cm)", {HistType::kTH1F, {zAxis}}}); - registry.add({"AmbTracks/DCAXY", " ; DCA_{XY} (cm)", {HistType::kTH1F, {dcaxyAxis}}}); registry.add({"AmbTracks/DCAZ", " ; DCA_{Z} (cm)", {HistType::kTH1F, {dcazAxis}}}); registry.add({"AmbTracks/DCAXYBest", " ; DCA_{XY} (cm)", {HistType::kTH1F, {dcaxyAxis}}}); @@ -2996,32 +2972,59 @@ struct DndetaMFTPbPb { aod::McCollisions const& /*mccollisions*/ ) { - for (const auto& collision : collisions) { - if (!collision.has_mcCollision()) { - continue; - } - // auto mcCollision = collision.template mcCollision_as(); - auto tracksInColl = tracksInAcc->sliceByCached(aod::fwdtrack::collisionId, collision.globalIndex(), cache); - int nTrk = 0, nFakeTrk = 0, nGoodTrk = 0; - for (const auto& track : tracksInColl) { - if (!track.has_mcParticle()) { + const auto& nRecoColls = collisions.size(); + registry.fill(HIST("Events/hNAssocColls"), 1.f, nRecoColls); + // Generated evets with >= 1 reco collisions + if (nRecoColls > CintZero) { + auto maxNcontributors = -1; + auto bestCollIndex = -1; + for (const auto& collision : collisions) { + if (!isGoodEvent(collision)) { continue; } - nTrk++; - auto particle = track.mcParticle(); + if (!collision.has_mcCollision()) { + continue; + } + if (maxNcontributors < collision.numContrib()) { + maxNcontributors = collision.numContrib(); + bestCollIndex = collision.globalIndex(); + } + } - if ((particle.mcCollisionId() != collision.mcCollision().globalIndex())) { - nFakeTrk++; + for (const auto& collision : collisions) { + if (!isGoodEvent(collision)) { + continue; + } + if (!collision.has_mcCollision()) { continue; } - if (collision.mcCollisionId() == particle.mcCollisionId()) { - nGoodTrk++; + // Select collisions with the largest number of contributors + if (bestCollIndex != collision.globalIndex()) { + continue; + } + // auto mcCollision = collision.template mcCollision_as(); + auto tracksInColl = tracksInAcc->sliceByCached(aod::fwdtrack::collisionId, collision.globalIndex(), cache); + int nTrk = 0, nFakeTrk = 0, nGoodTrk = 0; + for (const auto& track : tracksInColl) { + if (!track.has_mcParticle()) { + continue; + } + nTrk++; + auto particle = track.mcParticle(); + + if ((particle.mcCollisionId() != collision.mcCollision().globalIndex())) { + nFakeTrk++; + continue; + } + if (collision.mcCollisionId() == particle.mcCollisionId()) { + nGoodTrk++; + } } + float frac = (nTrk > 0) ? static_cast(nGoodTrk) / nTrk : -1.; + qaregistry.fill(HIST("TrackToColl/histFracGoodTracks"), frac); + float fracFake = (nTrk > 0) ? static_cast(nFakeTrk) / nTrk : -1.; + qaregistry.fill(HIST("TrackToColl/histFracTracksFakeMcColl"), fracFake); } - float frac = (nTrk > 0) ? static_cast(nGoodTrk) / nTrk : -1.; - qaregistry.fill(HIST("TrackToColl/histFracGoodTracks"), frac); - float fracFake = (nTrk > 0) ? static_cast(nFakeTrk) / nTrk : -1.; - qaregistry.fill(HIST("TrackToColl/histFracTracksFakeMcColl"), fracFake); } for (const auto& track : tracks) { @@ -3029,10 +3032,19 @@ struct DndetaMFTPbPb { if (track.has_mcParticle()) { // auto particle = track.mcParticle_as(); const auto& particle = track.mcParticle(); + + qaregistry.fill(HIST("TrackToColl/histTrackNumColls"), track.compatibleCollIds().size()); + + if (gConf.cfgRemoveTrivialAssoc) { + if (track.compatibleCollIds().empty() || (track.compatibleCollIds().size() == 1 && track.collisionId() == track.compatibleCollIds()[0])) { + qaregistry.fill(HIST("TrackToColl/histNonAmbTrackNumColls"), track.compatibleCollIds().size()); + continue; + } + } + bool isAmbiguous = (track.compatibleCollIds().size() > 1); if (isAmbiguous) { qaregistry.fill(HIST("TrackToColl/histAmbTrackNumColls"), track.compatibleCollIds().size()); - std::vector ambVtxZ{}; for (const auto& collIdx : track.compatibleCollIds()) { const auto& ambColl = collisions.rawIteratorAt(collIdx); @@ -3042,6 +3054,7 @@ struct DndetaMFTPbPb { qaregistry.fill(HIST("TrackToColl/histAmbTrackZvtxRMS"), computeRMS(ambVtxZ)); } } + float deltaX = -999.f; float deltaY = -999.f; float deltaZ = -999.f; @@ -3091,6 +3104,7 @@ struct DndetaMFTPbPb { ) { const auto& nRecoColls = collisions.size(); + registry.fill(HIST("Events/hNReAssocColls"), 1.f, nRecoColls); // Generated evets with >= 1 reco collisions if (nRecoColls > CintZero) { @@ -3119,8 +3133,6 @@ struct DndetaMFTPbPb { mapVtxYrec.emplace(collision.globalIndex(), collision.posY()); mapVtxZrec.emplace(collision.globalIndex(), collision.posZ()); mapMcCollIdPerRecColl.emplace(collision.globalIndex(), collision.mcCollisionId()); - } else { - continue; } } @@ -3138,9 +3150,11 @@ struct DndetaMFTPbPb { auto perCollisionASample = besttracks.sliceBy(perColU, collision.globalIndex()); for (auto const& atrack : perCollisionASample) { + registry.fill(HIST("Events/ReAssocMCStatus"), 1); if (!isBestTrackSelected(atrack)) { continue; } + registry.fill(HIST("Events/ReAssocMCStatus"), 2); auto itrack = atrack.template mfttrack_as(); if (!isTrackSelected(itrack)) { continue; @@ -3153,12 +3167,15 @@ struct DndetaMFTPbPb { if (!itrack.has_collision()) { continue; } + registry.fill(HIST("Events/ReAssocMCStatus"), 3); if (gConf.cfgRemoveReassigned) { if (itrack.collisionId() != atrack.bestCollisionId()) { continue; } + registry.fill(HIST("Events/ReAssocMCStatus"), 4); } if (itrack.has_mcParticle()) { + registry.fill(HIST("Events/ReAssocMCStatus"), 5); auto particle = itrack.template mcParticle_as(); auto collision = itrack.template collision_as(); auto mcCollision = particle.template mcCollision_as(); @@ -3167,6 +3184,8 @@ struct DndetaMFTPbPb { continue; } + registry.fill(HIST("Events/ReAssocMCStatus"), 6); + float deltaX = -999.f; float deltaY = -999.f; float deltaZ = -999.f; @@ -3193,17 +3212,48 @@ struct DndetaMFTPbPb { deltaY = vtxYbest - mcCollision.posY(); deltaZ = vtxZbest - mcCollision.posZ(); + const auto dcaXtruth(particle.vx() - particle.mcCollision().posX()); + const auto dcaYtruth(particle.vy() - particle.mcCollision().posY()); + const auto dcaZtruth(particle.vz() - particle.mcCollision().posZ()); + auto dcaXYtruth = std::sqrt(dcaXtruth * dcaXtruth + dcaYtruth * dcaYtruth); + if (itrack.collisionId() == atrack.bestCollisionId()) { // associated + registry.fill(HIST("Events/ReAssocMCStatus"), 7); if (collision.has_mcCollision() && mcCollIdRec == particle.mcCollisionId()) { - hReAssoc[0]->Fill(itrack.pt(), itrack.eta(), deltaX, deltaY, deltaZ); + registry.fill(HIST("Events/ReAssocMCStatus"), 8); + hReAssoc[0]->Fill(particle.pt(), particle.eta(), deltaX, deltaY, deltaZ); + if (!particle.isPhysicalPrimary()) { + hDCAMc[1]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } else { // Primaries + hDCAMc[0]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } } else { - hReAssoc[1]->Fill(itrack.pt(), itrack.eta(), deltaX, deltaY, deltaZ); + registry.fill(HIST("Events/ReAssocMCStatus"), 9); + hReAssoc[1]->Fill(particle.pt(), particle.eta(), deltaX, deltaY, deltaZ); + if (!particle.isPhysicalPrimary()) { + hDCAMc[3]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } else { // Primaries + hDCAMc[2]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } } } else { + registry.fill(HIST("Events/ReAssocMCStatus"), 10); if (collision.has_mcCollision() && mcCollIdRec == particle.mcCollisionId()) { - hReAssoc[2]->Fill(itrack.pt(), itrack.eta(), deltaX, deltaY, deltaZ); + registry.fill(HIST("Events/ReAssocMCStatus"), 11); + hReAssoc[2]->Fill(particle.pt(), particle.eta(), deltaX, deltaY, deltaZ); + if (!particle.isPhysicalPrimary()) { + hDCAMc[5]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } else { // Primaries + hDCAMc[4]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } } else { - hReAssoc[3]->Fill(itrack.pt(), itrack.eta(), deltaX, deltaY, deltaZ); + registry.fill(HIST("Events/ReAssocMCStatus"), 12); + hReAssoc[3]->Fill(particle.pt(), particle.eta(), deltaX, deltaY, deltaZ); + if (!particle.isPhysicalPrimary()) { + hDCAMc[7]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } else { // Primaries + hDCAMc[6]->Fill(particle.pt(), particle.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), dcaXYtruth, dcaZtruth); + } } } } @@ -3514,218 +3564,6 @@ struct DndetaMFTPbPb { PROCESS_SWITCH(DndetaMFTPbPb, processSecondariesMCCentFT0C, "Process secondaries checks (in FT0C centrality bins)", false); - template - void processDCAReassocMc(typename soa::Join const& collisions, - MC const& mcCollisions, - aod::McParticles const& /*particles*/, - BestTracksMC const& besttracks, - FiltMcMftTracks const& /*tracks*/ - ) - { - registry.fill(HIST("Events/hNGenRecCollsReassoc"), 1.f, collisions.size()); - registry.fill(HIST("Events/hNGenRecCollsReassoc"), 2.f, mcCollisions.size()); - - float cGen = -1; - if constexpr (has_reco_cent) { - float crecMin = 105.f; - for (const auto& collision : collisions) { - if (isGoodEvent(collision)) { - float c = getRecoCent(collision); - if (c < crecMin) { - crecMin = c; - } - } - } - if (cGen < 0) - cGen = crecMin; - } - float occGen = -1.; - for (const auto& collision : collisions) { - if (isGoodEvent(collision)) { - float o = getOccupancy(collision, eventCuts.occupancyEstimator); - if (o > occGen) { - occGen = o; - } - } - } - - if constexpr (has_reco_cent) { - registry.fill(HIST("Events/Centrality/EvtGenRecReassoc"), 1., cGen, occGen); - } else { - registry.fill(HIST("Events/EvtGenRecReassoc"), 1., occGen); - } - - for (const auto& collision : collisions) { - auto occ = getOccupancy(collision, eventCuts.occupancyEstimator); - float crec = getRecoCent(collision); - - if constexpr (has_reco_cent) { - registry.fill(HIST("Events/Centrality/EvtGenRecReassoc"), 2., crec, occ); - } else { - registry.fill(HIST("Events/EvtGenRecReassoc"), 2., occ); - } - - if (!isGoodEvent(collision)) { - continue; - } - - if constexpr (has_reco_cent) { - registry.fill(HIST("Events/Centrality/EvtGenRecReassoc"), 3., crec, occ); - } else { - registry.fill(HIST("Events/EvtGenRecReassoc"), 3., occ); - } - - if (!collision.has_mcCollision()) { - continue; - } - - auto perCollisionASample = besttracks.sliceBy(perColU, collision.globalIndex()); - for (auto const& atrack : perCollisionASample) { - if (!isBestTrackSelected(atrack)) { - continue; - } - auto itrack = atrack.template mfttrack_as(); - - if (!isTrackSelected(itrack)) { - continue; - } - float phi = itrack.phi(); - o2::math_utils::bringTo02Pi(phi); - if (phi < Czero || TwoPI < phi) { - continue; - } - - if (!itrack.has_collision()) { - continue; - } - if (gConf.cfgRemoveReassigned) { - if (itrack.collisionId() != atrack.bestCollisionId()) { - continue; - } - } - - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestRec"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - } else { - registry.fill(HIST("Tracks/THnDCAxyBestRec"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - } - - if (itrack.has_mcParticle()) { - auto particle = itrack.template mcParticle_as(); - if (!isChrgParticle(particle.pdgCode())) { - continue; - } - if (particle.eta() <= trackCuts.minEta || particle.eta() >= trackCuts.maxEta) { - continue; - } - if (gConf.cfgUseParticleSel && !isParticleSelected(particle)) { - continue; - } - - const auto dcaXtruth(particle.vx() - particle.mcCollision().posX()); - const auto dcaYtruth(particle.vy() - particle.mcCollision().posY()); - const auto dcaZtruth(particle.vz() - particle.mcCollision().posZ()); - auto dcaXYtruth = std::sqrt(dcaXtruth * dcaXtruth + dcaYtruth * dcaYtruth); - auto mcCollision = particle.template mcCollision_as(); - - if (eventCuts.useZDiffCut) { - if (std::abs(collision.posZ() - mcCollision.posZ()) > eventCuts.maxZvtxDiff) { - continue; - } - } - - if (collision.has_mcCollision() && collision.mcCollisionId() == particle.mcCollisionId()) { - if (!particle.isPhysicalPrimary()) { // Secondaries (weak decays and material) - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/BestGenSecDeltaX"), collision.posZ() - particle.mcCollision().posZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSec"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthSec"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); - } else { - registry.fill(HIST("Tracks/BestGenSecDeltaX"), collision.posZ() - particle.mcCollision().posZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenSec"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenTruthSec"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); - } - if (particle.getProcess() == TMCProcess::kPDecay) { // Particles from decay - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSecWeak"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - } else { - registry.fill(HIST("Tracks/THnDCAxyBestGenSecWeak"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - } - } else { // Particles from the material - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSecMat"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - } else { - registry.fill(HIST("Tracks/THnDCAxyBestGenSecMat"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - } - } - } else { // Primaries - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/BestGenPrimDeltaX"), collision.posZ() - particle.mcCollision().posZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); - } else { - registry.fill(HIST("Tracks/BestGenPrimDeltaX"), collision.posZ() - particle.mcCollision().posZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenTruthPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); - } - } - } else { // Wrong collision - if (!particle.isPhysicalPrimary()) { // Secondaries (weak decays and material) - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/BestGenSecWrongCollDeltaX"), collision.posZ() - particle.mcCollision().posZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); - } else { - registry.fill(HIST("Tracks/BestGenSecWrongCollDeltaX"), collision.posZ() - particle.mcCollision().posZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenTruthSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); - } - } else { // Primaries - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/BestGenPrimWrongCollDeltaX"), collision.posZ() - particle.mcCollision().posZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); - } else { - registry.fill(HIST("Tracks/BestGenPrimWrongCollDeltaX"), collision.posZ() - particle.mcCollision().posZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - registry.fill(HIST("Tracks/THnDCAxyBestGenTruthPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); - } - } - } - } else { - LOGP(debug, "No MC particle for ambiguous itrack, skip..."); - if constexpr (has_reco_cent) { - registry.fill(HIST("Tracks/Centrality/THnDCAxyBestRecFake"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); - } else { - registry.fill(HIST("Tracks/THnDCAxyBestRecFake"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); - } - } - } - } - } - - void processDCAReassocMcInclusive(soa::Join const& collisions, - aod::McCollisions const& mccollisions, - aod::McParticles const& particles, - BestTracksMC const& besttracks, - FiltMcMftTracks const& tracks) - { - processDCAReassocMc(collisions, mccollisions, particles, besttracks, tracks); - } - - PROCESS_SWITCH(DndetaMFTPbPb, processDCAReassocMcInclusive, "Process MC DCA checks using re-association information based on BestCollisionsFwd3d table (Inclusive)", false); - - void processDCAReassocMcCentFT0C(soa::Join const& collisions, - aod::McCollisions const& mccollisions, - aod::McParticles const& particles, - BestTracksMC const& besttracks, - FiltMcMftTracks const& tracks) - { - processDCAReassocMc(collisions, mccollisions, particles, besttracks, tracks); - } - - PROCESS_SWITCH(DndetaMFTPbPb, processDCAReassocMcCentFT0C, "Process MC DCA checks using re-association information based on BestCollisionsFwd3d table (in FT0C centrality bins)", false); - template void processCorrelationwBestTracks(typename C::iterator const& collision, FiltMftTracks const& /*tracks*/, soa::SmallGroups const& besttracks) { @@ -3876,8 +3714,6 @@ struct DndetaMFTPbPb { maxNcontributors = collision.numContrib(); bestCollIndex = collision.globalIndex(); crec = getRecoCent(collision); - } else { - continue; } } @@ -4085,8 +3921,6 @@ struct DndetaMFTPbPb { if (maxNcontributors < collision.numContrib()) { maxNcontributors = collision.numContrib(); centrality = getRecoCent(collision); - } else { - continue; } gtZeroColl = true; } diff --git a/PWGMM/Mult/Tasks/mftReassociationValidation.cxx b/PWGMM/Mult/Tasks/mftReassociationValidation.cxx index 7964859f289..2afc211b4b3 100644 --- a/PWGMM/Mult/Tasks/mftReassociationValidation.cxx +++ b/PWGMM/Mult/Tasks/mftReassociationValidation.cxx @@ -176,6 +176,13 @@ enum MftNot3dReassociatedAndMatchedToTrueCollisionStep { NMftNot3dReassociatedAndMatchedToTrueCollisionSteps }; +enum MftIsTrueCollisionAmongCompatibleCollisionsStep { + AllWronglyAssociatedTracks = 0, + IsTrueCollisionAmongCompatibleCollisions, + IsNotTrueCollisionAmongCompatibleCollisions, + NMftIsTrueCollisionAmongCompatibleCollisionsSteps +}; + enum MftTrackSelectionStep { NoSelection = 0, Eta, @@ -405,7 +412,7 @@ struct MftReassociationValidation { hZVtxDiffNot3dReassociatedTracks[MatchedToTrueCollisionStep::AllTracks] = registry.add("MC/hZVtxDiffNot3dReassociatedTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {configAxis.axisPt, configAxis.axisEta, configAxis.axisDcaX, configAxis.axisDcaY, configAxis.axisDcaZ}); hZVtxDiffNot3dReassociatedTracks[MatchedToTrueCollisionStep::IsNotMatchedToTrueCollision] = registry.add("MC/hZVtxDiffNot3dReassociatedTracksNotMatchedToTrueCollision", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {configAxis.axisPt, configAxis.axisEta, configAxis.axisDcaX, configAxis.axisDcaY, configAxis.axisDcaZ}); - hZVtxDiffNot3dReassociatedTracks[MatchedToTrueCollisionStep::IsMatchedToTrueCollision] = registry.add("MC/hZVtxDhZVtxDiffNot3dReassociatedTracksMatchedToTrueCollisioniffAmbiguousTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {configAxis.axisPt, configAxis.axisEta, configAxis.axisDcaX, configAxis.axisDcaY, configAxis.axisDcaZ}); + hZVtxDiffNot3dReassociatedTracks[MatchedToTrueCollisionStep::IsMatchedToTrueCollision] = registry.add("MC/hZVtxDiffNot3dReassociatedTracksMatchedToTrueCollision", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{X}_{vtx}^{reco}#minus#it{X}_{vtx}^{gen} (cm);#it{Y}_{vtx}^{reco}#minus#it{Y}_{vtx}^{gen} (cm);#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {configAxis.axisPt, configAxis.axisEta, configAxis.axisDcaX, configAxis.axisDcaY, configAxis.axisDcaZ}); registry.add("MC/hIsAmbiguousTrackMatchedToTrueCollision", "hIsAmbiguousTrackMatchedToTrueCollision", {HistType::kTH1D, {{MftAmbiguousAndMatchedToTrueCollisionStep::NMftAmbiguousAndMatchedToTrueCollisionSteps, -0.5, +MftAmbiguousAndMatchedToTrueCollisionStep::NMftAmbiguousAndMatchedToTrueCollisionSteps - 0.5}}}); std::string labelsMftAmbiguousAndMatchedToTrueCollisionStep[MftAmbiguousAndMatchedToTrueCollisionStep::NMftAmbiguousAndMatchedToTrueCollisionSteps]; @@ -472,6 +479,26 @@ struct MftReassociationValidation { for (int iBin = 0; iBin < MftNot3dReassociatedAndMatchedToTrueCollisionStep::NMftNot3dReassociatedAndMatchedToTrueCollisionSteps; iBin++) { registry.get(HIST("MC/IsNot3dReassociatedAndMatchedToTrueCollision"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMftNot3dReassociatedAndMatchedToTrueCollisionStep[iBin].data()); } + + registry.add("MC/hIsTrueCollisionAmongCompatibleCollisions", "IsTrueCollisionAmongCompatibleCollisions", {HistType::kTH1D, {{MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps, -0.5, +MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps - 0.5}}}); + registry.add("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi", "hIsTrueCollisionAmongCompatibleCollisionsNonAmbi", {HistType::kTH1D, {{MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps, -0.5, +MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps - 0.5}}}); + registry.add("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated", "hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated", {HistType::kTH1D, {{MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps, -0.5, +MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps - 0.5}}}); + registry.add("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated", "hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated", {HistType::kTH1D, {{MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps, -0.5, +MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps - 0.5}}}); + std::string labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps]; + labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks] = "number of wrongly associated tracks"; + labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions] = "number of MFT tracks with True Coll. among Compatible"; + labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions] = "number of MFT tracks WITHOUT True Coll. among Compatible"; + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"))->SetMinimum(0); + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"))->SetMinimum(0); + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"))->SetMinimum(0); + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"))->SetMinimum(0); + + for (int iBin = 0; iBin < MftIsTrueCollisionAmongCompatibleCollisionsStep::NMftIsTrueCollisionAmongCompatibleCollisionsSteps; iBin++) { + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[iBin].data()); + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[iBin].data()); + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[iBin].data()); + registry.get(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMftIsTrueCollisionAmongCompatibleCollisionsStep[iBin].data()); + } } // ========================= @@ -607,6 +634,39 @@ struct MftReassociationValidation { return grpo->getNominalL3Field(); } + template + bool isTrueCollisionAmongCompatibleCollisions(TTrack track) + { + + auto const& compatibleIds = track.compatibleCollIds(); + + // For this track, check if *any* reco collision that corresponds to its TRUE MC collision + // is present among the compatible collisions. + bool recoOfTrueInCompatible = false; + if (track.ambDegree() != 0) { + const int mcTrueCollisionId = track.mcParticle().mcCollisionId(); + // Fast membership test using compatibleCollIds() if available. + // If compatibleIds is empty, it means the table is missing or no compatible collisions were stored. + if (!compatibleIds.empty()) { + for (auto const& id : compatibleIds) { + + auto iterator = recoMcCollisionId.find(id); + + if (iterator != recoMcCollisionId.end()) { + if (iterator->second == mcTrueCollisionId) { + + recoOfTrueInCompatible = true; + return recoOfTrueInCompatible; + } + } else { + return recoOfTrueInCompatible; + } + } + } + } + return recoOfTrueInCompatible; + } + // ========================= // Cuts with functions // ========================= @@ -790,6 +850,11 @@ struct MftReassociationValidation { void processCreateLookupTable(FilteredCollisionsWSelMultMcLabels const& collisions) { + recoVtxX.clear(); + recoVtxY.clear(); + recoVtxZ.clear(); + recoMcCollisionId.clear(); + recoVtxX.reserve(collisions.size()); recoVtxY.reserve(collisions.size()); recoVtxZ.reserve(collisions.size()); @@ -806,7 +871,7 @@ struct MftReassociationValidation { void processMcReassociated2d(FilteredCollisionsWSelMultMcLabels::iterator const& collision, FilteredMftTracksWCollsMcLabels const& /*mftTracks*/, - soa::SmallGroups> const& reassociated2dMftTracks, + soa::SmallGroups> const& reassociated2dMftTracks, aod::McCollisions const& /*mcCollisions*/, aod::McParticles const& /*particles*/) { @@ -852,47 +917,59 @@ struct MftReassociationValidation { float reassociatedDeltaY = -999.f; float reassociatedDeltaZ = -999.f; auto collision = templatedTrack.collision_as(); - // auto mcCollision = particle.mcCollision_as(); - // deltaZ = collision.posZ() - mcCollision.posZ(); auto xPosTrue = reassociated2dMftTrack.mcParticle().mcCollision().posX(); auto yPosTrue = reassociated2dMftTrack.mcParticle().mcCollision().posY(); auto zPosTrue = reassociated2dMftTrack.mcParticle().mcCollision().posZ(); - const int bestRecoCol = reassociated2dMftTrack.bestCollisionId(); - // if (bestRecoCol < 0) { - // // no associated reco collision -> skip or count separately - // continue; - // } + const int bestRecoColl = reassociated2dMftTrack.bestCollisionId(); + const int originalRecoColl = templatedTrack.collisionId(); + + auto iteratorOriginalCollVtxX = recoVtxX.find(originalRecoColl); + auto iteratorOriginalCollVtxY = recoVtxY.find(originalRecoColl); + auto iteratorOriginalCollVtxZ = recoVtxZ.find(originalRecoColl); + auto iteratorBestCollVtxX = recoVtxX.find(bestRecoColl); + auto iteratorBestCollVtxY = recoVtxY.find(bestRecoColl); + auto iteratorBestCollVtxZ = recoVtxZ.find(bestRecoColl); + auto iteratorRecoMcCollisionId = recoMcCollisionId.find(bestRecoColl); - auto iteratorRecoVtxX = recoVtxX.find(bestRecoCol); - auto iteratorRecoVtxY = recoVtxY.find(bestRecoCol); - auto iteratorRecoVtxZ = recoVtxZ.find(bestRecoCol); - auto iteratorRecoMcCollisionId = recoMcCollisionId.find(bestRecoCol); - if (iteratorRecoVtxX == recoVtxX.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately + if (iteratorOriginalCollVtxX == recoVtxX.end()) { + // bestRecoColl not found in reco collisions map -> skip or count separately continue; } - if (iteratorRecoVtxY == recoVtxY.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately + if (iteratorOriginalCollVtxY == recoVtxY.end()) { continue; } - if (iteratorRecoVtxZ == recoVtxZ.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately + if (iteratorOriginalCollVtxZ == recoVtxZ.end()) { + continue; + } + if (iteratorBestCollVtxX == recoVtxX.end()) { + continue; + } + if (iteratorBestCollVtxY == recoVtxY.end()) { + continue; + } + if (iteratorBestCollVtxZ == recoVtxZ.end()) { continue; } if (iteratorRecoMcCollisionId == recoMcCollisionId.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately continue; } - const float xReco = iteratorRecoVtxX->second; - const float yReco = iteratorRecoVtxY->second; - const float zReco = iteratorRecoVtxZ->second; + const float xPosOriginalColl = iteratorOriginalCollVtxX->second; + const float yPosOriginalColl = iteratorOriginalCollVtxY->second; + const float zPosOriginalColl = iteratorOriginalCollVtxZ->second; + const float xPosBestColl = iteratorBestCollVtxX->second; + const float yPosBestColl = iteratorBestCollVtxY->second; + const float zPosBestColl = iteratorBestCollVtxZ->second; const int mcCollisionIdReco = iteratorRecoMcCollisionId->second; - reassociatedDeltaX = xReco - xPosTrue; - reassociatedDeltaY = yReco - yPosTrue; - reassociatedDeltaZ = zReco - zPosTrue; + deltaX = xPosOriginalColl - xPosTrue; + deltaY = yPosOriginalColl - yPosTrue; + deltaZ = zPosOriginalColl - zPosTrue; + + reassociatedDeltaX = xPosBestColl - xPosTrue; + reassociatedDeltaY = yPosBestColl - yPosTrue; + reassociatedDeltaZ = zPosBestColl - zPosTrue; if (reassociated2dMftTrack.ambDegree() > 1) { // AMBIGUOUS TRACKS registry.fill(HIST("MC/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::NumberOfAmbiguousTracks); @@ -920,6 +997,16 @@ struct MftReassociationValidation { } else { registry.fill(HIST("MC/IsNot2dReassociatedAndMatchedToTrueCollision"), MftNot2dReassociatedAndMatchedToTrueCollisionStep::IsNot2dReassociatedAndNotMatchedToTrueCollision); hZVtxDiffNot2dReassociatedTracks[MatchedToTrueCollisionStep::IsNotMatchedToTrueCollision]->Fill(templatedTrack.pt(), templatedTrack.eta(), reassociatedDeltaX, reassociatedDeltaY, reassociatedDeltaZ); + + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + if (isTrueCollisionAmongCompatibleCollisions(reassociated2dMftTrack)) { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + } else { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + } } } else { // IS 2D REASSOCIATED @@ -935,6 +1022,16 @@ struct MftReassociationValidation { } else { registry.fill(HIST("MC/Is2dReassociatedAndMatchedToTrueCollision"), Mft2dReassociatedAndMatchedToTrueCollisionStep::Is2dReassociatedAndNotMatchedToTrueCollision); hZVtxDiff2dReassociatedTracks[MatchedToTrueCollisionStep::IsNotMatchedToTrueCollision]->Fill(templatedTrack.pt(), templatedTrack.eta(), deltaX, deltaY, deltaZ); + + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + if (isTrueCollisionAmongCompatibleCollisions(reassociated2dMftTrack)) { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + } else { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + } } } @@ -950,6 +1047,16 @@ struct MftReassociationValidation { } else { registry.fill(HIST("MC/hIsNonAmbiguousTrackMatchedToTrueCollision"), MftNonAmbiguousAndMatchedToTrueCollisionStep::IsNonAmbiguousAndNotMatchedToTrueCollision); hZVtxDiffNonAmbiguousTracks[MatchedToTrueCollisionStep::IsNotMatchedToTrueCollision]->Fill(templatedTrack.pt(), templatedTrack.eta(), deltaX, deltaY, deltaZ); + + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + if (isTrueCollisionAmongCompatibleCollisions(reassociated2dMftTrack)) { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + } else { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + } } } // end of if non ambi @@ -962,7 +1069,7 @@ struct MftReassociationValidation { void processMcReassociated3d(FilteredCollisionsWSelMultMcLabels::iterator const& collision, FilteredMftTracksWCollsMcLabels const& /*mftTracks*/, - soa::SmallGroups> const& reassociated3dMftTracks, + soa::SmallGroups> const& reassociated3dMftTracks, aod::McCollisions const& /*mcCollisions*/, aod::McParticles const& /*particles*/) { @@ -1014,41 +1121,59 @@ struct MftReassociationValidation { auto yPosTrue = reassociated3dMftTrack.mcParticle().mcCollision().posY(); auto zPosTrue = reassociated3dMftTrack.mcParticle().mcCollision().posZ(); - const int bestRecoCol = reassociated3dMftTrack.bestCollisionId(); - // if (bestRecoCol < 0) { + const int bestRecoColl = reassociated3dMftTrack.bestCollisionId(); + const int originalRecoColl = templatedTrack.collisionId(); + // if (bestRecoColl < 0) { // // no associated reco collision -> skip or count separately // continue; // } - auto iteratorRecoVtxX = recoVtxX.find(bestRecoCol); - auto iteratorRecoVtxY = recoVtxY.find(bestRecoCol); - auto iteratorRecoVtxZ = recoVtxZ.find(bestRecoCol); - auto iteratorRecoMcCollisionId = recoMcCollisionId.find(bestRecoCol); - if (iteratorRecoVtxX == recoVtxX.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately + auto iteratorOriginalCollVtxX = recoVtxX.find(originalRecoColl); + auto iteratorOriginalCollVtxY = recoVtxY.find(originalRecoColl); + auto iteratorOriginalCollVtxZ = recoVtxZ.find(originalRecoColl); + auto iteratorBestCollVtxX = recoVtxX.find(bestRecoColl); + auto iteratorBestCollVtxY = recoVtxY.find(bestRecoColl); + auto iteratorBestCollVtxZ = recoVtxZ.find(bestRecoColl); + auto iteratorRecoMcCollisionId = recoMcCollisionId.find(bestRecoColl); + + if (iteratorOriginalCollVtxX == recoVtxX.end()) { + // bestRecoColl not found in reco collisions map -> skip or count separately continue; } - if (iteratorRecoVtxY == recoVtxY.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately + if (iteratorOriginalCollVtxY == recoVtxY.end()) { continue; } - if (iteratorRecoVtxZ == recoVtxZ.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately + if (iteratorOriginalCollVtxZ == recoVtxZ.end()) { + continue; + } + if (iteratorBestCollVtxX == recoVtxX.end()) { + continue; + } + if (iteratorBestCollVtxY == recoVtxY.end()) { + continue; + } + if (iteratorBestCollVtxZ == recoVtxZ.end()) { continue; } if (iteratorRecoMcCollisionId == recoMcCollisionId.end()) { - // bestRecoCol not found in reco collisions map -> skip or count separately continue; } - const float xReco = iteratorRecoVtxX->second; - const float yReco = iteratorRecoVtxY->second; - const float zReco = iteratorRecoVtxZ->second; + const float xPosOriginalColl = iteratorOriginalCollVtxX->second; + const float yPosOriginalColl = iteratorOriginalCollVtxY->second; + const float zPosOriginalColl = iteratorOriginalCollVtxZ->second; + const float xPosBestColl = iteratorBestCollVtxX->second; + const float yPosBestColl = iteratorBestCollVtxY->second; + const float zPosBestColl = iteratorBestCollVtxZ->second; const int mcCollisionIdReco = iteratorRecoMcCollisionId->second; - reassociatedDeltaX = xReco - xPosTrue; - reassociatedDeltaY = yReco - yPosTrue; - reassociatedDeltaZ = zReco - zPosTrue; + deltaX = xPosOriginalColl - xPosTrue; + deltaY = yPosOriginalColl - yPosTrue; + deltaZ = zPosOriginalColl - zPosTrue; + + reassociatedDeltaX = xPosBestColl - xPosTrue; + reassociatedDeltaY = yPosBestColl - yPosTrue; + reassociatedDeltaZ = zPosBestColl - zPosTrue; if (reassociated3dMftTrack.ambDegree() > 1) { // AMBIGUOUS TRACKS registry.fill(HIST("MC/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::NumberOfAmbiguousTracks); @@ -1076,6 +1201,16 @@ struct MftReassociationValidation { } else { registry.fill(HIST("MC/IsNot3dReassociatedAndMatchedToTrueCollision"), MftNot3dReassociatedAndMatchedToTrueCollisionStep::IsNot3dReassociatedAndNotMatchedToTrueCollision); hZVtxDiffNot3dReassociatedTracks[MatchedToTrueCollisionStep::IsNotMatchedToTrueCollision]->Fill(templatedTrack.pt(), templatedTrack.eta(), reassociatedDeltaX, reassociatedDeltaY, reassociatedDeltaZ); + + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + if (isTrueCollisionAmongCompatibleCollisions(reassociated3dMftTrack)) { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + } else { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaNotReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + } } } else { // IS 3D REASSOCIATED @@ -1091,6 +1226,16 @@ struct MftReassociationValidation { } else { registry.fill(HIST("MC/Is3dReassociatedAndMatchedToTrueCollision"), Mft3dReassociatedAndMatchedToTrueCollisionStep::Is3dReassociatedAndNotMatchedToTrueCollision); hZVtxDiff3dReassociatedTracks[MatchedToTrueCollisionStep::IsNotMatchedToTrueCollision]->Fill(templatedTrack.pt(), templatedTrack.eta(), deltaX, deltaY, deltaZ); + + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + if (isTrueCollisionAmongCompatibleCollisions(reassociated3dMftTrack)) { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + } else { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsDcaReassociated"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + } } } @@ -1106,6 +1251,16 @@ struct MftReassociationValidation { } else { registry.fill(HIST("MC/hIsNonAmbiguousTrackMatchedToTrueCollision"), MftNonAmbiguousAndMatchedToTrueCollisionStep::IsNonAmbiguousAndNotMatchedToTrueCollision); hZVtxDiffNonAmbiguousTracks[MatchedToTrueCollisionStep::IsNotMatchedToTrueCollision]->Fill(templatedTrack.pt(), templatedTrack.eta(), deltaX, deltaY, deltaZ); + + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"), MftIsTrueCollisionAmongCompatibleCollisionsStep::AllWronglyAssociatedTracks); + if (isTrueCollisionAmongCompatibleCollisions(reassociated3dMftTrack)) { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsTrueCollisionAmongCompatibleCollisions); + } else { + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisions"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + registry.fill(HIST("MC/hIsTrueCollisionAmongCompatibleCollisionsNonAmbi"), MftIsTrueCollisionAmongCompatibleCollisionsStep::IsNotTrueCollisionAmongCompatibleCollisions); + } } } // end of if non ambi diff --git a/PWGMM/UE/Tasks/uecharged.cxx b/PWGMM/UE/Tasks/uecharged.cxx index 56bd369a290..9af0eb3cc2a 100644 --- a/PWGMM/UE/Tasks/uecharged.cxx +++ b/PWGMM/UE/Tasks/uecharged.cxx @@ -13,7 +13,7 @@ /// \file uecharged.cxx /// \brief Underlying event analysis task /// \since November 2021 -/// \last update: January 2026 +/// \last update: March 2026 #include "PWGLF/DataModel/mcCentrality.h" #include "PWGLF/Utils/collisionCuts.h" @@ -50,58 +50,35 @@ using FT0s = aod::FT0s; struct ueCharged { - TrackSelection myTrackSelectionPrim() - { - TrackSelection selectedTracks; - selectedTracks.SetPtRange(0.1f, 1e10f); - selectedTracks.SetEtaRange(-0.8f, 0.8f); - selectedTracks.SetRequireITSRefit(true); - selectedTracks.SetRequireTPCRefit(true); - selectedTracks.SetRequireGoldenChi2(true); - selectedTracks.SetMinNCrossedRowsTPC(70); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); - selectedTracks.SetMaxChi2PerClusterTPC(4.f); - selectedTracks.SetRequireHitsInITSLayers(1, {0, 1, 2}); // Run3ITSibAny - selectedTracks.SetMaxChi2PerClusterITS(36.f); - selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / std::pow(pt, 1.1f); }); - selectedTracks.SetMaxDcaZ(0.1f); - return selectedTracks; - } - - TrackSelection myTrackSelectionOpenDCA() - { - TrackSelection selectedTracks; - selectedTracks.SetPtRange(0.1f, 1e10f); - selectedTracks.SetEtaRange(-0.8f, 0.8f); - selectedTracks.SetRequireITSRefit(true); - selectedTracks.SetRequireTPCRefit(true); - selectedTracks.SetRequireGoldenChi2(true); - selectedTracks.SetMinNCrossedRowsTPC(70); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); - selectedTracks.SetMaxChi2PerClusterTPC(4.f); - selectedTracks.SetRequireHitsInITSLayers(1, {0, 1, 2}); // Run3ITSibAny - selectedTracks.SetMaxChi2PerClusterITS(36.f); - selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); }); - selectedTracks.SetMaxDcaZ(0.1f); - return selectedTracks; - } - - TrackSelection mySelectionPrim; - TrackSelection mySelectionOpenDCA; - - Service pdg; - // Configurable for event selection Configurable isRun3{"isRun3", true, "is Run3 dataset"}; - Configurable pileuprejection{"pileuprejection", true, "Pileup rejection"}; - Configurable goodzvertex{"goodzvertex", true, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference"}; - Configurable sel8{"sel8", true, "Apply the sel8 event selection"}; - Configurable removeITSROFBorder{"removeITSROFBorder", false, "Remove ITS Read-Out Frame border and only apply kIsTriggerTVX & kNoTimeFrameBorder (recommended for MC)"}; - Configurable cfgINELCut{"cfgINELCut", 0, "INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1"}; + Configurable pileuprejection{"event_pileuprejection", true, "Pileup rejection"}; + Configurable goodzvertex{"event_goodzvertex", true, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference"}; + Configurable sel8{"event_sel8", true, "Apply the sel8 event selection"}; + Configurable removeITSROFBorder{"event_removeITSROFBorder", false, "Remove ITS Read-Out Frame border and only apply kIsTriggerTVX & kNoTimeFrameBorder (recommended for MC)"}; + Configurable cfgINELCut{"event_cfgINELCut", 0, "INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1"}; Configurable analyzeEvandTracksel{"analyzeEvandTracksel", true, "Analyze the event and track selection"}; - // acceptance cuts - Configurable cfgTrkEtaCut{"cfgTrkEtaCut", 0.8f, "Eta range for tracks"}; + + // Track selection configurables + TrackSelection myTrkSel; Configurable cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.15f, "Minimum constituent pT"}; + Configurable isCustomTracks{"trkcfg_isCustomTracks", true, "Use custom track cuts"}; + Configurable setITSreq{"trkcfg_setITSreq", 0, "0 = Run3ITSibAny, 1 = Run3ITSallAny, 2 = Run3ITSall7Layers, 3 = Run3ITSibTwo"}; + Configurable minPt{"trkcfg_minPt", 0.1f, "Set minimum pT of tracks"}; + Configurable maxPt{"trkcfg_maxPt", 1e10f, "Set maximum pT of tracks"}; + Configurable requireEta{"trkcfg_requireEta", 0.8f, "Set eta range of tracks"}; + Configurable requireITSRefit{"trkcfg_requireITSRefit", true, "Additional cut on the ITS requirement"}; + Configurable requireTPCRefit{"trkcfg_requireTPCRefit", true, "Additional cut on the TPC requirement"}; + Configurable requireGoldenChi2{"trkcfg_requireGoldenChi2", true, "Additional cut on the GoldenChi2"}; + Configurable maxChi2PerClusterTPC{"trkcfg_maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable maxChi2PerClusterITS{"trkcfg_maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; + // Configurable minITSnClusters{"trkcfg_minITSnClusters", 5, "minimum number of found ITS clusters"}; + Configurable minNCrossedRowsTPC{"trkcfg_minNCrossedRowsTPC", 70.f, "Additional cut on the minimum number of crossed rows in the TPC"}; + Configurable minNCrossedRowsOverFindableClustersTPC{"trkcfg_minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable maxDcaXYFactor{"trkcfg_maxDcaXYFactor", 1.f, "Multiplicative factor on the maximum value of the DCA xy"}; + Configurable maxDcaZ{"trkcfg_maxDcaZ", 0.1f, "Additional cut on the maximum value of the DCA z"}; + + Service pdg; // Data table definitions using ColDataTable = soa::Join; @@ -152,6 +129,24 @@ struct ueCharged { void init(InitContext const&) { + if (isCustomTracks.value) { + myTrkSel = getGlobalTrackSelectionRun3ITSMatch(setITSreq.value); + myTrkSel.SetPtRange(minPt.value, maxPt.value); + myTrkSel.SetEtaRange(-requireEta.value, requireEta.value); + myTrkSel.SetRequireITSRefit(requireITSRefit.value); + myTrkSel.SetRequireTPCRefit(requireTPCRefit.value); + myTrkSel.SetRequireGoldenChi2(requireGoldenChi2.value); + myTrkSel.SetMaxChi2PerClusterTPC(maxChi2PerClusterTPC.value); + myTrkSel.SetMaxChi2PerClusterITS(maxChi2PerClusterITS.value); + // myTrkSel.SetMinNClustersITS(minITSnClusters.value); + myTrkSel.SetMinNCrossedRowsTPC(minNCrossedRowsTPC.value); + myTrkSel.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC.value); + // myTrkSel.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); }); + myTrkSel.SetMaxDcaXYPtDep([](float /*pt*/) { return 10000.f; }); + myTrkSel.SetMaxDcaZ(maxDcaZ.value); + myTrkSel.print(); + } + ConfigurableAxis ptBinningt{"ptBinningt", {0, 0.15, 0.50, 1.00, 1.50, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, @@ -170,12 +165,13 @@ struct ueCharged { AxisSpec ptAxis = {ptBinning, "#it{p}_{T}^{assoc} (GeV/#it{c})"}; fEff.setObject(new TF1("fpara", - "(x<0.3)*((0.402353)+x*(1.90824)+x*x*(-3.37295)) +" - "(x>=0.3&&x<1.8)*((0.603846)+(0.30189)*x+(-0.240649)*" - "x*x+(0.0635382)*x*x*x) +" - "(x>=1.8&&x<14.)*((0.75982)+(-0.0241023)*x+" - "(0.00560107)*x*x+(-0.00048451)*x*x*x+" - "(1.43868e-05)*x*x*x*x)+(x>=14)*((0.755339)+(-0.000986326)*x)", + "(x<0.33)*((0.384347)+x*(1.77554)+x*x*(-2.9172)) +" + "(x>=0.33&&x<1.2)*((0.58547)+(0.293843)*x+(-0.293957)*" + "x*x+(0.109855)*x*x*x) +" + "(x>=1.2&&x<5.6)*((0.581232)+(0.205847)*x+" + "(-0.12133)*x*x+(0.0347906)*x*x*x+" + "(-0.0048334)*x*x*x*x+(0.000261644)*x*x*x*x*x)+(x>=5.6)*((0.711869)+(0.00364573)*x" + "+(-0.00019009)*x*x+(3.09894e-06)*x*x*x+(-1.81785e-08)*x*x*x*x)", 0., 1e5)); if (doprocessMC || doprocessMCTrue) { @@ -325,16 +321,41 @@ struct ueCharged { if (!track.has_collision()) { return false; } - if (!mySelectionPrim.IsSelected(track)) { + if (track.pt() < cfgTrkLowPtCut) { return false; } - if (std::abs(track.eta()) >= cfgTrkEtaCut) { - return false; + if (isCustomTracks.value) { + for (int i = 0; i < static_cast(TrackSelection::TrackCuts::kNCuts); i++) { + if (i == static_cast(TrackSelection::TrackCuts::kDCAxy)) { + continue; + } + if (!myTrkSel.IsSelected(track, static_cast(i))) { + return false; + } + } + return (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / std::pow(track.pt(), 1.1f)))); } - if (track.pt() < cfgTrkLowPtCut) { - return false; + return track.isGlobalTrack(); + } + + template + bool isDCAxyWoCut(T const& track) // function to skip DCA track selections + { + if (isCustomTracks.value) { + for (int i = 0; i < static_cast(TrackSelection::TrackCuts::kNCuts); i++) { + if (i == static_cast(TrackSelection::TrackCuts::kDCAxy)) { + continue; + } + if (i == static_cast(TrackSelection::TrackCuts::kDCAz)) { + continue; + } + if (!myTrkSel.IsSelected(track, static_cast(i))) { + return false; + } + } + return true; } - return true; + return track.isGlobalTrackWoDCA(); } template @@ -350,7 +371,7 @@ struct ueCharged { if (!pdgParticle || pdgParticle->Charge() == 0.) { return false; } - if (std::abs(particle.eta()) >= cfgTrkEtaCut) { + if (std::abs(particle.eta()) >= requireEta) { return false; } if (particle.pt() < cfgTrkLowPtCut) { @@ -508,7 +529,7 @@ struct ueCharged { std::vector indexArray; for (const auto& track : tracks) { - if (mySelectionOpenDCA.IsSelected(track)) + if (isDCAxyWoCut(track)) ue.fill(HIST("hPTVsDCAData"), track.pt(), track.dcaXY()); if (isTrackSelected(track)) { @@ -667,6 +688,10 @@ struct ueCharged { if (!foundRec) return; + if (analyzeEvandTracksel) { + analyzeEventAndTrackSelection(chosenRec, RecTracks.sliceBy(perCollision, chosenRecGlobalIndex)); + } + // compute truth-level leading particle and truth-region observables double flPtTrue = 0.; double flPhiTrue = 0.; @@ -762,7 +787,7 @@ struct ueCharged { if (!pdgParticle || pdgParticle->Charge() == 0.) { continue; } - if (std::abs(particle.eta()) >= cfgTrkEtaCut) { + if (std::abs(particle.eta()) >= requireEta) { continue; } @@ -832,7 +857,7 @@ struct ueCharged { if (track.collisionId() != chosenRecGlobalIndex) continue; - if (mySelectionOpenDCA.IsSelected(track)) + if (isDCAxyWoCut(track)) ue.fill(HIST("hPTVsDCAData"), track.pt(), track.dcaXY()); if (track.has_mcParticle()) { @@ -843,20 +868,20 @@ struct ueCharged { if (isTrackSelected(track)) ue.fill(HIST("hPtOut"), track.pt()); - if (mySelectionOpenDCA.IsSelected(track)) + if (isDCAxyWoCut(track)) ue.fill(HIST("hPtDCAall"), track.pt(), track.dcaXY()); if (particle.isPhysicalPrimary() && particle.producedByGenerator()) { // primary particles if (isTrackSelected(track) && isParticleSelected(particle)) { // TODO check if this condition ue.fill(HIST("hPtOutPrim"), particle.pt()); } - if (mySelectionOpenDCA.IsSelected(track)) { + if (isDCAxyWoCut(track)) { ue.fill(HIST("hPtDCAPrimary"), track.pt(), track.dcaXY()); } } else { // Secondaries (weak decays and material) if (isTrackSelected(track)) ue.fill(HIST("hPtOutSec"), track.pt()); - if (mySelectionOpenDCA.IsSelected(track)) { + if (isDCAxyWoCut(track)) { if (particle.getProcess() == 4) ue.fill(HIST("hPtDCAWeak"), track.pt(), track.dcaXY()); else @@ -996,7 +1021,7 @@ struct ueCharged { auto pdgParticle = pdg->GetParticle(particle.pdgCode()); if (!pdgParticle || pdgParticle->Charge() == 0.) continue; - if (std::abs(particle.eta()) >= cfgTrkEtaCut) + if (std::abs(particle.eta()) >= requireEta) continue; multTrue++; if (particle.pt() < cfgTrkLowPtCut) @@ -1145,7 +1170,7 @@ struct ueCharged { tracks_before++; } - if (mySelectionPrim.IsSelected(track)) { + if (isTrackSelected(track)) { if (track.hasITS() && track.hasTPC()) { ue.fill(HIST("postselection_track/ITS/itsNCls"), track.itsNCls()); ue.fill(HIST("postselection_track/ITS/itsChi2NCl"), track.itsChi2NCl()); diff --git a/PWGUD/DataModel/TauThreeProngEventTables.h b/PWGUD/DataModel/TauThreeProngEventTables.h index b670e8b7f69..61cc184cbdb 100644 --- a/PWGUD/DataModel/TauThreeProngEventTables.h +++ b/PWGUD/DataModel/TauThreeProngEventTables.h @@ -84,7 +84,7 @@ DECLARE_SOA_COLUMN(TrkTOFnSigmaMu, trkTOFnSigmaMu, float[6]); DECLARE_SOA_COLUMN(TrkTOFchi2, trkTOFchi2, float[6]); // truth event DECLARE_SOA_COLUMN(TrueChannel, trueChannel, int); -DECLARE_SOA_COLUMN(TrueHasRecoColl, trueHasRecoColl, bool); +// DECLARE_SOA_COLUMN(TrueHasRecoColl, trueHasRecoColl, bool); // DECLARE_SOA_COLUMN(TruePosX, truePosX, float); // DECLARE_SOA_COLUMN(TruePosY, truePosY, float); DECLARE_SOA_COLUMN(TruePosZ, truePosZ, float); @@ -145,7 +145,7 @@ DECLARE_SOA_TABLE(TrueTauFourTracks, "AOD", "TRUETAU", tautree::TrkTOFbeta, tautree::TrkTOFnSigmaEl, tautree::TrkTOFnSigmaPi, tautree::TrkTOFnSigmaKa, tautree::TrkTOFnSigmaPr, tautree::TrkTOFnSigmaMu, tautree::TrkTOFchi2, tautree::TrueChannel, - tautree::TrueHasRecoColl, + // tautree::TrueHasRecoColl, tautree::TruePosZ, tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, tautree::TrueDaugPx, tautree::TrueDaugPy, tautree::TrueDaugPz, diff --git a/PWGUD/DataModel/TwoTracksEventTables.h b/PWGUD/DataModel/TwoTracksEventTables.h index 73be3f3c438..5eb2640f431 100644 --- a/PWGUD/DataModel/TwoTracksEventTables.h +++ b/PWGUD/DataModel/TwoTracksEventTables.h @@ -29,7 +29,7 @@ namespace two_tracks_tree { // event info DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); -DECLARE_SOA_COLUMN(Bc, bc, int); +DECLARE_SOA_COLUMN(Bc, bc, uint64_t); DECLARE_SOA_COLUMN(TotalTracks, totalTracks, int); DECLARE_SOA_COLUMN(NumContrib, numContrib, int); DECLARE_SOA_COLUMN(GlobalNonPVtracks, globalNonPVtracks, int); diff --git a/PWGUD/TableProducer/SGCandProducer.cxx b/PWGUD/TableProducer/SGCandProducer.cxx index c3cb33cb43e..888dbfb608e 100644 --- a/PWGUD/TableProducer/SGCandProducer.cxx +++ b/PWGUD/TableProducer/SGCandProducer.cxx @@ -285,6 +285,7 @@ struct SGCandProducer { { if (verboseInfo) LOGF(debug, " collision %d", collision.globalIndex()); + getHist(TH1, histdir + "/Stat")->Fill(0., 1.); // reject collisions at TF boundaries if (rejectAtTFBoundary && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { @@ -389,6 +390,8 @@ struct SGCandProducer { fitInfo.BBFV0Apf, fitInfo.BGFV0Apf, fitInfo.BBFDDApf, fitInfo.BBFDDCpf, fitInfo.BGFDDApf, fitInfo.BGFDDCpf); outputCollisionSelExtras(chFT0A, chFT0C, chFDDA, chFDDC, chFV0A, occ, ir, trs, trofs, hmpr, tfb, itsROFb, sbp, zVtxFT0vPv, vtxITSTPC, collision.rct_raw()); + if (verboseInfo) + LOGF(info, "%s Coll GID %d", histdir, collision.globalIndex()); outputCollsLabels(collision.globalIndex()); if (newbc.has_zdc()) { auto zdc = newbc.zdc(); @@ -481,7 +484,7 @@ struct SGCandProducer { if (std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end()) { if (verboseInfo) - LOGF(info, "Event with good generatorId"); + LOGF(info, "Event with good generatorId %d", mccol.getGeneratorId()); processReco(std::string("MCreco"), collision, bcs, tracks, fwdtracks, fv0as, ft0s, fdds); } } @@ -688,6 +691,8 @@ struct McSGCandProducer { // loop over McCollisions and UDCCs simultaneously auto mccol = mccols.iteratorAt(0); auto mcOfInterest = std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end(); + if (verboseInfoMC) + LOGF(info, "Is Generator ID OK %d, MCcoll GenId %d, SubGenID %d, SourceId %d, Set in json ID %d", mcOfInterest, mccol.getGeneratorId(), mccol.getSubGeneratorId(), mccol.getSourceId(), *(generatorIds->begin())); auto lastmccol = mccols.iteratorAt(mccols.size() - 1); auto mccolAtEnd = false; @@ -701,6 +706,7 @@ struct McSGCandProducer { bool goon = true; while (goon) { auto globBC = mccol.bc_as().globalBC(); + // check if dgcand has an associated McCollision if (sgcand.has_collision()) { auto sgcandCol = sgcand.collision_as(); @@ -875,6 +881,7 @@ struct McSGCandProducer { LOGF(info, "Number of McCollisions %d", mccols.size()); LOGF(info, "Number of SG candidates %d", sgcands.size()); LOGF(info, "Number of UD tracks %d", udtracks.size()); + LOGF(info, "Number of McParticles %d", mcparts.size()); } if (mccols.size() > 0) { if (sgcands.size() > 0) { diff --git a/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx b/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx index baea03e1d59..1900e1a1232 100644 --- a/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx +++ b/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx @@ -67,7 +67,8 @@ enum MyRecoProblem { NO_PROBLEM = 0, // no problem MANY_RECO = 1, // more than 1 reconstructed collision TOO_MANY_DAUGHTERS = 2, // more than 6 daughters from 2 taus - TWO_TRACKS = 3 // more than 1 associated track to MC particle (tau daughter) + TWO_TRACKS = 3, // more than 1 associated track to MC particle (tau daughter) + NO_TRACK = 4 // No associated track to MC particle (tau daughter) }; enum MyParticle { @@ -1019,9 +1020,10 @@ struct TauThreeProngEventTableProducer { const int sixTracks = 6; const int oneProng = 1; const int threeProng = 3; + const float epsilon = 0.000001; if (verbose) - LOGF(info, "0. UDMcCollision size %d, Collisions size %d, UDtracks %d, UDMcParticles %d", mcCollisions.size(), collisions.size(), tracks.size(), mcParticles.size()); + LOGF(info, " UDMcCollision size %d, Collisions size %d, UDtracks %d, UDMcParticles %d", mcCollisions.size(), collisions.size(), tracks.size(), mcParticles.size()); // temporary variables float tmpRapidity = -999.; @@ -1038,6 +1040,8 @@ struct TauThreeProngEventTableProducer { // start loop over generated collisions for (const auto& mccoll : mcCollisions) { + if (verbose) + LOGF(info, "-- McColl GID %d", mccoll.globalIndex()); registrySkim.get(HIST("skim/efficiencyMC"))->Fill(0., 1.); // all MC collisions // set up default values per colission @@ -1052,14 +1056,16 @@ struct TauThreeProngEventTableProducer { partFromTauInEta = true; // get particles associated to generated collision + // auto const& tmpPartsFromMcColl = mcParticles.sliceBy(partPerMcCollision, (int64_t)mccoll.globalIndex()); auto const& tmpPartsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + if (verbose) - LOGF(info, "1. part from MC coll %d", tmpPartsFromMcColl.size()); + LOGF(info, "- part from MC coll %d", tmpPartsFromMcColl.size()); int countMothers = 0; const int desiredNMothers = 2; for (const auto& particle : tmpPartsFromMcColl) { if (verbose) - LOGF(info, "2. MC part pdg %d", particle.pdgCode()); + LOGF(info, "-- MC part pdg %d", particle.pdgCode()); if (std::abs(particle.pdgCode()) != kTauMinus) continue; // 15 = tau_minus // if (std::abs(particle.pdgCode()) != 15) continue; // 15 = tau_minus @@ -1073,7 +1079,7 @@ struct TauThreeProngEventTableProducer { trueTauPhi[countMothers] = RecoDecay::phi(particle.px(), particle.py()); if (verbose) - LOGF(info, "tau P(%f,%f,%f), e %f, y %f", particle.px(), particle.py(), particle.pz(), particle.e(), tmpRapidity); + LOGF(info, "-- tau P(%f,%f,%f), e %f, y %f", particle.px(), particle.py(), particle.pz(), particle.e(), tmpRapidity); registrySkim.get(HIST("skim/tauRapidityMC"))->Fill(tmpRapidity); registrySkim.get(HIST("skim/tauPhiMC"))->Fill(trueTauPhi[countMothers]); registrySkim.get(HIST("skim/tauEtaMC"))->Fill(trueTauEta[countMothers]); @@ -1081,15 +1087,16 @@ struct TauThreeProngEventTableProducer { if (std::abs(tmpRapidity) > trkEtacut) { // 0.9 tauInRapidity = false; if (verbose) - LOGF(info, "tau y %f", tmpRapidity); + LOGF(info, "--- tau y %f", tmpRapidity); } // rapidity check } // number of taus countMothers++; } // end of loop over MC paricles + // LOGF(info, "1b. countMothers %d", countMothers); registrySkim.get(HIST("skim/nTauMC"))->Fill(countMothers); if (countMothers != desiredNMothers) { // 2 if (verbose) - LOGF(info, "Truth collision has number of mother particles (taus) %d different than 2. Jump to the next MC event.", countMothers); + LOGF(info, "-- Truth collision has number of mother particles (taus) %d different than 2. Jump to the next MC event.", countMothers); continue; } @@ -1097,7 +1104,7 @@ struct TauThreeProngEventTableProducer { if (!tauInRapidity) { // tau NOT in rapidity -> continue if (verbose) - LOGF(info, "At least one mother particle (taus) out of rapidity (|y|<0.9). Jump to the next MC event."); + LOGF(info, "-- At least one mother particle (taus) out of rapidity (|y|<0.9). Jump to the next MC event."); continue; } @@ -1149,9 +1156,10 @@ struct TauThreeProngEventTableProducer { // check number of charged particles in MC event if ((nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != fourTracks) && (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != sixTracks)) { if (verbose) - LOGF(info, "Different from 4/6 charged particles (%d) from both taus. Jump to the next MC event.", nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); + LOGF(info, "-- Different from 4/6 charged particles (%d) from both taus. Jump to the next MC event.", nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); continue; } + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(3., 1.); // 1+3 (3+3) topology if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 registrySkim.get(HIST("skim/efficiencyMC"))->Fill(4., 1.); @@ -1161,9 +1169,10 @@ struct TauThreeProngEventTableProducer { if (!partFromTauInEta) { if (verbose) - LOGF(info, "At least one daughter particle from taus out of pseudo-rapidity (|eta|<0.9). Jump to the next MC event."); + LOGF(info, "-- At least one daughter particle from taus out of pseudo-rapidity (|eta|<0.9). Jump to the next MC event."); continue; } + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(6., 1.); // particles from tau in |eta|<0.9 if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 registrySkim.get(HIST("skim/efficiencyMC"))->Fill(7., 1.); @@ -1179,12 +1188,12 @@ struct TauThreeProngEventTableProducer { zerothTau = 0; // prepare local variables for output table - int32_t runNumber = -999; + int32_t runNumber = -999; // when no reconstructed collisions is associated to MCcoll it should remain = -999 int bc = -999; // int nTrks[3] = {-999, -999, -999}; // totalTracks, numContrib, globalNonPVtracks int totalTracks = -999; int8_t nPVcontrib = -99; - int rct = -999; + int rct = -99; // float vtxPos[3] = {-999., -999., -999.}; float zVertex = -999; @@ -1232,10 +1241,10 @@ struct TauThreeProngEventTableProducer { // float tofEP[2] = {-999, -999}; float chi2TOF[6] = {-999., -999., -999., -999., -999., -999.}; - bool trueHasRecoColl = false; - float trueDaugX[6] = {-999., -999., -999., -999., -999., -999.}; - float trueDaugY[6] = {-999., -999., -999., -999., -999., -999.}; - float trueDaugZ[6] = {-999., -999., -999., -999., -999., -999.}; + // bool trueHasRecoColl = false; + float trueDaugX[6] = {-998., -998., -998., -998., -998., -998.}; + float trueDaugY[6] = {-998., -998., -998., -998., -998., -998.}; + float trueDaugZ[6] = {-998., -998., -998., -998., -998., -998.}; int trueDaugPdgCode[6] = {-999, -999, -999, -999, -999, -999}; // bool problem = false; MyRecoProblem problem = NO_PROBLEM; @@ -1256,180 +1265,233 @@ struct TauThreeProngEventTableProducer { else if (nPi == sixTracks) // 6 trueChannel = 4; + // LOGF(info, "MC Coll global index %d", mccoll.globalIndex()); + // LOGF(info, "2. UDMcCollision size %d, Collisions size %d, UDtracks %d, UDMcParticles %d", mcCollisions.size(), collisions.size(), tracks.size(), mcParticles.size()); + // for (const auto& coll : collisions) { + // LOGF(info, "coll global index %d", coll.globalIndex()); + // } + // find reconstructed collisions associated to the generated collision auto const& collFromMcColls = collisions.sliceBy(colPerMcCollision, mccoll.globalIndex()); if (verbose) - LOGF(info, "coll from MC Coll %d", collFromMcColls.size()); + LOGF(info, "-- coll from MC Coll %d", collFromMcColls.size()); // check the generated collision was reconstructed if (collFromMcColls.size() > 0) { // get the truth and reco-level info if (verbose) - LOGF(info, "MC Collision has reconstructed collision!"); - trueHasRecoColl = true; + LOGF(info, "--- MC Collision has reconstructed collision!"); + // trueHasRecoColl = true; // check there is exactly one reco-level collision associated to generated collision if (collFromMcColls.size() > 1) { if (verbose) - LOGF(info, "Truth collision has more than 1 reco collision. Skipping this event."); - // histos.get(HIST("Truth/hTroubles"))->Fill(1); - // problem = true; + LOGF(info, "---- Truth collision has more than 1 reco collision. Event remains."); + // LOGF(info, "Truth collision has more than 1 reco collision. Skipping this event."); + // histos.get(HIST("Truth/hTroubles"))->Fill(1); + // problem = true; problem = MANY_RECO; registrySkim.get(HIST("skim/problemMC"))->Fill(MANY_RECO); - continue; + // continue; + } else { + if (verbose) + LOGF(info, "---- Truth collision has 1 reco collision. Record event."); } - // grap reco-level collision - auto const& collFromMcColl = collFromMcColls.iteratorAt(0); - // grab tracks from the reco-level collision to get info to match measured data tables (processDataSG function) - auto const& trksFromColl = tracks.sliceBy(trackPerCollision, collFromMcColl.globalIndex()); - // int countTracksPerCollision = 0; - // int countGoodNonPVtracks = 0; - // for (auto const& trkFromColl : trksFromColl) { - // // countTracksPerCollision++; - // if (!trkFromColl.isPVContributor()) { - // countGoodNonPVtracks++; - // continue; - // } - // } - - // fill info for reconstructed collision - runNumber = collFromMcColl.runNumber(); - bc = collFromMcColl.globalBC(); - totalTracks = trksFromColl.size(); - // nTrks[0] = countTracksPerCollision; - nPVcontrib = collFromMcColl.numContrib(); - // nTrks[1] = collFromMcColl.numContrib(); - // nTrks[2] = countGoodNonPVtracks; - rct = isGoodRCTflag(collFromMcColl); - zVertex = collFromMcColl.posZ(); - // vtxPos[0] = collFromMcColl.posX(); - // vtxPos[1] = collFromMcColl.posY(); - // vtxPos[2] = collFromMcColl.posZ(); - - recoMode = collFromMcColl.flags(); - occupancy = collFromMcColl.occupancyInTime(); - hadronicRate = collFromMcColl.hadronicRate(); - bcSels[0] = collFromMcColl.trs(); - bcSels[1] = collFromMcColl.trofs(); - bcSels[2] = collFromMcColl.hmpr(); - bcSels[3] = collFromMcColl.tfb(); - bcSels[4] = collFromMcColl.itsROFb(); - bcSels[5] = collFromMcColl.sbp(); - bcSels[6] = collFromMcColl.zVtxFT0vPV(); - bcSels[7] = collFromMcColl.vtxITSTPC(); - // energyZNA = collFromMcColl.energyCommonZNA(); - // energyZNC = collFromMcColl.energyCommonZNC(); - // if (energyZNA < 0) - // energyZNA = -1.; - // if (energyZNC < 0) - // energyZNC = -1.; - - amplitudesFIT[0] = collFromMcColl.totalFT0AmplitudeA(); - amplitudesFIT[1] = collFromMcColl.totalFT0AmplitudeC(); - amplitudesFIT[2] = collFromMcColl.totalFV0AmplitudeA(); - // timesFIT[0] = collFromMcColl.timeFT0A(); - // timesFIT[1] = collFromMcColl.timeFT0C(); - // timesFIT[2] = collFromMcColl.timeFV0A(); - // get particles associated to generated collision - auto const& partsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); - if (verbose) - LOGF(info, "part from MC coll %d", partsFromMcColl.size()); - // int countMothers = 0; - int countDaughters = 0; - countPi0 = 0; - for (const auto& particle : partsFromMcColl) { - if (verbose) - LOGF(info, "Reco coll; part pdg %d", particle.pdgCode()); - // select only tauons with checking if particle has no mother - // in UPC MC taus have mothers - // if (particle.has_mothers()) - if (std::abs(particle.pdgCode()) != kTauMinus) - continue; // 15 = tau_minus + // grab reco-level collision + for (const auto& collFromMcColl : collFromMcColls) { + if (verbose) { + LOGF(info, "---- ###### Collision %d #########", collFromMcColl.index()); + LOGF(info, "---- Coll GID %d, Vertex (%f,%f,%f)", collFromMcColl.globalIndex(), collFromMcColl.posX(), collFromMcColl.posY(), collFromMcColl.posZ()); + } + // auto const& collFromMcColl = collFromMcColls.iteratorAt(0); + // grab tracks from the reco-level collision to get info to match measured data tables (processDataSG function) + auto const& trksFromColl = tracks.sliceBy(trackPerCollision, collFromMcColl.globalIndex()); + // int countTracksPerCollision = 0; + // int countGoodNonPVtracks = 0; + // for (auto const& trkFromColl : trksFromColl) { + // // countTracksPerCollision++; + // if (!trkFromColl.isPVContributor()) { + // countGoodNonPVtracks++; + // continue; + // } + // } - // get daughters of the tau - const auto& daughters = particle.daughters_as(); - // int countDaughters = 0; - for (const auto& daughter : daughters) { + // fill info for reconstructed collision + runNumber = collFromMcColl.runNumber(); + bc = collFromMcColl.globalBC(); + totalTracks = trksFromColl.size(); + // nTrks[0] = countTracksPerCollision; + nPVcontrib = collFromMcColl.numContrib(); + // nTrks[1] = collFromMcColl.numContrib(); + // nTrks[2] = countGoodNonPVtracks; + rct = isGoodRCTflag(collFromMcColl); + zVertex = collFromMcColl.posZ(); + // vtxPos[0] = collFromMcColl.posX(); + // vtxPos[1] = collFromMcColl.posY(); + // vtxPos[2] = collFromMcColl.posZ(); + + recoMode = collFromMcColl.flags(); + occupancy = collFromMcColl.occupancyInTime(); + hadronicRate = collFromMcColl.hadronicRate(); + bcSels[0] = collFromMcColl.trs(); + bcSels[1] = collFromMcColl.trofs(); + bcSels[2] = collFromMcColl.hmpr(); + bcSels[3] = collFromMcColl.tfb(); + bcSels[4] = collFromMcColl.itsROFb(); + bcSels[5] = collFromMcColl.sbp(); + bcSels[6] = collFromMcColl.zVtxFT0vPV(); + bcSels[7] = collFromMcColl.vtxITSTPC(); + // energyZNA = collFromMcColl.energyCommonZNA(); + // energyZNC = collFromMcColl.energyCommonZNC(); + // if (energyZNA < 0) + // energyZNA = -1.; + // if (energyZNC < 0) + // energyZNC = -1.; + + amplitudesFIT[0] = collFromMcColl.totalFT0AmplitudeA(); + amplitudesFIT[1] = collFromMcColl.totalFT0AmplitudeC(); + amplitudesFIT[2] = collFromMcColl.totalFV0AmplitudeA(); + // timesFIT[0] = collFromMcColl.timeFT0A(); + // timesFIT[1] = collFromMcColl.timeFT0C(); + // timesFIT[2] = collFromMcColl.timeFV0A(); + + // get particles associated to generated collision + auto const& partsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + if (verbose) + LOGF(info, "---- part from MC coll %d", partsFromMcColl.size()); + // int countMothers = 0; + int countDaughters = 0; + countPi0 = 0; + for (const auto& particle : partsFromMcColl) { if (verbose) - LOGF(info, "With Coll; daug pdg %d", daughter.pdgCode()); - // check if it is the charged particle (= no pi0 or neutrino) - if (enumMyParticle(daughter.pdgCode()) == MyOtherParticle) // -1 - continue; - countDaughters++; - if (daughter.pdgCode() == kPi0) - countPi0++; - - // check whether 1+3 or 3+3 topology is present - if (countDaughters > sixTracks) { // 6 + LOGF(info, "----- Reco coll; part pdg %d, GID %d", particle.pdgCode(), particle.globalIndex()); + // select only tauons with checking if particle has no mother + // in UPC MC taus have mothers + // if (particle.has_mothers()) + if (std::abs(particle.pdgCode()) != kTauMinus) + continue; // 15 = tau_minus + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + // int countDaughters = 0; + for (const auto& daughter : daughters) { if (verbose) - LOGF(info, "Truth collision has more than 6 charged daughters from 2 taus. Breaking the daughter loop."); - // histos.get(HIST("Truth/hTroubles"))->Fill(3); - // problem = true; - problem = TOO_MANY_DAUGHTERS; - registrySkim.get(HIST("skim/problemMC"))->Fill(TOO_MANY_DAUGHTERS); - - break; - } - - // fill info for each daughter - trueDaugX[countDaughters - 1] = daughter.px(); - trueDaugY[countDaughters - 1] = daughter.py(); - trueDaugZ[countDaughters - 1] = daughter.pz(); - trueDaugPdgCode[countDaughters - 1] = daughter.pdgCode(); - - // get tracks associated to MC daughter (how well the daughter was reconstructed) - auto const& tracksFromDaughter = tracks.sliceBy(trackPerMcParticle, daughter.globalIndex()); - // check there is exactly 1 track per 1 particle - if (tracksFromDaughter.size() > 1) { + LOGF(info, "----- With Coll; daug pdg %d, GID %d", daughter.pdgCode(), daughter.globalIndex()); + + if (daughter.pdgCode() == kPi0) + countPi0++; + + // check if it is the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == MyOtherParticle) // -1 + continue; + countDaughters++; + + // check whether 1+3 or 3+3 topology is present + if (countDaughters > sixTracks) { // 6 + if (verbose) + LOGF(info, "------ Truth collision has more than 6 charged daughters from 2 taus. Breaking the daughter loop."); + // histos.get(HIST("Truth/hTroubles"))->Fill(3); + // problem = true; + problem = TOO_MANY_DAUGHTERS; + registrySkim.get(HIST("skim/problemMC"))->Fill(TOO_MANY_DAUGHTERS); + + break; + } + + // fill info for each daughter + trueDaugX[countDaughters - 1] = daughter.px(); + trueDaugY[countDaughters - 1] = daughter.py(); + trueDaugZ[countDaughters - 1] = daughter.pz(); + trueDaugPdgCode[countDaughters - 1] = daughter.pdgCode(); if (verbose) - LOGF(info, "Daughter has more than 1 associated track. Skipping this daughter."); - // histos.get(HIST("Truth/hTroubles"))->Fill(4); - // problem = true; - problem = TWO_TRACKS; - registrySkim.get(HIST("skim/problemMC"))->Fill(TWO_TRACKS); - continue; - } - // grab the track and fill info for reconstructed track (should be done 4 or 6 times) - const auto& trk = tracksFromDaughter.iteratorAt(0); - if (verbose) - LOGF(info, "p(%f,%f,%f)", trk.px(), trk.py(), trk.pz()); - px[countDaughters - 1] = trk.px(); - py[countDaughters - 1] = trk.py(); - pz[countDaughters - 1] = trk.pz(); - sign[countDaughters - 1] = trk.sign(); - dcaXY[countDaughters - 1] = trk.dcaXY(); - dcaZ[countDaughters - 1] = trk.dcaZ(); - // trkTimeRes[countMothers - 1] = trk.trackTimeRes(); - // if (countMothers == 1) { - // itsClusterSizesTrk1 = trk.itsClusterSizes(); - // } else { - // itsClusterSizesTrk2 = trk.itsClusterSizes(); - // } - - nclTPCcrossedRows[countDaughters - 1] = trk.tpcNClsCrossedRows(); - nclTPCfind[countDaughters - 1] = trk.tpcNClsFindable(); - nclTPCchi2[countDaughters - 1] = trk.tpcChi2NCl(); - trkITSchi2[countDaughters - 1] = trk.itsChi2NCl(); - trkITScl[countDaughters - 1] = numberOfItsClustersCheck(trk); - - tpcSignal[countDaughters - 1] = trk.tpcSignal(); - tpcEl[countDaughters - 1] = trk.tpcNSigmaEl(); - tpcMu[countDaughters - 1] = trk.tpcNSigmaMu(); - tpcPi[countDaughters - 1] = trk.tpcNSigmaPi(); - tpcKa[countDaughters - 1] = trk.tpcNSigmaKa(); - tpcPr[countDaughters - 1] = trk.tpcNSigmaPr(); - // tpcIP[countDaughters - 1] = trk.tpcInnerParam(); - - tofSignal[countDaughters - 1] = trk.beta(); - tofEl[countDaughters - 1] = trk.tofNSigmaEl(); - tofMu[countDaughters - 1] = trk.tofNSigmaMu(); - tofPi[countDaughters - 1] = trk.tofNSigmaPi(); - tofKa[countDaughters - 1] = trk.tofNSigmaKa(); - tofPr[countDaughters - 1] = trk.tofNSigmaPr(); - // tofEP[countMothers - 1] = trk.tofExpMom(); - if (trk.hasTOF()) - chi2TOF[countDaughters - 1] = trk.tofChi2(); - - } // daughters - } // particles + LOGF(info, "----- tau daug pxpypz (%f, %f, %f) pdg %d", daughter.px(), daughter.py(), daughter.pz(), daughter.pdgCode()); + // get tracks associated to MC daughter (how well the daughter was reconstructed) + auto const& tracksFromDaughter = tracks.sliceBy(trackPerMcParticle, daughter.globalIndex()); + // check there is exactly 1 track per 1 particle + if (tracksFromDaughter.size() > 1) { + if (verbose) + LOGF(info, "------ Daughter has more than 1 associated track. Ntracks = %d.", tracksFromDaughter.size()); + // LOGF(info, "Daughter has more than 1 associated track. Ntracks = %d. Skipping this daughter.", tracksFromDaughter.size()); + + // make sure that track momentum is the same (difference is smaller than epsilon=0.000001) for multiple reconstructed tracks, if not reject + // tracks are accocated to 2 different collisions (!?) + float tmptrk[3]; + bool firstObject = true; + int counter = 0; + for (const auto& trk : tracksFromDaughter) { + if (verbose) + LOGF(info, "------- track GID %d, p(%f,%f,%f)", trk.globalIndex(), trk.px(), trk.py(), trk.pz()); + if (firstObject) { + tmptrk[0] = trk.px(); + tmptrk[1] = trk.py(); + tmptrk[2] = trk.pz(); + firstObject = false; + counter++; + } else { + if ((std::abs(tmptrk[0] - trk.px()) > epsilon) || (std::abs(tmptrk[1] - trk.py()) > epsilon) || (std::abs(tmptrk[2] - trk.pz()) > epsilon)) + counter++; + } + } // end of loop over tracks from 1 McParticle + if (verbose) + LOGF(info, "------ Corrected number of associated tracks to MC particle %d", counter); + + if (counter > 1) { + if (verbose) + LOGF(info, "------ Daughter has more than 1 associated track. Ntracks = %d. Skipping this daughter.", counter); + problem = TWO_TRACKS; + registrySkim.get(HIST("skim/problemMC"))->Fill(TWO_TRACKS); + continue; + } + } else if (tracksFromDaughter.size() < 1) { + // what if no track is associated to mc particle??? + if (verbose) + LOGF(info, "----- Daughter has no associated track. Ntracks = %d. Skipping this daughter.", tracksFromDaughter.size()); + problem = NO_TRACK; + registrySkim.get(HIST("skim/problemMC"))->Fill(NO_TRACK); + continue; + } + + // grab the track and fill info for reconstructed track (should be done 4 or 6 times) + const auto& trk = tracksFromDaughter.iteratorAt(0); + + px[countDaughters - 1] = trk.px(); + py[countDaughters - 1] = trk.py(); + pz[countDaughters - 1] = trk.pz(); + sign[countDaughters - 1] = trk.sign(); + dcaXY[countDaughters - 1] = trk.dcaXY(); + dcaZ[countDaughters - 1] = trk.dcaZ(); + // trkTimeRes[countMothers - 1] = trk.trackTimeRes(); + // if (countMothers == 1) { + // itsClusterSizesTrk1 = trk.itsClusterSizes(); + // } else { + // itsClusterSizesTrk2 = trk.itsClusterSizes(); + // } + + nclTPCcrossedRows[countDaughters - 1] = trk.tpcNClsCrossedRows(); + nclTPCfind[countDaughters - 1] = trk.tpcNClsFindable(); + nclTPCchi2[countDaughters - 1] = trk.tpcChi2NCl(); + trkITSchi2[countDaughters - 1] = trk.itsChi2NCl(); + trkITScl[countDaughters - 1] = numberOfItsClustersCheck(trk); + + tpcSignal[countDaughters - 1] = trk.tpcSignal(); + tpcEl[countDaughters - 1] = trk.tpcNSigmaEl(); + tpcMu[countDaughters - 1] = trk.tpcNSigmaMu(); + tpcPi[countDaughters - 1] = trk.tpcNSigmaPi(); + tpcKa[countDaughters - 1] = trk.tpcNSigmaKa(); + tpcPr[countDaughters - 1] = trk.tpcNSigmaPr(); + // tpcIP[countDaughters - 1] = trk.tpcInnerParam(); + + tofSignal[countDaughters - 1] = trk.beta(); + tofEl[countDaughters - 1] = trk.tofNSigmaEl(); + tofMu[countDaughters - 1] = trk.tofNSigmaMu(); + tofPi[countDaughters - 1] = trk.tofNSigmaPi(); + tofKa[countDaughters - 1] = trk.tofNSigmaKa(); + tofPr[countDaughters - 1] = trk.tofNSigmaPr(); + // tofEP[countMothers - 1] = trk.tofExpMom(); + if (trk.hasTOF()) + chi2TOF[countDaughters - 1] = trk.tofChi2(); + + } // end of loop over daughters of taus + } // end of loop over MC particles + } // end of loop over collisions associated to MC collision } else { // get only the truth information. The reco-level info is left on default if (verbose) LOGF(info, "MC Collision has NO reconstructed collision!"); @@ -1470,12 +1532,14 @@ struct TauThreeProngEventTableProducer { for (const auto& daughter : daughters) { if (verbose) LOGF(info, "NO Coll; daug id %d, pdg %d", daughter.globalIndex(), daughter.pdgCode()); + + if (daughter.pdgCode() == kPi0) + countPi0++; + // select only the charged particle (= no pi0 or neutrino) if (enumMyParticle(daughter.pdgCode()) == -1) continue; countDaughters++; - if (daughter.pdgCode() == kPi0) - countPi0++; // check whether 1+3 or 3+3 topology is present if (countDaughters > sixTracks) { // 6 @@ -1526,7 +1590,7 @@ struct TauThreeProngEventTableProducer { chi2TOF, // trueChannel, - trueHasRecoColl, + // trueHasRecoColl, mccoll.posZ(), trueTauX, trueTauY, trueTauZ, trueDaugX, trueDaugY, trueDaugZ, diff --git a/PWGUD/TableProducer/twoTracksEventTableProducer.cxx b/PWGUD/TableProducer/twoTracksEventTableProducer.cxx index 874761db585..3af6a964021 100644 --- a/PWGUD/TableProducer/twoTracksEventTableProducer.cxx +++ b/PWGUD/TableProducer/twoTracksEventTableProducer.cxx @@ -626,6 +626,7 @@ struct TwoTracksEventTableProducer { // get particles associated to generated collision auto const& partsFromMcColl = parts.sliceBy(partPerMcCollision, mccoll.globalIndex()); int countMothers = 0; + int totalChargedDaughters = 0; for (const auto& particle : partsFromMcColl) { // select only mothers with checking if particle has no mother if (particle.has_mothers()) @@ -644,74 +645,85 @@ struct TwoTracksEventTableProducer { trueMotherY[countMothers - 1] = particle.py(); trueMotherZ[countMothers - 1] = particle.pz(); - // get daughters of the tau + // get daughters of the mother const auto& daughters = particle.daughters_as(); - int countDaughters = 0; for (const auto& daughter : daughters) { // check if it is the charged particle (= no pi0 or neutrino) if (enumMyParticle(daughter.pdgCode()) == -1) continue; - countDaughters++; - // check there is only 1 charged daughter related to 1 tau - if (countDaughters > 1) { + // check we do not have more than 2 charged daughters in total + if (totalChargedDaughters >= 2) { if (verboseInfo) - printLargeMessage("Truth collision has more than 1 charged daughters of no mother particles. Breaking the daughter loop."); + printLargeMessage("Truth collision has more than 2 total charged daughters. Breaking the daughter loop."); histos.get(HIST("Truth/hTroubles"))->Fill(3); problem = true; break; } // fill info for each daughter - trueDaugX[countMothers - 1] = daughter.px(); - trueDaugY[countMothers - 1] = daughter.py(); - trueDaugZ[countMothers - 1] = daughter.pz(); - trueDaugPdgCode[countMothers - 1] = daughter.pdgCode(); + trueDaugX[totalChargedDaughters] = daughter.px(); + trueDaugY[totalChargedDaughters] = daughter.py(); + trueDaugZ[totalChargedDaughters] = daughter.pz(); + trueDaugPdgCode[totalChargedDaughters] = daughter.pdgCode(); // get tracks associated to MC daughter (how well the daughter was reconstructed) auto const& tracksFromDaughter = trks.sliceBy(trackPerMcParticle, daughter.globalIndex()); // check there is exactly 1 track per 1 particle + if (tracksFromDaughter.size() == 0) { + if (verboseInfo) + printLargeMessage("Daughter has no associated track. Skipping this daughter."); + histos.get(HIST("Truth/hTroubles"))->Fill(5); + problem = true; + totalChargedDaughters++; + continue; + } if (tracksFromDaughter.size() > 1) { if (verboseInfo) printLargeMessage("Daughter has more than 1 associated track. Skipping this daughter."); histos.get(HIST("Truth/hTroubles"))->Fill(4); problem = true; + totalChargedDaughters++; continue; } - // grab the track and fill info for reconstructed track (should be done twice) + // grab the track and fill info for reconstructed track const auto& trk = tracksFromDaughter.iteratorAt(0); - px[countMothers - 1] = trk.px(); - py[countMothers - 1] = trk.py(); - pz[countMothers - 1] = trk.pz(); - sign[countMothers - 1] = trk.sign(); - dcaxy[countMothers - 1] = trk.dcaXY(); - dcaz[countMothers - 1] = trk.dcaZ(); - trkTimeRes[countMothers - 1] = trk.trackTimeRes(); - if (countMothers == 1) { + px[totalChargedDaughters] = trk.px(); + py[totalChargedDaughters] = trk.py(); + pz[totalChargedDaughters] = trk.pz(); + sign[totalChargedDaughters] = trk.sign(); + dcaxy[totalChargedDaughters] = trk.dcaXY(); + dcaz[totalChargedDaughters] = trk.dcaZ(); + trkTimeRes[totalChargedDaughters] = trk.trackTimeRes(); + if (totalChargedDaughters == 0) { itsClusterSizesTrk1 = trk.itsClusterSizes(); } else { itsClusterSizesTrk2 = trk.itsClusterSizes(); } - tpcSignal[countMothers - 1] = trk.tpcSignal(); - tpcEl[countMothers - 1] = trk.tpcNSigmaEl(); - tpcMu[countMothers - 1] = trk.tpcNSigmaMu(); - tpcPi[countMothers - 1] = trk.tpcNSigmaPi(); - tpcKa[countMothers - 1] = trk.tpcNSigmaKa(); - tpcPr[countMothers - 1] = trk.tpcNSigmaPr(); - tpcIP[countMothers - 1] = trk.tpcInnerParam(); - tofSignal[countMothers - 1] = trk.tofSignal(); - tofEl[countMothers - 1] = trk.tofNSigmaEl(); - tofMu[countMothers - 1] = trk.tofNSigmaMu(); - tofPi[countMothers - 1] = trk.tofNSigmaPi(); - tofKa[countMothers - 1] = trk.tofNSigmaKa(); - tofPr[countMothers - 1] = trk.tofNSigmaPr(); - tofEP[countMothers - 1] = trk.tofExpMom(); + tpcSignal[totalChargedDaughters] = trk.tpcSignal(); + tpcEl[totalChargedDaughters] = trk.tpcNSigmaEl(); + tpcMu[totalChargedDaughters] = trk.tpcNSigmaMu(); + tpcPi[totalChargedDaughters] = trk.tpcNSigmaPi(); + tpcKa[totalChargedDaughters] = trk.tpcNSigmaKa(); + tpcPr[totalChargedDaughters] = trk.tpcNSigmaPr(); + tpcIP[totalChargedDaughters] = trk.tpcInnerParam(); + tofSignal[totalChargedDaughters] = trk.tofSignal(); + tofEl[totalChargedDaughters] = trk.tofNSigmaEl(); + tofMu[totalChargedDaughters] = trk.tofNSigmaMu(); + tofPi[totalChargedDaughters] = trk.tofNSigmaPi(); + tofKa[totalChargedDaughters] = trk.tofNSigmaKa(); + tofPr[totalChargedDaughters] = trk.tofNSigmaPr(); + tofEP[totalChargedDaughters] = trk.tofExpMom(); + totalChargedDaughters++; } // daughters + if (problem) + break; } // particles } else { // get only the truth information. The reco-level info is left on default // get particles associated to generated collision auto const& partsFromMcColl = parts.sliceBy(partPerMcCollision, mccoll.globalIndex()); int countMothers = 0; + int totalChargedDaughters = 0; for (const auto& particle : partsFromMcColl) { - // select only tauons with checking if particle has no mother + // select only motherless particles if (particle.has_mothers()) continue; countMothers++; @@ -723,39 +735,42 @@ struct TwoTracksEventTableProducer { problem = true; break; } - // fill info for each tau + // fill info for each mother trueMotherX[countMothers - 1] = particle.px(); trueMotherY[countMothers - 1] = particle.py(); trueMotherZ[countMothers - 1] = particle.pz(); - // get daughters of the tau + // get daughters of the mother const auto& daughters = particle.daughters_as(); - int countDaughters = 0; for (const auto& daughter : daughters) { // select only the charged particle (= no pi0 or neutrino) if (enumMyParticle(daughter.pdgCode()) == -1) continue; - countDaughters++; - // check there is only 1 charged daughter related to 1 tau - if (countDaughters > 1) { + // check we do not have more than 2 charged daughters in total + if (totalChargedDaughters >= 2) { if (verboseInfo) - printLargeMessage("Truth collision has more than 1 charged daughters of no mother particles. Breaking the daughter loop."); + printLargeMessage("Truth collision has more than 2 total charged daughters. Breaking the daughter loop."); histos.get(HIST("Truth/hTroubles"))->Fill(13); problem = true; break; } // fill info for each daughter - trueDaugX[countMothers - 1] = daughter.px(); - trueDaugY[countMothers - 1] = daughter.py(); - trueDaugZ[countMothers - 1] = daughter.pz(); - trueDaugPdgCode[countMothers - 1] = daughter.pdgCode(); + trueDaugX[totalChargedDaughters] = daughter.px(); + trueDaugY[totalChargedDaughters] = daughter.py(); + trueDaugZ[totalChargedDaughters] = daughter.pz(); + trueDaugPdgCode[totalChargedDaughters] = daughter.pdgCode(); + totalChargedDaughters++; } // daughters + if (problem) + break; } // particles } // collisions - // decide the channel and set the variable. Only two cahnnels suported now. + // decide the channel and set the variable if ((enumMyParticle(trueDaugPdgCode[0]) == P_ELECTRON) && (enumMyParticle(trueDaugPdgCode[1]) == P_ELECTRON)) trueChannel = CH_EE; + if ((enumMyParticle(trueDaugPdgCode[0]) == P_MUON) && (enumMyParticle(trueDaugPdgCode[1]) == P_MUON)) + trueChannel = CH_MUMU; if ((enumMyParticle(trueDaugPdgCode[0]) == P_ELECTRON) && ((enumMyParticle(trueDaugPdgCode[1]) == P_PION) || (enumMyParticle(trueDaugPdgCode[1]) == P_MUON))) trueChannel = CH_EMUPI; if ((enumMyParticle(trueDaugPdgCode[1]) == P_ELECTRON) && ((enumMyParticle(trueDaugPdgCode[0]) == P_PION) || (enumMyParticle(trueDaugPdgCode[0]) == P_MUON))) diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx index 9dcb3cac9bd..a8138f126e6 100644 --- a/PWGUD/Tasks/flowCorrelationsUpc.cxx +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -46,10 +46,11 @@ namespace o2::aod namespace flowcorrupc { DECLARE_SOA_COLUMN(Multiplicity, multiplicity, int); -} +DECLARE_SOA_COLUMN(Truegapside, truegapside, int); +} // namespace flowcorrupc DECLARE_SOA_TABLE(Multiplicity, "AOD", "MULTIPLICITY", flowcorrupc::Multiplicity); - +DECLARE_SOA_TABLE(Truegapside, "AOD", "TRUEGAPSIDE", flowcorrupc::Truegapside); } // namespace o2::aod using namespace o2; @@ -61,11 +62,17 @@ using namespace o2::framework::expressions; struct CalcNchUpc { O2_DEFINE_CONFIGURABLE(cfgZVtxCut, float, 10.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.2f, "minimum accepted track pT") - O2_DEFINE_CONFIGURABLE(cfgPtCutMax, float, 10.0f, "maximum accepted track pT") - O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 0.8f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.1f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 0.9f, "Eta cut") O2_DEFINE_CONFIGURABLE(cfgMinMixEventNum, int, 5, "Minimum number of events to mix") + // Added UPC Cuts + SGSelector sgSelector; + Configurable cfgCutFV0{"cfgCutFV0", 50., "FV0A threshold"}; + Configurable cfgCutFT0A{"cfgCutFT0A", 150., "FT0A threshold"}; + Configurable cfgCutFT0C{"cfgCutFT0C", 50., "FT0C threshold"}; + Configurable cfgCutZDC{"cfgCutZDC", 10., "ZDC threshold"}; + // Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); using UdTracks = soa::Join; @@ -73,6 +80,7 @@ struct CalcNchUpc { using UDCollisionsFull = soa::Join; Produces multiplicityNch; + Produces truegapside; HistogramRegistry registry{"registry"}; @@ -80,14 +88,25 @@ struct CalcNchUpc { { AxisSpec axisNch = {100, 0, 100}; AxisSpec axisVrtx = {10, -10, 10}; + // AxisSpec axisgap = {12, -6, 6}; + // std::vector trueGapBins = {-2, -1, 0, 1, 2, 3}; + // AxisSpec axisgap = {trueGapBins, "true gap side"}; + + std::vector binEdges = {-1.5, -0.5, 0.5, 1.5, 2.5, 3.5}; + AxisSpec axisgap = {binEdges, "true gap side"}; + registry.add("truegap", "truegap", {HistType::kTH1D, {axisgap}}); registry.add("Ncharge", "N_{charge}", {HistType::kTH1D, {axisNch}}); registry.add("zVtx_all", "zVtx_all", {HistType::kTH1D, {axisVrtx}}); + registry.add("Nch_vs_zVtx", "Nch vs zVtx", {HistType::kTH2D, {axisVrtx, axisNch}}); + // registry.add("truegap", "truegap", {HistType::kTH1D, {axisgap}}); } void process(UDCollisionsFull::iterator const& collision, UdTracksFull const& tracks) { multiplicityNch(tracks.size()); + truegapside(sgSelector.trueGap(collision, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC)); + // LOG(info) << "truegapside=" << sgSelector.trueGap(collision, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC); registry.fill(HIST("Ncharge"), tracks.size()); registry.fill(HIST("zVtx_all"), collision.posZ()); } @@ -98,7 +117,7 @@ struct FlowCorrelationsUpc { O2_DEFINE_CONFIGURABLE(cfgIfVertex, bool, false, "choose vertex or not") O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.1f, "minimum accepted track pT") O2_DEFINE_CONFIGURABLE(cfgPtCutMax, float, 10.0f, "maximum accepted track pT") - O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 0.8f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 0.9f, "Eta cut") O2_DEFINE_CONFIGURABLE(cfgMinMixEventNum, int, 5, "Minimum number of events to mix") O2_DEFINE_CONFIGURABLE(cfgMinMult, int, 0, "Minimum multiplicity for collision") O2_DEFINE_CONFIGURABLE(cfgMaxMult, int, 10, "Maximum multiplicity for collision") @@ -109,8 +128,8 @@ struct FlowCorrelationsUpc { O2_DEFINE_CONFIGURABLE(cfgRadiusLow, float, 0.8, "Low radius for merging cut") O2_DEFINE_CONFIGURABLE(cfgRadiusHigh, float, 2.5, "High radius for merging cut") O2_DEFINE_CONFIGURABLE(cfgIsGoodItsLayers, bool, false, "whether choose itslayers") - O2_DEFINE_CONFIGURABLE(cfgGapSideA, bool, true, "choose gapside A") - O2_DEFINE_CONFIGURABLE(cfgGapSideC, bool, false, "choose gapside C") + O2_DEFINE_CONFIGURABLE(cfgGapSide, int, 1, "0: gapside A;1:C") + O2_DEFINE_CONFIGURABLE(cfgGapSideMerge, bool, false, "whether merge A and C side together") O2_DEFINE_CONFIGURABLE(cfgDcaxy, bool, true, "choose dcaxy") O2_DEFINE_CONFIGURABLE(cfgDcaz, bool, false, "choose dcaz") O2_DEFINE_CONFIGURABLE(cfgDcazCut, float, 10.0, "dcaz cut") @@ -145,12 +164,13 @@ struct FlowCorrelationsUpc { Configurable cfgCutZDC{"cfgCutZDC", 10., "ZDC threshold"}; // make the filters and cuts. - // Filter collisionFilter = (nabs(aod::collision::posZ) < cfgZVtxCut) && (aod::flowcorrupc::multiplicity) > cfgMinMult && (aod::flowcorrupc::multiplicity) < cfgMaxMult && (aod::evsel::sel8) == true; - // Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + Filter trackFilter = (aod::udtrack::isPVContributor == true); + Filter collisionFilter = (aod::udcollision::gapSide == (uint8_t)cfgGapSide && (cfgIfVertex == false || aod::collision::posZ < cfgZVtxCut) && (aod::udcollision::occupancyInTime > 0 && aod::udcollision::occupancyInTime < cfgCutOccupancyHigh) && aod::flowcorrupc::truegapside == 1); - using UdTracks = soa::Join; - using UdTracksFull = soa::Join; - using UDCollisionsFull = soa::Join; + using UdTracks = soa::Filtered>; + using UdTracksFull = soa::Filtered>; + + using UDCollisionsFull = soa::Filtered>; // Define the outputs OutputObj same{Form("sameEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult))}; @@ -160,6 +180,8 @@ struct FlowCorrelationsUpc { void init(InitContext&) { + LOG(info) << "cfgGapSide = " << cfgGapSide; + LOG(info) << "cfgGapSide value type: " << typeid(cfgGapSide).name(); LOGF(info, "Starting init"); // Make histograms to check the distributions after cuts registry.add("deltaEta_deltaPhi_same", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // check to see the delta eta and delta phi distribution @@ -169,10 +191,17 @@ struct FlowCorrelationsUpc { registry.add("pT", "pT", {HistType::kTH1D, {axisPtTrigger}}); registry.add("Nch", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); registry.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); + registry.add("Nch_vs_zVtx", "Nch vs zVtx", {HistType::kTH2D, {axisVertex, axisMultiplicity}}); + registry.add("Nch_same", "Nch same event", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("Nch_mixed", "Nch mixed event", {HistType::kTH1D, {axisMultiplicity}}); registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); - registry.add("eventcount", "bin", {HistType::kTH1F, {{4, 0, 4, "bin"}}}); // histogram to see how many events are in the same and mixed event + registry.add("eventcount_same", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many events are in the same and mixed event + registry.add("eventcount_mixed", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many events are in the same and mixed event + + registry.add("trackcount_same", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many tracks are in the same and mixed event + registry.add("trackcount_mixed", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many tracks are in the same and mixed event std::vector corrAxis = {{axisSample, "Sample"}, {axisVertex, "z-vtx (cm)"}, @@ -215,9 +244,6 @@ struct FlowCorrelationsUpc { if (dPhiStar > constants::math::PI) dPhiStar = constants::math::TwoPI - dPhiStar; - if (dPhiStar < -constants::math::PI) - dPhiStar = -constants::math::TwoPI - dPhiStar; - return dPhiStar; } @@ -226,7 +252,7 @@ struct FlowCorrelationsUpc { { // registry.fill(HIST("hTrackCount"), 0.5); // UPC selection - if (!track.isPVContributor()) { + if (track.pt() < cfgPtCutMin || track.pt() > cfgPtCutMax) { return false; } // registry.fill(HIST("hTrackCount"), 1.5); @@ -333,53 +359,15 @@ struct FlowCorrelationsUpc { void processSame(UDCollisionsFull::iterator const& collision, UdTracksFull const& tracks) { + // LOG(info) << "Event passed filter: truegapside=" << collision.truegapside(); if (tracks.size() < cfgMinMult || tracks.size() > cfgMaxMult) { return; } - if (cfgIsGoodItsLayers && collision.trs() == 0) { - return; - } - - int gapSide = collision.gapSide(); - if (gapSide == 0) { - if (!cfgGapSideA) { - return; - } - } - if (gapSide == 1) { - if (!cfgGapSideC) { - return; - } - } - if (gapSide != 0 && gapSide != 1) { - return; - } - int trueGapSide = sgSelector.trueGap(collision, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC); - gapSide = trueGapSide; - if (gapSide == 0) { - if (!cfgGapSideA) { - return; - } - } - if (gapSide == 1) { - if (!cfgGapSideC) { - return; - } - } - if (gapSide != 0 && gapSide != 1) { - return; - } - float vtxz = collision.posZ(); - if (cfgIfVertex && abs(vtxz) > cfgZVtxCut) { - return; - } - int occupancy = collision.occupancyInTime(); - if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) { - return; - } + registry.fill(HIST("eventcount_same"), 3.5); int runIndex = collision.runNumber(); - registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + // registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + registry.fill(HIST("Nch_vs_zVtx"), collision.posZ(), tracks.size()); fillYield(collision, tracks); fillCorrelations(tracks, tracks, collision.posZ(), SameEvent, runIndex); // fill the SE histogram and Sparse } @@ -398,70 +386,11 @@ struct FlowCorrelationsUpc { SameKindPair pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto const& [collision1, tracks1, collision2, tracks2] : pairs) { + // registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin if (tracks1.size() < cfgMinMult || tracks1.size() > cfgMaxMult || tracks2.size() < cfgMinMult || tracks2.size() > cfgMaxMult) { continue; } - if (cfgIsGoodItsLayers && (collision1.trs() == 0 || collision2.trs() == 0)) { - continue; - } - - int gapSide1 = collision1.gapSide(); - if (gapSide1 == 0) { - if (!cfgGapSideA) { - continue; - } - } - if (gapSide1 == 1) { - if (!cfgGapSideC) { - continue; - } - } - int gapSide2 = collision2.gapSide(); - if (gapSide2 == 0) { - if (!cfgGapSideA) { - continue; - } - } - if (gapSide2 == 1) { - if (!cfgGapSideC) { - continue; - } - } - int trueGapSide1 = sgSelector.trueGap(collision1, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC); - int trueGapSide2 = sgSelector.trueGap(collision2, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC); - if (trueGapSide1 != trueGapSide2) { - continue; - } - if (trueGapSide1 == 0) { - if (!cfgGapSideA) { - continue; - } - } - if (trueGapSide2 == 1) { - if (!cfgGapSideC) { - continue; - } - } - if ((gapSide1 != 0 && gapSide1 != 1) || (gapSide2 != 0 && gapSide2 != 1)) { - continue; - } - float vtxz = collision1.posZ(); - if (cfgIfVertex && abs(vtxz) > cfgZVtxCut) { - return; - } - int occupancy = collision1.occupancyInTime(); - if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) { - return; - } - vtxz = collision2.posZ(); - if (cfgIfVertex && abs(vtxz) > cfgZVtxCut) { - return; - } - occupancy = collision2.occupancyInTime(); - if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) { - return; - } - registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + registry.fill(HIST("eventcount_same"), 4.5); fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, collision1.runNumber()); // fill the ME histogram and Sparse } } diff --git a/PWGUD/Tasks/sginclusivePhiKstarSD.cxx b/PWGUD/Tasks/sginclusivePhiKstarSD.cxx index 4aeb475109b..ea7c42308a2 100644 --- a/PWGUD/Tasks/sginclusivePhiKstarSD.cxx +++ b/PWGUD/Tasks/sginclusivePhiKstarSD.cxx @@ -368,6 +368,7 @@ struct SginclusivePhiKstarSD { "All Events", "has_udMcCollision", Form("generatorsID = %d", generatedId.value), + Form("upcFlag = %d%s", upcflag.value, check(upcflag.value != -1)), Form("GapsideMC = %d", gapsideMC.value), Form("|Vz| < %.1f", vzCut.value), Form("Occupancy < %.0f%s", confgOccCut.value, check(useOccCut.value)), @@ -381,7 +382,6 @@ struct SginclusivePhiKstarSD { std::string("kIsGoodZvtxFT0vsPV") + check(useZvtxftovpv.value), std::string("kIsVertexITSTPC") + check(useVtxItsTpc.value), Form("RCTFlag = %d%s", cutRCTflag.value, check(cutRCTflag.value > 0)), - Form("upcFlag = %d%s", upcflag.value, check(upcflag.value != -1)), Form("%d < numContrib < %d%s", mintrack.value, maxtrack.value, check(usenumContrib.value))}; for (size_t i = 0; i < eveCutLabelsMC.size(); ++i) { @@ -1421,71 +1421,70 @@ struct SginclusivePhiKstarSD { registry.get(HIST("Reco/Stat"))->Fill(4.0, 1.); registry.get(HIST("Reco/Stat"))->Fill(truegapSide, 1.); - if (upcflag != -1 && collision.flags() == upcflag) { - auto partSlice = McParts.sliceBy(partPerMcCollision, mccoll.globalIndex()); - for (const auto& trk1 : partSlice) { - if (std::abs(trk1.pdgCode()) == o2::constants::physics::Pdg::kK0Star892) { - vkstar.SetCoordinates(trk1.px(), trk1.py(), trk1.pz(), o2::constants::physics::MassK0Star892); - auto kDaughters = trk1.daughters_as(); - const size_t kExpectedNumberOfDaughters = 2; - if (kDaughters.size() != kExpectedNumberOfDaughters) { + auto partSlice = McParts.sliceBy(partPerMcCollision, mccoll.globalIndex()); + for (const auto& trk1 : partSlice) { + if (std::abs(trk1.pdgCode()) == o2::constants::physics::Pdg::kK0Star892) { + vkstar.SetCoordinates(trk1.px(), trk1.py(), trk1.pz(), o2::constants::physics::MassK0Star892); + auto kDaughters = trk1.daughters_as(); + const size_t kExpectedNumberOfDaughters = 2; + if (kDaughters.size() != kExpectedNumberOfDaughters) { + continue; + } + auto daughtp = false; + auto daughtm = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } - auto daughtp = false; - auto daughtm = false; - for (const auto& kCurrentDaughter : kDaughters) { - if (!kCurrentDaughter.isPhysicalPrimary()) { - continue; - } - if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kKPlus) { - daughtp = true; - } else if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kPiPlus) { - daughtm = true; - } + if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kKPlus) { + daughtp = true; + } else if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kPiPlus) { + daughtm = true; } - if (daughtp && daughtm) { - if (std::abs(vkstar.Rapidity()) < 0.5) { - registry.get(HIST("MC/accMPtRap_kstar_G1"))->Fill(vkstar.M(), vkstar.Pt(), vkstar.Rapidity(), 1.); - if (truegapSide == gapsideMC) { - registry.get(HIST("MC/accMPtRap_kstar_G11"))->Fill(vkstar.M(), vkstar.Pt(), vkstar.Rapidity(), 1.); - } + } + if (daughtp && daughtm) { + if (std::abs(vkstar.Rapidity()) < 0.5) { + registry.get(HIST("MC/accMPtRap_kstar_G1"))->Fill(vkstar.M(), vkstar.Pt(), vkstar.Rapidity(), 1.); + if (truegapSide == gapsideMC) { + registry.get(HIST("MC/accMPtRap_kstar_G11"))->Fill(vkstar.M(), vkstar.Pt(), vkstar.Rapidity(), 1.); } } } - // phi - if (std::abs(trk1.pdgCode()) == o2::constants::physics::Pdg::kPhi) { - if (trk1.has_mothers()) { - continue; - } - vphi.SetCoordinates(trk1.px(), trk1.py(), trk1.pz(), o2::constants::physics::MassPhi); - auto kDaughters = trk1.daughters_as(); - const size_t kExpectedNumberOfDaughters1 = 2; - if (kDaughters.size() != kExpectedNumberOfDaughters1) { + } + // phi + if (std::abs(trk1.pdgCode()) == o2::constants::physics::Pdg::kPhi) { + if (trk1.has_mothers()) { + continue; + } + vphi.SetCoordinates(trk1.px(), trk1.py(), trk1.pz(), o2::constants::physics::MassPhi); + auto kDaughters = trk1.daughters_as(); + const size_t kExpectedNumberOfDaughters1 = 2; + if (kDaughters.size() != kExpectedNumberOfDaughters1) { + continue; + } + auto daughtp1 = false; + auto daughtm1 = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } - auto daughtp1 = false; - auto daughtm1 = false; - for (const auto& kCurrentDaughter : kDaughters) { - if (!kCurrentDaughter.isPhysicalPrimary()) { - continue; - } - if (kCurrentDaughter.pdgCode() == PDG_t::kKPlus) { - daughtp1 = true; - } else if (kCurrentDaughter.pdgCode() == PDG_t::kKMinus) { - daughtm1 = true; - } + if (kCurrentDaughter.pdgCode() == PDG_t::kKPlus) { + daughtp1 = true; + } else if (kCurrentDaughter.pdgCode() == PDG_t::kKMinus) { + daughtm1 = true; } - if (daughtp1 && daughtm1) { - if (std::abs(vphi.Rapidity()) < 0.5) { - registry.get(HIST("MC/accMPtRap_phi_G1"))->Fill(vphi.M(), vphi.Pt(), vphi.Rapidity(), 1.); - if (truegapSide == gapsideMC) { - registry.get(HIST("MC/accMPtRap_phi_G11"))->Fill(vphi.M(), vphi.Pt(), vphi.Rapidity(), 1.); - } + } + if (daughtp1 && daughtm1) { + if (std::abs(vphi.Rapidity()) < 0.5) { + registry.get(HIST("MC/accMPtRap_phi_G1"))->Fill(vphi.M(), vphi.Pt(), vphi.Rapidity(), 1.); + if (truegapSide == gapsideMC) { + registry.get(HIST("MC/accMPtRap_phi_G11"))->Fill(vphi.M(), vphi.Pt(), vphi.Rapidity(), 1.); } } } } } + if (truegapSide != gapsideMC) return; registry.fill(HIST("Reco/hEventCutFlowMC"), 4); @@ -1516,7 +1515,7 @@ struct SginclusivePhiKstarSD { if (useTfb && collision.tfb() != 1) return; - registry.fill(HIST("Reco/hEventCutFlowMC"), 1); + registry.fill(HIST("Reco/hEventCutFlowMC"), 11); if (useItsrofb && collision.itsROFb() != 1) return; diff --git a/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx b/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx index fd1b467951b..c1ba0124327 100644 --- a/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx +++ b/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx @@ -47,6 +47,19 @@ namespace o2::aod { namespace tree { +DECLARE_SOA_COLUMN(GapSide, gapSide, float); +DECLARE_SOA_COLUMN(GapSideTimeZN, gapSideTimeZN, float); +DECLARE_SOA_COLUMN(Sbp, sbp, int); +DECLARE_SOA_COLUMN(ITSROFb, itsROFb, int); +DECLARE_SOA_COLUMN(VtxITSTPCCut, vtxITSTPCCut, int); +DECLARE_SOA_COLUMN(ZVtxFT0vsPvCut, zVtxFT0vsPvCut, int); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +DECLARE_SOA_COLUMN(EnergyZNA, energyZNA, float); +DECLARE_SOA_COLUMN(EnergyZNC, energyZNC, float); +DECLARE_SOA_COLUMN(AmplitudeFV0A, amplitudeFV0A, float); +DECLARE_SOA_COLUMN(Occupancy, occupancy, float); +DECLARE_SOA_COLUMN(UPCMode, upcMode, float); DECLARE_SOA_COLUMN(PtSideA, ptSideA, std::vector); DECLARE_SOA_COLUMN(RapSideA, rapSideA, std::vector); DECLARE_SOA_COLUMN(PhiSideA, phiSideA, std::vector); @@ -71,6 +84,19 @@ DECLARE_SOA_COLUMN(NchSideC, nchSideC, int); DECLARE_SOA_COLUMN(MultiplicitySideC, multiplicitySideC, int); } // namespace tree DECLARE_SOA_TABLE(TREE, "AOD", "Tree", + tree::GapSide, + tree::GapSideTimeZN, + tree::Sbp, + tree::ITSROFb, + tree::VtxITSTPCCut, + tree::ZVtxFT0vsPvCut, + tree::TimeZNA, + tree::TimeZNC, + tree::EnergyZNA, + tree::EnergyZNC, + tree::AmplitudeFV0A, + tree::Occupancy, + tree::UPCMode, tree::PtSideA, tree::RapSideA, tree::PhiSideA, @@ -117,17 +143,35 @@ struct UpcPhotonuclearAnalysisJMG { Configurable nEventsMixed{"nEventsMixed", 3, {"Events to be Mixed"}}; Configurable factorEventsMixed{"factorEventsMixed", 100, {"factorEventsMixed to events mixed"}}; Configurable myZVtxCut{"myZVtxCut", 10., {"My collision cut"}}; - Configurable myTimeZNACut{"myTimeZNACut", 2., {"My collision cut"}}; - Configurable myTimeZNCCut{"myTimeZNCCut", 2., {"My collision cut"}}; + Configurable useSBP{"useSBP", false, {"My collision cut"}}; + Configurable sbpCut{"sbpCut", 1, {"My collision cut"}}; + Configurable useITSROFb{"useITSROFb", false, {"My collision cut"}}; + Configurable itsROFbCut{"itsROFbCut", 1, {"My collision cut"}}; + Configurable useVtxITSTPC{"useVtxITSTPC", false, {"My collision cut"}}; + Configurable vtxITSTPCCut{"vtxITSTPCCut", 1, {"My collision cut"}}; + Configurable useZVtxFT0vsPv{"useZVtxFT0vsPv", false, {"My collision cut"}}; + Configurable zVtxFT0vsPvCut{"zVtxFT0vsPvCut", 1, {"My collision cut"}}; + Configurable useEnergyZN{"useEnergyZN", false, {"My collision cut"}}; + Configurable useGapSideVariable{"useGapSideVariable", false, {"My collision cut"}}; + Configurable useUPCMode{"useUPCMode", false, {"My collision cut"}}; + Configurable upcModeCut{"upcModeCut", 1, {"My collision cut"}}; + Configurable useOccupancy{"useOccupancy", false, {"My collision cut"}}; + Configurable cutOccupancy{"cutOccupancy", 1000, {"My collision cut"}}; // Declare configurables on side A gap - Configurable cutGapAMyEnergyZNA{"cutGapAMyEnergyZNA", 0., {"My collision cut. A Gap"}}; + Configurable cutGapATimeZNA{"cutGapATimeZNA", 2., {"My collision cut. Gap Side A"}}; + Configurable cutGapATimeZNC{"cutGapATimeZNC", 2., {"My collision cut. Gap Side A"}}; + Configurable cutGapAMyEnergyZNA{"cutGapAMyEnergyZNA", 0., {"My collision cut. Gap Side A"}}; // Configurable cutAGapMyAmplitudeFT0AMax{"cutAGapMyAmplitudeFT0AMax", 200., {"My collision cut. A Gap"}}; - Configurable cutGapAMyEnergyZNC{"cutGapAMyEnergyZNC", 1., {"My collision cut. A Gap"}}; + Configurable cutGapAMyEnergyZNC{"cutGapAMyEnergyZNC", 1., {"My collision cut. Gap Side A"}}; + Configurable useFV0{"useFV0", false, {"My collision cut. Gap Side A"}}; + Configurable cutGapAFV0Amplitude{"cutGapAFV0Amplitude", 50, {"My collision cut. Gap Side A"}}; // Configurable cutAGapMyAmplitudeFT0CMin{"cutAGapMyAmplitudeFT0CMin", 0., {"My collision cut. A Gap"}}; // Declare configurables on side C gap - Configurable cutGapCMyEnergyZNA{"cutGapCMyEnergyZNA", 1., {"My collision cut. C Gap"}}; + Configurable cutGapCTimeZNA{"cutGapCTimeZNA", 2., {"My collision cut. Gap Side C"}}; + Configurable cutGapCTimeZNC{"cutGapCTimeZNC", 2., {"My collision cut. Gap Side C"}}; + Configurable cutGapCMyEnergyZNA{"cutGapCMyEnergyZNA", 1., {"My collision cut. Gap Side C"}}; // Configurable cutCGapMyAmplitudeFT0AMin{"cutCGapMyAmplitudeFT0AMin", 0., {"My collision cut. A Gap"}}; - Configurable cutGapCMyEnergyZNC{"cutGapCMyEnergyZNC", 0., {"My collision cut. C Gap"}}; + Configurable cutGapCMyEnergyZNC{"cutGapCMyEnergyZNC", 0., {"My collision cut. Gap Side C"}}; // Configurable cutCGapMyAmplitudeFT0CMax{"cutCGapMyAmplitudeFT0CMax", 200., {"My collision cut. A Gap"}}; // Declare configurables on tracks Configurable cutMyptMin{"cutMyptMin", 0.2, {"My Track cut"}}; @@ -147,11 +191,6 @@ struct UpcPhotonuclearAnalysisJMG { Configurable cutMyTPCNClsCrossedRowsOverNClsFindableMin{"cutMyTPCNClsCrossedRowsOverNClsFindableMin", 0.8f, {"My Track cut"}}; Configurable cutMyTPCNClsOverFindableNClsMin{"cutMyTPCNClsOverFindableNClsMin", 0.5f, {"My Track cut"}}; Configurable cutMyTPCChi2NclMax{"cutMyTPCChi2NclMax", 4.f, {"My Track cut"}}; - Configurable myWeightMin{"myWeightMin", 0.2f, {"My Track cut"}}; - Configurable myWeightMax{"myWeightMax", 5.f, {"My Track cut"}}; - Configurable myEpsilonToWeight{"myEpsilonToWeight", 1e-6f, {"NUA correction"}}; - Configurable useEpsilon{"useEpsilon", false, {"NUA correction"}}; - Configurable useNMax{"useNMax", true, {"NUA correction"}}; Configurable> cfgPairCut{"cfgPairCut", {CFGPairCutDefaults[0], 5, @@ -168,12 +207,13 @@ struct UpcPhotonuclearAnalysisJMG { ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {20, -1.0, 1.0}, "eta axis for efficiency histograms"}; ConfigurableAxis axisPtEfficiency{"axisPtEfficiency", {VARIABLE_WIDTH, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0}, "pt axis for efficiency histograms"}; - Filter collisionZVtxFilter = nabs(aod::collision::posZ) < myZVtxCut; - Filter collisionZNTimeFilter = nabs(aod::udzdc::timeZNA) < myTimeZNACut && nabs(aod::udzdc::timeZNC) < myTimeZNCCut; - Filter collisionZNeEnergyFilter = (aod::udzdc::energyCommonZNA < cutGapAMyEnergyZNA && aod::udzdc::energyCommonZNC >= cutGapAMyEnergyZNC) || (aod::udzdc::energyCommonZNA >= cutGapCMyEnergyZNA && aod::udzdc::energyCommonZNC < cutGapCMyEnergyZNC); - Filter collisioSGFilter = aod::udcollision::gapSide == uint8_t(0) || aod::udcollision::gapSide == uint8_t(1); + // Filter collisionZVtxFilter = nabs(aod::collision::posZ) < myZVtxCut; + // Filter collisionZNTimeFilterGapA = (nabs(aod::udzdc::timeZNA) > cutGapATimeZNA && nabs(aod::udzdc::timeZNC) < cutGapATimeZNC) || (nabs(aod::udzdc::timeZNA) < cutGapCTimeZNA && nabs(aod::udzdc::timeZNC) > cutGapCTimeZNC); + // Filter collisionZNeEnergyFilter = (aod::udzdc::energyCommonZNA < cutGapAMyEnergyZNA && aod::udzdc::energyCommonZNC >= cutGapAMyEnergyZNC) || (aod::udzdc::energyCommonZNA >= cutGapCMyEnergyZNA && aod::udzdc::energyCommonZNC < cutGapCMyEnergyZNC); + // Filter collisioSGFilter = aod::udcollision::gapSide == uint8_t(0) || aod::udcollision::gapSide == uint8_t(1); - using FullSGUDCollision = soa::Filtered>; + // using FullSGUDCollision = soa::Filtered>; + using FullSGUDCollision = soa::Join; using FullUDTracks = soa::Join; // Output definitions @@ -190,6 +230,7 @@ struct UpcPhotonuclearAnalysisJMG { void init(InitContext const&) { const AxisSpec axisCollision{4, -0.5, 3.5}; + const AxisSpec axisCollisionFlow{12, -0.5, 11.5}; const AxisSpec axisZvtx{20, -10., 10.}; const AxisSpec axisPt{402, -0.05, 20.05}; const AxisSpec axisP{402, -10.05, 10.05}; @@ -235,6 +276,7 @@ struct UpcPhotonuclearAnalysisJMG { } histos.add("Events/hCountCollisions", "0 total - 1 side A - 2 side C - 3 both side; Number of analysed collision; counts", kTH1F, {axisCollision}); histos.add("Events/hCountCollisionsMixed", "0 total - 1 side A - 2 side C - 3 both side; Number of analysed collision; counts", kTH1F, {axisCollision}); + histos.add("Events/hCollisionsFlow", "; ; counts", kTH1F, {axisCollisionFlow}); histos.add("Tracks/hTracksAfterCuts", " ; ; counts", kTH1F, {axisCountTracks}); // histos to selection gap in side A @@ -322,9 +364,9 @@ struct UpcPhotonuclearAnalysisJMG { std::vector vtxBinsEdges{VARIABLE_WIDTH, -10.0f, -7.0f, -5.0f, -2.5f, 0.0f, 2.5f, 5.0f, 7.0f, 10.0f}; std::vector gapSideBinsEdges{VARIABLE_WIDTH, -0.5, 0.5, 1.5}; - struct SameEventTag { - }; - struct MixedEventTag { + enum EventType { + SameEvent = 1, + MixedEvent = 2 }; SliceCache cache; @@ -333,27 +375,65 @@ struct UpcPhotonuclearAnalysisJMG { // int countGapC = 0; // Binning only on PosZ without multiplicity - using BinningType = ColumnBinningPolicy; + // using BinningType = ColumnBinningPolicy; // BinningType bindingOnVtx{{vtxBinsEdges, gapSideBinsEdges}, true}; - // using BinningType = ColumnBinningPolicy; + using BinningType = ColumnBinningPolicy; // BinningType bindingOnVtx{{vtxBinsEdges}, true}; // SameKindPair pairs{bindingOnVtx, nEventsMixed, -1, &cache}; template bool isCollisionCutSG(CSG const& collision, int SideGap) { - bool gapSideA = (collision.energyCommonZNA() < cutGapAMyEnergyZNA) && (collision.energyCommonZNC() >= cutGapAMyEnergyZNC); - bool gapSideC = (collision.energyCommonZNA() >= cutGapCMyEnergyZNA) && (collision.energyCommonZNC() < cutGapCMyEnergyZNC); + if (std::abs(collision.posZ()) > myZVtxCut) { + return false; + } + if (useSBP && collision.sbp() != sbpCut) { + return false; + } + if (useITSROFb && collision.itsROFb() != itsROFbCut) { + return false; + } + if (useVtxITSTPC && collision.vtxITSTPC() != vtxITSTPCCut) { + return false; + } + if (useZVtxFT0vsPv && collision.zVtxFT0vPV() != zVtxFT0vsPvCut) { + return false; + } + if (useOccupancy && collision.occupancyInTime() > cutOccupancy) { + return false; + } + if (useUPCMode && collision.flags() != upcModeCut) { + return false; + } switch (SideGap) { - case 0: // Gap in A side - return gapSideA; // 0n - A side && Xn - C Side + case 0: // Gap in A side + if (!(std::abs(collision.timeZNA()) > cutGapATimeZNA && std::abs(collision.timeZNC()) < cutGapATimeZNC)) { + return false; + } + if (useEnergyZN && ((collision.energyCommonZNA() < cutGapAMyEnergyZNA) && (collision.energyCommonZNC() >= cutGapAMyEnergyZNC))) { + return false; + } // 0n - A side && Xn - C Side + if (useGapSideVariable && collision.gapSide() != uint8_t(0)) { + return false; + } + if (useFV0 && collision.totalFV0AmplitudeA() > cutGapAFV0Amplitude) { + return false; + } // if ((collision.totalFT0AmplitudeA() < cutAGapMyAmplitudeFT0AMax && collision.totalFT0AmplitudeC() >= cutAGapMyAmplitudeFT0CMin) == false) { // return false; // } break; - case 1: // Gap in C side - return gapSideC; // Xn - A side && 0n - C Side + case 1: // Gap in C side + if (!(std::abs(collision.timeZNA()) < cutGapCTimeZNA && std::abs(collision.timeZNC()) > cutGapCTimeZNC)) { + return false; + } + if (useEnergyZN && ((collision.energyCommonZNA() >= cutGapCMyEnergyZNA) && (collision.energyCommonZNC() < cutGapCMyEnergyZNC))) { + return false; + } // Xn - A side && 0n - C Side + if (useGapSideVariable && collision.gapSide() != uint8_t(1)) { + return false; + } // if ((collision.totalFT0AmplitudeA() >= cutCGapMyAmplitudeFT0AMin && collision.totalFT0AmplitudeC() < cutCGapMyAmplitudeFT0CMax) == false) { // return false; // } @@ -362,12 +442,15 @@ struct UpcPhotonuclearAnalysisJMG { return false; break; } + return true; } template bool isCollisionCutSG(CSG const& collision) { - return isCollisionCutSG(collision, 0) || isCollisionCutSG(collision, 1); + bool passGapA = isCollisionCutSG(collision, 0); + bool passGapC = isCollisionCutSG(collision, 1); + return passGapA || passGapC; } template @@ -455,8 +538,8 @@ struct UpcPhotonuclearAnalysisJMG { return true; } - template - void fillCorrelationsUD(TTarget target, const TTracks& tracks1, const TTracks& tracks2, float multiplicity, float posZ, TTag) + template + void fillCorrelationsUD(TTarget target, const TTracks& tracks1, const TTracks& tracks2, float multiplicity, float posZ, int system) { for (const auto& track1 : tracks1) { if (isTrackCut(track1) == false) { @@ -488,7 +571,7 @@ struct UpcPhotonuclearAnalysisJMG { multiplicity, deltaPhi, posZ); - if constexpr (std::is_same_v) { + if (system == SameEvent) { if (minMultiplicity <= multiplicity) { histos.fill(HIST("sameEvent2D"), deltaEta, deltaPhi); } @@ -507,7 +590,7 @@ struct UpcPhotonuclearAnalysisJMG { if (range5Min <= multiplicity && multiplicity <= range5Max) { histos.fill(HIST("sameEvent_41_50"), deltaEta, deltaPhi); } - } else if constexpr (std::is_same_v) { + } else if (system == MixedEvent) { if (minMultiplicity <= multiplicity) { histos.fill(HIST("mixedEvent2D"), deltaEta, deltaPhi); } @@ -535,6 +618,7 @@ struct UpcPhotonuclearAnalysisJMG { { histos.fill(HIST("Events/hCountCollisions"), 0); int sgSide = reconstructedCollision.gapSide(); + int sgSideTimeZN = -1; int nTracksCharged = 0; float sumPt = 0; int nchPVGapSideA = 0; @@ -546,7 +630,6 @@ struct UpcPhotonuclearAnalysisJMG { int nTracksChargedSideA(-222), nTracksChargedSideC(-222); int multiplicitySideA(-222), multiplicitySideC(-222); - for (const auto& track : reconstructedTracks) { if (isTrackCut(track) == false) { continue; @@ -554,8 +637,16 @@ struct UpcPhotonuclearAnalysisJMG { float phiVal = RecoDecay::constrainAngle(phi(track.px(), track.py()), 0.f); histos.fill(HIST("etaphiVtx"), reconstructedCollision.posZ(), eta(track.px(), track.py(), track.pz()), phiVal); } + bool isGapATimeZN = (std::abs(reconstructedCollision.timeZNA()) > cutGapATimeZNA) && (std::abs(reconstructedCollision.timeZNC()) < cutGapATimeZNC); + bool isGapCTimeZN = (std::abs(reconstructedCollision.timeZNA()) < cutGapCTimeZNA) && (std::abs(reconstructedCollision.timeZNC()) > cutGapCTimeZNC); + if (isGapATimeZN) { + sgSideTimeZN = 0; + } + if (isGapCTimeZN) { + sgSideTimeZN = 1; + } - switch (sgSide) { + switch (sgSideTimeZN) { case 0: // gap for side A if (isCollisionCutSG(reconstructedCollision, 0) == false) { return; @@ -681,7 +772,41 @@ struct UpcPhotonuclearAnalysisJMG { return; break; } - tree(vTrackPtSideA, vTrackEtaSideA, vTrackPhiSideA, vTrackTPCSignalSideA, vTrackTOFSignalSideA, vTrackTPCNSigmaPiSideA, vTrackTOFNSigmaPiSideA, vTrackTPCNSigmaKaSideA, vTrackTOFNSigmaKaSideA, vTrackPtSideC, vTrackEtaSideC, vTrackPhiSideC, vTrackTPCSignalSideA, vTrackTOFSignalSideA, vTrackTPCNSigmaPiSideA, vTrackTOFNSigmaPiSideA, vTrackTPCNSigmaKaSideA, vTrackTOFNSigmaKaSideA, nTracksChargedSideA, multiplicitySideA, nTracksChargedSideC, multiplicitySideC); + tree(sgSide, + sgSideTimeZN, + reconstructedCollision.sbp(), + reconstructedCollision.itsROFb(), + reconstructedCollision.vtxITSTPC(), + reconstructedCollision.zVtxFT0vPV(), + reconstructedCollision.timeZNA(), + reconstructedCollision.timeZNC(), + reconstructedCollision.energyCommonZNA(), + reconstructedCollision.energyCommonZNC(), + reconstructedCollision.totalFV0AmplitudeA(), + reconstructedCollision.occupancyInTime(), + reconstructedCollision.flags(), + vTrackPtSideA, + vTrackEtaSideA, + vTrackPhiSideA, + vTrackTPCSignalSideA, + vTrackTOFSignalSideA, + vTrackTPCNSigmaPiSideA, + vTrackTOFNSigmaPiSideA, + vTrackTPCNSigmaKaSideA, + vTrackTOFNSigmaKaSideA, + vTrackPtSideC, + vTrackEtaSideC, + vTrackPhiSideC, + vTrackTPCSignalSideA, + vTrackTOFSignalSideA, + vTrackTPCNSigmaPiSideA, + vTrackTOFNSigmaPiSideA, + vTrackTPCNSigmaKaSideA, + vTrackTOFNSigmaKaSideA, + nTracksChargedSideA, + multiplicitySideA, + nTracksChargedSideC, + multiplicitySideC); // nTracksChargedSideA = nTracksChargedSideC = multiplicitySideA = multiplicitySideC = 0; } @@ -693,21 +818,8 @@ struct UpcPhotonuclearAnalysisJMG { // int sgSide = reconstructedCollision.gapSide(); // int sgSide = 0; - // int maxCount = 0; - // int maxCountGapA = 0; - // int maxCountGapC = 0; - - // if (auto histEventCount = histos.get(HIST("eventcount"))) { - // int binA = histEventCount->GetXaxis()->FindBin(-2); Gap A - // int binC = histEventCount->GetXaxis()->FindBin(-1); Gap C - - // maxCount = histEventCount->GetBinContent(binA) * factorEventsMixed; - // maxCountGapA = histEventCount->GetBinContent(binA) * factorEventsMixed; - // maxCountGapC = histEventCount->GetBinContent(binC) * factorEventsMixed; - // } - - BinningType bindingOnVtx{{vtxBinsEdges, gapSideBinsEdges}, true}; - // BinningType bindingOnVtx{{vtxBinsEdges}, true}; + // BinningType bindingOnVtx{{vtxBinsEdges, gapSideBinsEdges}, true}; + BinningType bindingOnVtx{{vtxBinsEdges}, true}; auto tracksTuple = std::make_tuple(reconstructedTracks); SameKindPair pairs{bindingOnVtx, nEventsMixed, -1, reconstructedCollision, tracksTuple, &cache}; @@ -717,10 +829,6 @@ struct UpcPhotonuclearAnalysisJMG { continue; } - // if (countGapA >= maxCountGapA && countGapC >= maxCountGapC) { - // break; - // } - float multiplicity = 0; histos.fill(HIST("Events/hCountCollisionsMixed"), 0); @@ -744,42 +852,7 @@ struct UpcPhotonuclearAnalysisJMG { histos.fill(HIST("Events/hCountCollisionsMixed"), 2); // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ()})); // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ(), collision1.gapSide()})); - fillCorrelationsUD(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), MixedEventTag{}); - // LOGF(info, "Filling mixed events"); - - // if (collision1.gapSide() == 0 && collision2.gapSide() == 0) { gap on side A - // if (isCollisionCutSG(collision1, 0) == false && isCollisionCutSG(collision2, 0) == false) { - // continue; - // } - // std::cout << "Counts for Gap A: " << countGapA << " Maximum Count for Gap A " << maxCountGapA << std::endl; - // ++countGapA; - // LOGF(info, "In the pairs loop, gap side A"); - // multiplicity = tracks1.size(); - // if (fillCollisionUD(mixedGapSideA, multiplicity) == false) { - // return; - // } - // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ()})); - // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ(), collision1.gapSide()})); - // fillCorrelationsUD(mixedGapSideA, tracks1, tracks2, multiplicity, collision1.posZ()); - // LOGF(info, "Filling mixedGapSideA events, Gap for side A"); - // } - - // if (collision1.gapSide() == 1 && collision2.gapSide() == 1) { gap on side C - // if (isCollisionCutSG(collision1, 1) == false && isCollisionCutSG(collision2, 1) == false) { - // continue; - // } - // std::cout << "Counts for Gap C: " << countGapC << " Maximum Count for Gap C" << maxCountGapC << std::endl; - // ++countGapC; - // LOGF(info, "In the pairs loop, gap side C"); - // multiplicity = tracks1.size(); - // if (fillCollisionUD(mixedGapSideC, multiplicity) == false) { - // return; - // } - // fillCorrelationsUD(mixedGapSideC, tracks1, tracks2, multiplicity, collision1.posZ()); - // LOGF(info, "Filling mixedGapSideC events, Gap for side C"); - // } else { - // continue; - // } + fillCorrelationsUD(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), MixedEvent); } } @@ -790,6 +863,73 @@ struct UpcPhotonuclearAnalysisJMG { // int sgSide = reconstructedCollision.gapSide(); float multiplicity = 0; + auto hEventFlow = histos.get(HIST("Events/hCollisionsFlow")); + hEventFlow->GetXaxis()->SetBinLabel(1, "All events"); + hEventFlow->GetXaxis()->SetBinLabel(2, "Z Vtx"); + hEventFlow->GetXaxis()->SetBinLabel(3, "SBP"); + hEventFlow->GetXaxis()->SetBinLabel(4, "ITS ROFb"); + hEventFlow->GetXaxis()->SetBinLabel(5, "Vtx ITS-TPC"); + hEventFlow->GetXaxis()->SetBinLabel(6, "Z Vtx FT0vsPv"); + hEventFlow->GetXaxis()->SetBinLabel(7, "Occupancy"); + hEventFlow->GetXaxis()->SetBinLabel(8, "UPC Mode"); + hEventFlow->GetXaxis()->SetBinLabel(9, "Time ZN"); + hEventFlow->GetXaxis()->SetBinLabel(10, "Energy ZN"); + hEventFlow->GetXaxis()->SetBinLabel(11, "FV0-A Amplitude"); + hEventFlow->GetXaxis()->SetBinLabel(12, "GapSide Variable"); + + histos.fill(HIST("Events/hCollisionsFlow"), 0); + if (std::abs(reconstructedCollision.posZ()) > myZVtxCut) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 1); + if (useSBP && reconstructedCollision.sbp() != sbpCut) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 2); + if (useITSROFb && reconstructedCollision.itsROFb() != itsROFbCut) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 3); + if (useVtxITSTPC && reconstructedCollision.vtxITSTPC() != vtxITSTPCCut) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 4); + if (useZVtxFT0vsPv && reconstructedCollision.zVtxFT0vPV() != zVtxFT0vsPvCut) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 5); + if (useOccupancy && reconstructedCollision.occupancyInTime() > cutOccupancy) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 6); + if (useUPCMode && reconstructedCollision.flags() != 1) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 7); + bool isGapATimeZN = (std::abs(reconstructedCollision.timeZNA()) > cutGapATimeZNA) && (std::abs(reconstructedCollision.timeZNC()) < cutGapATimeZNC); + bool isGapCTimeZN = (std::abs(reconstructedCollision.timeZNA()) < cutGapCTimeZNA) && (std::abs(reconstructedCollision.timeZNC()) > cutGapCTimeZNC); + if (!(isGapATimeZN || isGapCTimeZN)) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 8); + + bool isGapAMyEnergyZN = useEnergyZN && ((reconstructedCollision.energyCommonZNA() < cutGapAMyEnergyZNA) && (reconstructedCollision.energyCommonZNC() >= cutGapAMyEnergyZNC)); + bool isGapCMyEnergyZN = useEnergyZN && ((reconstructedCollision.energyCommonZNA() >= cutGapCMyEnergyZNA) && (reconstructedCollision.energyCommonZNC() < cutGapCMyEnergyZNC)); + if (isGapAMyEnergyZN || isGapCMyEnergyZN) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 9); + if (isGapATimeZN && useFV0 && reconstructedCollision.totalFV0AmplitudeA() > cutGapAFV0Amplitude) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 10); + bool cutGapSideAVariable = useGapSideVariable && reconstructedCollision.gapSide() != uint8_t(0); + bool cutGapSideCVariable = useGapSideVariable && reconstructedCollision.gapSide() != uint8_t(1); + if (cutGapSideAVariable || cutGapSideCVariable) { + return; + } + histos.fill(HIST("Events/hCollisionsFlow"), 11); + if (isCollisionCutSG(reconstructedCollision) == false) { return; } @@ -914,38 +1054,7 @@ struct UpcPhotonuclearAnalysisJMG { histos.fill(HIST("eventcount"), 5); } fillQAUD(reconstructedTracks, multiplicity); - fillCorrelationsUD(same, reconstructedTracks, reconstructedTracks, multiplicity, reconstructedCollision.posZ(), SameEventTag{}); - - /*switch (sgSide) { - case 0: // gap for side A - if (isCollisionCutSG(reconstructedCollision, 0) == false) { - return; - } - multiplicity = reconstructedTracks.size(); - if (fillCollisionUD(sameGapSideA, multiplicity) == false) { - return; - } - LOGF(info, "Filling sameGapSideA events"); - histos.fill(HIST("eventcount"), -2); - fillQAUD(reconstructedTracks); - fillCorrelationsUD(sameGapSideA, reconstructedTracks, reconstructedTracks, multiplicity, reconstructedCollision.posZ()); - break; - case 1: // gap for side C - if (isCollisionCutSG(reconstructedCollision, 1) == false) { - return; - } - multiplicity = reconstructedTracks.size(); - if (fillCollisionUD(sameGapSideC, multiplicity) == false) { - return; - } - histos.fill(HIST("eventcount"), -1); - // LOGF(info, "Filling sameGapSideC events"); - fillCorrelationsUD(sameGapSideC, reconstructedTracks, reconstructedTracks, multiplicity, reconstructedCollision.posZ()); - break; - default: - return; - break; - }*/ + fillCorrelationsUD(same, reconstructedTracks, reconstructedTracks, multiplicity, reconstructedCollision.posZ(), SameEvent); } PROCESS_SWITCH(UpcPhotonuclearAnalysisJMG, processSame, "Process same event", true); diff --git a/Tutorials/CMakeLists.txt b/Tutorials/CMakeLists.txt index d99c71adc88..e99e99b9d9d 100644 --- a/Tutorials/CMakeLists.txt +++ b/Tutorials/CMakeLists.txt @@ -122,6 +122,11 @@ o2physics_add_dpl_workflow(ccdbaccess PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::CCDB O2::Framework O2Physics::AnalysisCore COMPONENT_NAME AnalysisTutorial) +o2physics_add_dpl_workflow(ccdbtableaccess + SOURCES src/ccdbtableaccess.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::CCDB O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + o2physics_add_dpl_workflow(weak-decay-iteration SOURCES src/weakDecayIteration.cxx COMPONENT_NAME AnalysisTutorial) diff --git a/Tutorials/src/ccdbtableaccess.cxx b/Tutorials/src/ccdbtableaccess.cxx new file mode 100644 index 00000000000..52688bcebfc --- /dev/null +++ b/Tutorials/src/ccdbtableaccess.cxx @@ -0,0 +1,66 @@ +// 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 A tutorial task to retrieve objects from CCDB given a time stamp. +/// \author Daiki Sekihata +/// \since 2026-03-01 + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include + +using namespace o2::framework; +using namespace o2::header; +using namespace o2; + +namespace o2::aod +{ +namespace testccdb +{ +DECLARE_SOA_CCDB_COLUMN(GRPMagField, grpMagField, o2::parameters::GRPMagField, "GLO/Config/GRPMagField"); //! +DECLARE_SOA_CCDB_COLUMN(MeanVertex, meanVertex, o2::dataformats::MeanVertexObject, "GLO/Calib/MeanVertex"); //! +} // namespace testccdb + +DECLARE_SOA_TIMESTAMPED_TABLE(MyCCDBObjects, aod::Timestamps, o2::aod::timestamp::Timestamp, 1, "MYCCDBOBJ", //! + testccdb::GRPMagField, testccdb::MeanVertex); +} // namespace o2::aod + +struct TestCCDBTable { + void init(o2::framework::InitContext&) {} + + using MyBCs = soa::Join; + + void process(MyBCs const& bcs) + { + int i = 0; + for (const auto& bc : bcs) { + if (i >= 5) { + return; + } + float l3current = bc.grpMagField().getL3Current(); + float zvtx = bc.meanVertex().getZ(); + LOGF(info, "bc.globalBC() = %llu, bc.timestamp() = %llu, L3 current = %f A, mean zvtx = %f cm", bc.globalBC(), bc.timestamp(), l3current, zvtx); + i++; + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/cmake/O2PhysicsAddWorkflow.cmake b/cmake/O2PhysicsAddWorkflow.cmake index 39d98b2db76..d2d599c4406 100644 --- a/cmake/O2PhysicsAddWorkflow.cmake +++ b/cmake/O2PhysicsAddWorkflow.cmake @@ -47,7 +47,7 @@ function(o2physics_add_dpl_workflow baseTargetName) set_property(TARGET ${targetExeName} PROPERTY JOB_POOL_COMPILE analysis) set_property(TARGET ${targetExeName} PROPERTY JOB_POOL_LINK analysis) - if(A_REUSE_FROM) + if(A_REUSE_FROM AND NOT DEFINED ENV{USE_RECC}) target_precompile_headers(${targetExeName} REUSE_FROM ${A_REUSE_FROM}) endif()