From c1d708a29249a6681073b845780778a29f5d3909 Mon Sep 17 00:00:00 2001 From: Isabel Kantak Date: Fri, 20 Feb 2026 17:10:02 +0100 Subject: [PATCH 1/7] Add calculation of psipair and phiv at a propagated position from the photon conversion and save the values in the v0photonphivpsi table. Add histograms for ML cuts. --- PWGEM/PhotonMeson/DataModel/gammaTables.h | 11 +- .../TableProducer/photonconversionbuilder.cxx | 109 ++++++++++++++---- 2 files changed, 90 insertions(+), 30 deletions(-) diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index e1ca0cc8d54..f840f771db1 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -416,15 +416,16 @@ using EMPrimaryElectronsFromDalitz = EMPrimaryElectronsFromDalitz_001; // iterators using EMPrimaryElectronFromDalitz = EMPrimaryElectronsFromDalitz::iterator; -namespace v0photonsphiv +namespace v0photonsphivpsi { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! DECLARE_SOA_COLUMN(PhiV, phiv, float); //! -} // namespace v0photonsphiv -DECLARE_SOA_TABLE(V0PhotonsPhiV, "AOD", "V0PHOTONPHIV", //! - o2::soa::Index<>, v0photonsphiv::PhiV); +DECLARE_SOA_COLUMN(PsiPair, psipair, float); +} // namespace v0photonsphivpsi +DECLARE_SOA_TABLE(V0PhotonsPhiVPsi, "AOD", "V0PHOTONPHIVPSI", //! + o2::soa::Index<>, v0photonsphivpsi::PhiV, v0photonsphivpsi::PsiPair); // iterators -using V0PhotonsPhiV = V0PhotonsPhiV; +using V0PhotonsPhiVPsi = V0PhotonsPhiVPsi; namespace dalitzee { diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index 227ffe00564..a6716ecb72f 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -98,7 +98,7 @@ struct PhotonConversionBuilder { Produces v0legs; Produces v0legsXYZ; Produces v0legsDeDxMC; - Produces v0photonsphiv; + Produces v0photonsphivpsi; // Produces v0photonskfcov; // Produces events_ngpcm; @@ -165,7 +165,7 @@ struct PhotonConversionBuilder { Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; Configurable nClassesPCMMl{"nClassesPCMMl", static_cast(o2::analysis::em_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; - Configurable centTypePCMMl{"centTypePCMMl", "CentFT0C", "Centrality type for 2D ML application: CentFT0C, CentFT0M, or CentFT0A"}; + Configurable centTypePCMMl{"centTypePCMMl", 2, "Centrality type for 2D ML application: FT0M:0, FT0A:1, FT0C:2"}; Configurable> cutDirPCMMl{"cutDirPCMMl", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"path_ccdb/BDT_PCM/"}, "Paths of models on CCDB"}; @@ -176,8 +176,11 @@ struct PhotonConversionBuilder { Configurable> binsCentPCMMl{"binsCentPCMMl", std::vector{0.0, 100.0}, "Centrality bin limits for ML application"}; Configurable> cutsPCMMlFlat{"cutsPCMMlFlat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; + Configurable propV0LegsRadius{"propV0LegsRadius", 60.f, "Radius to which the V0 legs are propagated to calculate psipair and phiV"}; + o2::analysis::EmMlResponsePCM emMlResponse; std::vector outputML; + V0PhotonCandidate v0photoncandidate; o2::ccdb::CcdbApi ccdbApi; int mRunNumber; @@ -213,9 +216,7 @@ struct PhotonConversionBuilder { {"V0/hRxy_minX_ITSTPC_TPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, {"V0/hRxy_minX_TPC_TPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, {"V0/hPCA_diffX", "PCA vs. trackiu X - R_{xy};distance btween 2 legs (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{500, 0.0f, 5.f}, {100, -50.0, 50.0f}}}}, - {"V0/hPhiV", "#phi_{V}; #phi_{V} (rad.)", {HistType::kTH1F, {{500, 0.0f, o2::constants::math::TwoPI}}}}, - {"V0/hBDTvalueBeforeCutVsPt", "BDT response before cut vs pT; pT (GeV/c); BDT response", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}}, - {"V0/hBDTvalueAfterCutVsPt", "BDT response after cut vs pT; pT (GeV/c); BDT response", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}}, + {"V0/hPhiVPsiPair", "phiV vs. psi pair;#psi_{pair} (rad.);#phi_{V} (rad.)", {HistType::kTH2F, {{500, -o2::constants::math::PI, o2::constants::math::PI}, {500, 0.0f, o2::constants::math::TwoPI}}}}, {"V0Leg/hPt", "pT of leg at SV;p_{T,e} (GeV/c)", {HistType::kTH1F, {{1000, 0.0f, 10.0f}}}}, {"V0Leg/hEtaPhi", "#eta vs. #varphi of leg at SV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, o2::constants::math::TwoPI}, {200, -1, +1}}}}, {"V0Leg/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, 0, 1}}}}, @@ -305,6 +306,22 @@ struct PhotonConversionBuilder { } emMlResponse.cacheInputFeaturesIndices(namesInputFeatures); emMlResponse.init(); + if (nClassesPCMMl == 2) { + registry.add("V0/hBDTBackgroundScoreBeforeCutVsPt", "BDT background score before cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTBackgroundScoreAfterCutVsPt", "BDT background score after cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSignalScoreBeforeCutVsPt", "BDT signal score before cut vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSignalScoreAfterCutVsPt", "BDT signal score after cut vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + } else if (nClassesPCMMl == 3) { + registry.add("V0/hBDTBackgroundScoreBeforeCutVsPt", "BDT background score before cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTBackgroundScoreAfterCutVsPt", "BDT background score after cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTPrimaryPhotonScoreBeforeCutVsPt", "BDT primary photon score before cut vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTPrimaryPhotonScoreAfterCutVsPt", "BDT primary photon score after cut vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSecondaryPhotonScoreBeforeCutVsPt", "BDT secondary photon score before cut vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSecondaryPhotonScoreAfterCutVsPt", "BDT secondary photon score after cut vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + } else { + registry.add("V0/hBDTScoreBeforeCutVsPt", "BDT score before cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTScoreAfterCutVsPt", "BDT score after cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + } } } @@ -468,17 +485,17 @@ struct PhotonConversionBuilder { return cospaRZ; } - template - void fillTrackTable(TTrack const& track, TShiftedTrack const& shiftedtrack, TKFParticle const& kfp, const float dcaXY, const float dcaZ) + template + void fillTrackTable(TTrack const& track, TShiftedTrack const& shiftedtrack, const float dcaXY, const float dcaZ) { v0legs(track.collisionId(), track.globalIndex(), track.sign(), - kfp.GetPx(), kfp.GetPy(), kfp.GetPz(), dcaXY, dcaZ, + shiftedtrack.GetPx(), shiftedtrack.GetPy(), shiftedtrack.GetPz(), dcaXY, dcaZ, track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), track.tpcChi2NCl(), track.tpcInnerParam(), track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap()); - v0legsXYZ(shiftedtrack.getX(), shiftedtrack.getY(), shiftedtrack.getZ()); + v0legsXYZ(shiftedtrack.GetX(), shiftedtrack.GetY(), shiftedtrack.GetZ()); if constexpr (isMC) { v0legsDeDxMC(track.mcTunedTPCSignal()); @@ -564,6 +581,37 @@ struct PhotonConversionBuilder { return; // RZ line cut } + float phiv = 999.f; + float psipair = 999.f; + float baseR = std::hypot(xyz[0], xyz[1]); + float offsetsR[3] = {propV0LegsRadius, 30.f, 10.f}; + bool pPropagatedSuccess = false; + bool nPropagatedSuccess = false; + auto pTrackProp = pTrack; + auto nTrackProp = nTrack; + for (float offsetR : offsetsR) { + pTrackProp = pTrack; + pTrackProp.setPID(o2::track::PID::Electron); + nTrackProp = nTrack; + nTrackProp.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo); + pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR); + nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR); + if (pPropagatedSuccess && nPropagatedSuccess) { + KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); + KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); + phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz(), pos.sign(), ele.sign(), d_bz); + psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz()); + break; + } else { + LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset."; + } + } + if (phiv == 999.f || psipair == 999.f) { + LOG(debug) << "Propagation failed for all radii ("<< propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f)."; + } + KFPTrack kfp_track_pos = createKFPTrackFromTrackParCov(pTrack, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); KFPTrack kfp_track_ele = createKFPTrackFromTrackParCov(nTrack, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); KFParticle kfp_pos(kfp_track_pos, kPositron); @@ -674,7 +722,8 @@ struct PhotonConversionBuilder { kfp_pos_DecayVtx.TransportToPoint(xyz); // Don't set Primary Vertex kfp_ele_DecayVtx.TransportToPoint(xyz); // Don't set Primary Vertex - V0PhotonCandidate v0photoncandidate(gammaKF_DecayVtx, kfp_pos_DecayVtx, kfp_ele_DecayVtx, collision, cospa_kf, d_bz); + CentType centType = static_cast(centTypePCMMl.value); + v0photoncandidate.setPhotonCandidate(gammaKF_DecayVtx, kfp_pos_DecayVtx, kfp_ele_DecayVtx, collision, cospa_kf, psipair, phiv, centType); if (!ele.hasITS() && !pos.hasITS()) { // V0s with TPConly-TPConly if (max_r_itsmft_ss < rxy && rxy < maxX + margin_r_tpc) { @@ -724,26 +773,36 @@ struct PhotonConversionBuilder { bool isSelectedML = false; std::vector mlInputFeatures = emMlResponse.getInputFeatures(v0photoncandidate, pos, ele); if (use2DBinning) { - if (std::string(centTypePCMMl) == "CentFT0C") { - isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCentFT0C(), outputML); - } else if (std::string(centTypePCMMl) == "CentFT0A") { - isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCentFT0A(), outputML); - } else if (std::string(centTypePCMMl) == "CentFT0M") { - isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCentFT0M(), outputML); - } else { - LOG(fatal) << "Unsupported centTypePCMMl: " << centTypePCMMl << " , please choose from CentFT0C, CentFT0A, CentFT0M."; - } + isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCent(), outputML); } else { isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), outputML); } if (filltable) { - registry.fill(HIST("V0/hBDTvalueBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + if (nClassesPCMMl == 2) { + registry.fill(HIST("V0/hBDTBackgroundScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSignalScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + } else if (nClassesPCMMl == 3) { + registry.fill(HIST("V0/hBDTPrimaryPhotonScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSecondaryPhotonScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + registry.fill(HIST("V0/hBDTBackgroundScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[2]); + } else { + registry.fill(HIST("V0/hBDTScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + } } if (!isSelectedML) { return; } if (filltable) { - registry.fill(HIST("V0/hBDTvalueAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + if (nClassesPCMMl == 2) { + registry.fill(HIST("V0/hBDTBackgroundScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSignalScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + } else if (nClassesPCMMl == 3) { + registry.fill(HIST("V0/hBDTPrimaryPhotonScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSecondaryPhotonScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + registry.fill(HIST("V0/hBDTBackgroundScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[2]); + } else { + registry.fill(HIST("V0/hBDTScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + } } } @@ -760,7 +819,7 @@ struct PhotonConversionBuilder { registry.fill(HIST("V0/hPCA_Rxy"), rxy, v0photoncandidate.getPCA()); registry.fill(HIST("V0/hDCAxyz"), v0photoncandidate.getDcaXYToPV(), v0photoncandidate.getDcaZToPV()); 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/hPhiV"), v0photoncandidate.getPhiV()); + 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); @@ -797,12 +856,12 @@ struct PhotonConversionBuilder { v0_sv.M(), v0photoncandidate.getDcaXYToPV(), v0photoncandidate.getDcaZToPV(), cospa_kf, cospaXY_kf, cospaRZ_kf, v0photoncandidate.getPCA(), v0photoncandidate.getAlpha(), v0photoncandidate.getQt(), v0photoncandidate.getChi2NDF()); - v0photonsphiv(v0photoncandidate.getPhiV()); + v0photonsphivpsi(v0photoncandidate.getPhiV(), v0photoncandidate.getPsiPair()); // v0photonskfcov(gammaKF_PV.GetCovariance(9), gammaKF_PV.GetCovariance(14), gammaKF_PV.GetCovariance(20), gammaKF_PV.GetCovariance(13), gammaKF_PV.GetCovariance(19), gammaKF_PV.GetCovariance(18)); - fillTrackTable(pos, pTrack, kfp_pos_DecayVtx, posdcaXY, posdcaZ); // positive leg first - fillTrackTable(ele, nTrack, kfp_ele_DecayVtx, eledcaXY, eledcaZ); // negative leg second + fillTrackTable(pos, kfp_pos_DecayVtx, posdcaXY, posdcaZ); // positive leg first + fillTrackTable(ele, kfp_ele_DecayVtx, eledcaXY, eledcaZ); // negative leg second } // end of fill table } From 6dc698131d359009dff83aa70c1f0d0b05a5048b Mon Sep 17 00:00:00 2001 From: Isabel Kantak Date: Fri, 20 Feb 2026 17:11:50 +0100 Subject: [PATCH 2/7] Update ML-based photon cuts to be able to get ML score in tasks. Update initialisation and filling of V0PhotonCandidate. --- PWGEM/PhotonMeson/Core/V0PhotonCandidate.h | 62 ++++++++++++++-------- PWGEM/PhotonMeson/Core/V0PhotonCut.cxx | 12 ++--- PWGEM/PhotonMeson/Core/V0PhotonCut.h | 49 ++++++++--------- 3 files changed, 72 insertions(+), 51 deletions(-) diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h index 2df1c5e08a1..07267a2d78f 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h @@ -23,11 +23,19 @@ #include +enum CentType : uint8_t { + CentFT0M = 0, + CentFT0A = 1, + CentFT0C = 2 +}; + struct V0PhotonCandidate { public: - // Constructor for photonconversionbuilder - V0PhotonCandidate(const KFParticle& v0, const KFParticle& pos, const KFParticle& ele, const auto& collision, float cospa, float d_bz) : cospa(cospa) + // 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) { px = v0.GetPx(); py = v0.GetPy(); @@ -57,18 +65,27 @@ struct V0PhotonCandidate { alpha = v0_alpha(posPx, posPy, posPz, elePx, elePy, elePz); qt = v0_qt(posPx, posPy, posPz, elePx, elePy, elePz); - int posSign = (pos.GetQ() > 0) - (pos.GetQ() < 0); - int eleSign = (ele.GetQ() > 0) - (ele.GetQ() < 0); - phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(posPx, posPy, posPz, elePx, elePy, elePz, posSign, eleSign, d_bz); - psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(posPx, posPy, posPz, elePx, elePy, elePz); - - centFT0M = collision.centFT0M(); - centFT0C = collision.centFT0C(); - centFT0A = collision.centFT0A(); + + this->cospa = cospa; + this->psipair = psipair; + this->phiv = phiv; + this->centType = centType; + + switch (centType) { + case CentType::CentFT0A: + cent = collision.centFT0A(); + break; + case CentType::CentFT0C: + cent = collision.centFT0C(); + break; + case CentType::CentFT0M: + cent = collision.centFT0M(); + break; + } } - // Constructor for V0PhotonCut - V0PhotonCandidate(const auto& v0, const auto& pos, const auto& ele, float centFT0A, float centFT0C, float centFT0M, float d_bz) : centFT0A(centFT0A), centFT0C(centFT0C), centFT0M(centFT0M) + // Set-Method for V0PhotonCut + void setPhoton(const auto& v0, const auto& pos, const auto& ele, float cent, CentType centType) { px = v0.px(); py = v0.py(); @@ -93,9 +110,14 @@ struct V0PhotonCandidate { cospa = v0.cospa(); alpha = v0.alpha(); qt = v0.qtarm(); - - phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(posPx, posPy, posPz, elePx, elePy, elePz, pos.sign(), ele.sign(), d_bz); - psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(posPx, posPy, posPz, elePx, elePy, elePz); + psipair = 999.f; // default if V0PhotonPhiVPsi table is not included + phiv = 999.f; // default if V0PhotonPhiVPsi table is not included + if constexpr( requires{ v0.psipair(); v0.phiv(); } ) { + psipair = v0.psipair(); + phiv = v0.phiv(); + } + this->cent = cent; + this->centType = centType; } // Getter functions @@ -119,10 +141,9 @@ struct V0PhotonCandidate { float getElePx() const { return elePx; } float getElePy() const { return elePy; } float getElePz() const { return elePz; } - float getCentFT0M() const { return centFT0M; } - float getCentFT0C() const { return centFT0C; } - float getCentFT0A() const { return centFT0A; } + float getCent() const { return cent; } float getPCA() const { return pca; } + CentType getCentType() const { return centType; } private: float px; @@ -145,10 +166,9 @@ struct V0PhotonCandidate { float psipair; float cospa; float chi2ndf; - float centFT0A; - float centFT0C; - float centFT0M; + float cent; float pca; + CentType centType; }; #endif // PWGEM_PHOTONMESON_CORE_V0PHOTONCANDIDATE_H_ diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx b/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx index 9c45ed9156c..5abc97c5d1c 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx @@ -306,20 +306,20 @@ void V0PhotonCut::SetCutsMl(const std::vector& cuts) void V0PhotonCut::SetNClassesMl(int nClasses) { mNClassesMl = nClasses; + mOutputML.reserve(mNClassesMl); LOG(info) << "V0 Photon Cut, set number of classes ML: " << mNClassesMl; } void V0PhotonCut::SetNamesInputFeatures(const std::vector& featureNames) { mNamesInputFeatures = featureNames; + mMlInputFeatures.reserve(mNamesInputFeatures.size()); LOG(info) << "V0 Photon Cut, set ML input feature names with size:" << mNamesInputFeatures.size(); } -void V0PhotonCut::SetCentrality(float centFT0A, float centFT0C, float centFT0M) +void V0PhotonCut::SetCentrality(float cent) { - mCentFT0A = centFT0A; - mCentFT0C = centFT0C; - mCentFT0M = centFT0M; + mCent = cent; } void V0PhotonCut::SetD_Bz(float d_bz) { @@ -332,10 +332,10 @@ void V0PhotonCut::SetCutDirMl(const std::vector& cutDirMl) LOG(info) << "V0 Photon Cut, set ML cut directions with size:" << mCutDirMl.size(); } -void V0PhotonCut::SetCentralityTypeMl(const std::string& centType) +void V0PhotonCut::SetCentralityTypeMl(CentType centType) { mCentralityTypeMl = centType; - LOG(info) << "V0 Photon Cut, set centrality type ML: " << mCentralityTypeMl; + LOG(info) << "V0 Photon Cut, set centrality type ML: " << mCentralityTypeMl << " (0: CentFT0M, 1: CentFT0A, 2: CentFT0C)"; } void V0PhotonCut::SetLabelsBinsMl(const std::vector& labelsBins) diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.h b/PWGEM/PhotonMeson/Core/V0PhotonCut.h index ba430be368b..4fb2c960ec6 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.h @@ -42,6 +42,7 @@ #include #include #include +#include namespace o2::analysis { @@ -144,7 +145,7 @@ static const std::vector labelsCent = { "Cent bin 10"}; // column labels -static const std::vector labelsCutScore = {"score primary photons", "score background"}; +static const std::vector labelsCutScore = {"score background", "score primary photons"}; } // namespace em_cuts_ml } // namespace o2::analysis @@ -573,30 +574,22 @@ class V0PhotonCut : public TNamed } } if (mApplyMlCuts) { - if (!mEmMlResponse) { + if (mEmMlResponse == nullptr) { LOG(error) << "EM ML Response is not initialized!"; return false; } - bool mIsSelectedMl = false; - std::vector mOutputML; - V0PhotonCandidate v0photoncandidate(v0, pos, ele, mCentFT0A, mCentFT0C, mCentFT0M, mD_Bz); - std::vector mlInputFeatures = mEmMlResponse->getInputFeatures(v0photoncandidate, pos, ele); + mIsSelectedMl = false; + mV0PhotonForMl.setPhoton(v0, pos, ele, mCent, mCentralityTypeMl); + mMlInputFeatures = mEmMlResponse->getInputFeatures(mV0PhotonForMl, pos, ele); if (mUse2DBinning) { - if (mCentralityTypeMl == "CentFT0C") { - mIsSelectedMl = mEmMlResponse->isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCentFT0C(), mOutputML); - } else if (mCentralityTypeMl == "CentFT0A") { - mIsSelectedMl = mEmMlResponse->isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCentFT0A(), mOutputML); - } else if (mCentralityTypeMl == "CentFT0M") { - mIsSelectedMl = mEmMlResponse->isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCentFT0M(), mOutputML); - } else { - LOG(fatal) << "Unsupported centTypePCMMl: " << mCentralityTypeMl << " , please choose from CentFT0C, CentFT0A, CentFT0M."; - } + mIsSelectedMl = mEmMlResponse->isSelectedMl(mMlInputFeatures, mV0PhotonForMl.getPt(), mV0PhotonForMl.getCent(), mOutputML); } else { - mIsSelectedMl = mEmMlResponse->isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), mOutputML); + mIsSelectedMl = mEmMlResponse->isSelectedMl(mMlInputFeatures, mV0PhotonForMl.getPt(), mOutputML); } if (!mIsSelectedMl) { return false; } + mMlBDTScores = std::span(mOutputML.data(), mOutputML.size()); } if (doQA) { fillAfterPhotonHistogram(v0, pos, ele, fRegistry); @@ -845,7 +838,7 @@ class V0PhotonCut : public TNamed void initV0MlModels(o2::ccdb::CcdbApi& ccdbApi) { - if (!mEmMlResponse) { + if (mEmMlResponse == nullptr) { mEmMlResponse = new o2::analysis::EmMlResponsePCM(); } if (mUse2DBinning) { @@ -899,6 +892,11 @@ class V0PhotonCut : public TNamed mEmMlResponse->init(); } + const std::span getBDTValue() const + { + return mMlBDTScores; + } + template bool IsConversionPointInAcceptance(TMCPhoton const& mcphoton, float convRadius) const { @@ -968,10 +966,10 @@ class V0PhotonCut : public TNamed void SetLoadMlModelsFromCCDB(bool flag = true); void SetNClassesMl(int nClasses); void SetMlTimestampCCDB(int timestamp); - void SetCentrality(float centFT0A, float centFT0C, float centFT0M); + void SetCentralityTypeMl(CentType centType); + void SetCentrality(float cent); void SetD_Bz(float d_bz); void SetCcdbUrl(const std::string& url = "http://alice-ccdb.cern.ch"); - void SetCentralityTypeMl(const std::string& centType); void SetCutDirMl(const std::vector& cutDirMl); void SetMlModelPathsCCDB(const std::vector& modelPaths); void SetMlOnnxFileNames(const std::vector& onnxFileNamesVec); @@ -1011,22 +1009,25 @@ class V0PhotonCut : public TNamed bool mLoadMlModelsFromCCDB{true}; int mTimestampCCDB{-1}; int mNClassesMl{static_cast(o2::analysis::em_cuts_ml::NCutScores)}; - float mCentFT0A{0.f}; - float mCentFT0C{0.f}; - float mCentFT0M{0.f}; + float mCent{0.f}; float mD_Bz{0.f}; std::string mCcdbUrl{"http://alice-ccdb.cern.ch"}; - std::string mCentralityTypeMl{"CentFT0C"}; std::vector mCutDirMl{std::vector{o2::analysis::em_cuts_ml::vecCutDir}}; std::vector mModelPathsCCDB{std::vector{"path_ccdb/BDT_PCM/"}}; std::vector mOnnxFileNames{std::vector{"ModelHandler_onnx_PCM.onnx"}}; std::vector mNamesInputFeatures{std::vector{"feature1", "feature2"}}; std::vector mLabelsBinsMl{std::vector{"bin 0", "bin 1"}}; - std::vector mLabelsCutScoresMl{std::vector{"score primary photons", "score background"}}; + std::vector mLabelsCutScoresMl{std::vector{o2::analysis::em_cuts_ml::labelsCutScore}}; std::vector mBinsPtMl{std::vector{o2::analysis::em_cuts_ml::vecBinsPt}}; std::vector mBinsCentMl{std::vector{o2::analysis::em_cuts_ml::vecBinsCent}}; std::vector mCutsMlFlat{std::vector{0.5}}; o2::analysis::EmMlResponsePCM* mEmMlResponse{nullptr}; + mutable bool mIsSelectedMl{false}; + mutable std::vector mOutputML{}; + mutable std::vector mMlInputFeatures{}; + mutable std::span mMlBDTScores{}; + CentType mCentralityTypeMl{CentType::CentFT0C}; + mutable V0PhotonCandidate mV0PhotonForMl; // pid cuts float mMinTPCNsigmaEl{-5}, mMaxTPCNsigmaEl{+5}; From cf548f3485035590d31bbf1ee101ad9dd698dbce Mon Sep 17 00:00:00 2001 From: Isabel Kantak Date: Fri, 20 Feb 2026 17:12:42 +0100 Subject: [PATCH 3/7] Add optional ML-based photon cuts to QC task --- PWGEM/PhotonMeson/Tasks/pcmQC.cxx | 178 ++++++++++++++++++++++++-- PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx | 190 +++++++++++++++++++++++++--- 2 files changed, 341 insertions(+), 27 deletions(-) diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 3f8130abe0d..eb45e61d764 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -25,6 +25,8 @@ #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include +#include +#include #include #include #include @@ -52,10 +54,18 @@ using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; using MyV0Photon = MyV0Photons::iterator; +using MyV0PhotonsML = soa::Join; +using MyV0PhotonML = MyV0PhotonsML::iterator; + struct PCMQC { Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + 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"}; EMPhotonEventCut fEMEventCut; struct : ConfigurableGroup { @@ -106,8 +116,28 @@ struct PCMQC { Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; 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_dEdx_postcalibration{"cfg_dEdx_postcalibration", false, "flag to enable dEdx post calibration"}; + // for ML cuts + Configurable cfg_apply_ml_cuts{"cfg_apply_ml", false, "flag to apply ML cut"}; + Configurable cfg_use_2d_binning{"cfg_use_2d_binning", false, "flag to use 2D binning (pT, cent)"}; + Configurable cfg_load_ml_models_from_ccdb{"cfg_load_ml_models_from_ccdb", true, "flag to load ML models from CCDB"}; + Configurable cfg_timestamp_ccdb{"cfg_timestamp_ccdb", -1, "timestamp for CCDB"}; + Configurable cfg_nclasses_ml{"cfg_nclasses_ml", static_cast(o2::analysis::em_cuts_ml::NCutScores), "number of classes for ML"}; + Configurable> cfg_cut_dir_ml{"cfg_cut_dir_ml", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "cut direction for ML"}; + Configurable> cfg_input_feature_names{"cfg_input_feature_names", std::vector{"feature1", "feature2"}, "input feature names for ML models"}; + Configurable> cfg_model_paths_ccdb{"cfg_model_paths_ccdb", std::vector{"path_ccdb/BDT_PCM/"}, "CCDB paths for ML models"}; + Configurable> cfg_onnx_file_names{"cfg_onnx_file_names", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for ML models"}; + Configurable> cfg_labels_bins_ml{"cfg_labels_bins_ml", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; + Configurable> cfg_labels_cut_scores_ml{"cfg_labels_cut_scores_ml", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; + Configurable> cfg_bins_pt_ml{"cfg_bins_pt_ml", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; + Configurable> cfg_bins_cent_ml{"cfg_bins_cent_ml", std::vector{o2::analysis::em_cuts_ml::vecBinsCent}, "centrality bins for ML"}; + Configurable> cfg_cuts_ml_flat{"cfg_cuts_ml_flat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; } pcmcuts; + o2::ccdb::CcdbApi ccdbApi; + o2::framework::Service ccdb; + int mRunNumber; + float d_bz; static constexpr std::string_view event_types[2] = {"before/", "after/"}; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; @@ -116,6 +146,54 @@ struct PCMQC { addhistograms(); DefineEMEventCut(); DefinePCMCut(); + + 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 (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"; + } + fV0PhotonCut.SetD_Bz(d_bz); + mRunNumber = collision.runNumber(); } void addhistograms() @@ -164,6 +242,22 @@ struct PCMQC { fRegistry.add("V0/hKFChi2vsZ", "KF chi2 vs. conversion point in Z;Z (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); fRegistry.add("V0/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, false); fRegistry.add("V0/hNgamma", "Number of #gamma candidates per collision", kTH1F, {{101, -0.5f, 100.5f}}); + + if (pcmcuts.cfg_apply_ml_cuts) { + if (pcmcuts.cfg_nclasses_ml == 2) { + fRegistry.add("V0/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + fRegistry.add("V0/hBDTSignalScoreVsPt", "BDT signal score vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + fRegistry.add("V0/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } else if (pcmcuts.cfg_nclasses_ml == 3) { + fRegistry.add("V0/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + fRegistry.add("V0/hBDTPrimaryPhotonScoreVsPt", "BDT primary photon score vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + fRegistry.add("V0/hBDTSecondaryPhotonScoreVsPt", "BDT secondary photon score vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + fRegistry.add("V0/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } else { + fRegistry.add("V0/hBDTScoreVsPt", "BDT score vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + fRegistry.add("V0/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } + } // v0leg info fRegistry.add("V0Leg/hPt", "pT;p_{T,e} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); @@ -183,7 +277,11 @@ struct PCMQC { fRegistry.add("V0Leg/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); fRegistry.add("V0Leg/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); fRegistry.add("V0Leg/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); - // fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {80, -20, 20}}, false); + if (pcmcuts.cfg_dEdx_postcalibration) { + fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Pos", "momentum of pos leg vs. conversion point of V0 vs. TPC n sigma pos vs. eta of pos leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); + fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Ele", "momentum of neg leg vs. conversion point of V0 vs. TPC n sigma el vs. eta of neg leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); + } + // fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {80, -20, 20}}, false); // fRegistry.add("V0Leg/hZX", "Z vs. X;Z (cm);X (cm)", kTH2F, {{200, -100, 100}, {100, 0, 100}}, false); // fRegistry.add("V0Leg/hZY", "Z vs. Y;Z (cm);Y (cm)", kTH2F, {{200, -100, 100}, {80, -20, 20}}, false); } @@ -235,6 +333,31 @@ struct PCMQC { fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + + // for ML + fV0PhotonCut.SetApplyMlCuts(pcmcuts.cfg_apply_ml_cuts); + fV0PhotonCut.SetUse2DBinning(pcmcuts.cfg_use_2d_binning); + fV0PhotonCut.SetLoadMlModelsFromCCDB(pcmcuts.cfg_load_ml_models_from_ccdb); + fV0PhotonCut.SetNClassesMl(pcmcuts.cfg_nclasses_ml); + fV0PhotonCut.SetMlTimestampCCDB(pcmcuts.cfg_timestamp_ccdb); + fV0PhotonCut.SetCcdbUrl(ccdburl); + CentType mCentralityTypeMlEnum; + mCentralityTypeMlEnum = static_cast(cfgCentEstimator.value); + fV0PhotonCut.SetCentralityTypeMl(mCentralityTypeMlEnum); + fV0PhotonCut.SetCutDirMl(pcmcuts.cfg_cut_dir_ml); + fV0PhotonCut.SetMlModelPathsCCDB(pcmcuts.cfg_model_paths_ccdb); + fV0PhotonCut.SetMlOnnxFileNames(pcmcuts.cfg_onnx_file_names); + fV0PhotonCut.SetBinsPtMl(pcmcuts.cfg_bins_pt_ml); + fV0PhotonCut.SetBinsCentMl(pcmcuts.cfg_bins_cent_ml); + fV0PhotonCut.SetCutsMl(pcmcuts.cfg_cuts_ml_flat); + fV0PhotonCut.SetNamesInputFeatures(pcmcuts.cfg_input_feature_names); + fV0PhotonCut.SetLabelsBinsMl(pcmcuts.cfg_labels_bins_ml); + fV0PhotonCut.SetLabelsCutScoresMl(pcmcuts.cfg_labels_cut_scores_ml); + fV0PhotonCut.SetD_Bz(0.0f); // dummy value -> only for psi_pair calculation + + if (pcmcuts.cfg_apply_ml_cuts) { + fV0PhotonCut.initV0MlModels(ccdbApi); + } } template @@ -302,6 +425,28 @@ struct PCMQC { o2::math_utils::bringTo02Pi(phi_cp); float eta_cp = std::atanh(v0.vz() / std::sqrt(std::pow(v0.vx(), 2) + std::pow(v0.vy(), 2) + std::pow(v0.vz(), 2))); fRegistry.fill(HIST("V0/hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); + + // BDT response histogram can be filled here when apply BDT is true + if (pcmcuts.cfg_apply_ml_cuts) { + const std::span& bdtValue = fV0PhotonCut.getBDTValue(); + float psipair = 999.f; + float phiv = 999.f; + if constexpr( requires{ v0.psipair(); v0.phiv(); } ) { + psipair = v0.psipair(); + phiv = v0.phiv(); + } + fRegistry.fill(HIST("V0/hPhiVPsi"), psipair, phiv); + if (pcmcuts.cfg_nclasses_ml == 2 && bdtValue.size() == 2) { + fRegistry.fill(HIST("V0/hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/hBDTSignalScoreVsPt"), v0.pt(), bdtValue[1]); + } else if (pcmcuts.cfg_nclasses_ml == 3 && bdtValue.size() == 3) { + fRegistry.fill(HIST("V0/hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/hBDTPrimaryPhotonScoreVsPt"), v0.pt(), bdtValue[1]); + fRegistry.fill(HIST("V0/hBDTSecondaryPhotonScoreVsPt"), v0.pt(), bdtValue[2]); + } else if (bdtValue.size() == 1) { + fRegistry.fill(HIST("V0/hBDTCutVsPt"), v0.pt(), bdtValue[0]); + } + } } template @@ -331,15 +476,17 @@ struct PCMQC { // fRegistry.fill(HIST("V0Leg/hZY"), leg.z(), leg.y()); } - Preslice perCollision = aod::v0photonkf::emeventId; + o2::framework::SliceCache v0cache; 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 processQC(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, aod::V0Legs const&) + template + void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const& v0legs) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { + initCCDB(collision); const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; @@ -353,11 +500,12 @@ struct PCMQC { fRegistry.fill(HIST("Event/before/hCollisionCounter"), 10.0); // accepted fRegistry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted + fV0PhotonCut.SetCentrality(centralities[cfgCentEstimator]); int nv0 = 0; - auto v0photons_coll = v0photons.sliceBy(perCollision, collision.globalIndex()); - for (auto& v0 : v0photons_coll) { - auto pos = v0.posTrack_as(); - auto ele = v0.negTrack_as(); + auto v0photons_coll = v0photons.sliceByCached(aod::v0photonkf::emeventId, collision.globalIndex(), v0cache); + for (const auto& v0 : v0photons_coll) { + auto pos = v0.template posTrack_as(); + auto ele = v0.template negTrack_as(); if (!fV0PhotonCut.IsSelected(v0)) { continue; @@ -366,15 +514,29 @@ struct PCMQC { for (auto& leg : {pos, ele}) { fillV0LegInfo(leg); } + if (pcmcuts.cfg_dEdx_postcalibration) { + fRegistry.fill(HIST("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Pos"), pos.p(), v0.v0radius(), pos.tpcNSigmaEl(), pos.eta()); + fRegistry.fill(HIST("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Ele"), ele.p(), v0.v0radius(), ele.tpcNSigmaEl(), ele.eta()); + } nv0++; } // end of v0 loop fRegistry.fill(HIST("V0/hNgamma"), nv0); } // end of collision loop + } + void processQC(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, aod::V0Legs const& v0legs) + { + process(collisions, v0photons, v0legs); } // end of process + void processQCML(FilteredMyCollisions const& collisions, MyV0PhotonsML const& v0photonsML, aod::V0Legs const& v0legs) + { + process(collisions, v0photonsML, v0legs); + } // end of ML process + void processDummy(MyCollisions const&) {} PROCESS_SWITCH(PCMQC, processQC, "run PCM QC", true); + PROCESS_SWITCH(PCMQC, processQCML, "run PCM QC with ML", false); PROCESS_SWITCH(PCMQC, processDummy, "Dummy function", false); }; diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx index f858ec60743..fc954865ec5 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx @@ -27,6 +27,8 @@ #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include +#include +#include #include #include #include @@ -58,9 +60,12 @@ using MyCollision = MyCollisions::iterator; using MyMCCollisions = soa::Join; using MyMCCollision = MyMCCollisions::iterator; -using MyV0Photons = soa::Join; +using MyV0Photons = o2::soa::Join; using MyV0Photon = MyV0Photons::iterator; +using MyV0PhotonsML = soa::Join; +using MyV0PhotonML = MyV0PhotonsML::iterator; + using MyMCV0Legs = soa::Join; using MyMCV0Leg = MyMCV0Legs::iterator; @@ -69,6 +74,11 @@ struct PCMQCMC { Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + 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 maxRgen{"maxRgen", 90.f, "maximum radius for generated particles"}; Configurable margin_z_mc{"margin_z_mc", 7.0, "margin for z cut in cm for MC"}; @@ -123,8 +133,27 @@ struct PCMQCMC { Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; 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"}; + // for ML cuts + Configurable cfg_apply_ml_cuts{"cfg_apply_ml", false, "flag to apply ML cut"}; + Configurable cfg_use_2d_binning{"cfg_use_2d_binning", false, "flag to use 2D binning (pT, cent)"}; + Configurable cfg_load_ml_models_from_ccdb{"cfg_load_ml_models_from_ccdb", true, "flag to load ML models from CCDB"}; + Configurable cfg_timestamp_ccdb{"cfg_timestamp_ccdb", -1, "timestamp for CCDB"}; + Configurable cfg_nclasses_ml{"cfg_nclasses_ml", static_cast(o2::analysis::em_cuts_ml::NCutScores), "number of classes for ML"}; + Configurable> cfg_cut_dir_ml{"cfg_cut_dir_ml", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "cut direction for ML"}; + Configurable> cfg_input_feature_names{"cfg_input_feature_names", std::vector{"feature1", "feature2"}, "input feature names for ML models"}; + Configurable> cfg_model_paths_ccdb{"cfg_model_paths_ccdb", std::vector{"path_ccdb/BDT_PCM/"}, "CCDB paths for ML models"}; + Configurable> cfg_onnx_file_names{"cfg_onnx_file_names", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for ML models"}; + Configurable> cfg_labels_bins_ml{"cfg_labels_bins_ml", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; + Configurable> cfg_labels_cut_scores_ml{"cfg_labels_cut_scores_ml", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; + Configurable> cfg_bins_pt_ml{"cfg_bins_pt_ml", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; + Configurable> cfg_bins_cent_ml{"cfg_bins_cent_ml", std::vector{o2::analysis::em_cuts_ml::vecBinsCent}, "centrality bins for ML"}; + Configurable> cfg_cuts_ml_flat{"cfg_cuts_ml_flat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; } pcmcuts; + o2::ccdb::CcdbApi ccdbApi; + o2::framework::Service ccdb; + int mRunNumber; + float d_bz; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; static constexpr std::string_view event_types[2] = {"before/", "after/"}; static constexpr std::string_view mcphoton_types[5] = {"primary/", "fromWD/", "fromHS/", "fromPi0Dalitz/", "fromEtaDalitz/"}; @@ -134,6 +163,54 @@ struct PCMQCMC { DefineEMEventCut(); DefinePCMCut(); 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 (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"; + } + fV0PhotonCut.SetD_Bz(d_bz); + mRunNumber = collision.runNumber(); } void addhistograms() @@ -222,6 +299,21 @@ struct PCMQCMC { fRegistry.add("V0/primary/hXY_MC", "X vs. Y of true photon conversion point.;X (cm);Y (cm)", kTH2F, {{400, -100.0f, +100}, {400, -100, +100}}, true); fRegistry.add("V0/primary/hRZ_MC", "R vs. Z of true photon conversion point;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100.0f, +100}, {200, 0, 100}}, true); fRegistry.add("V0/primary/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, false); + if (pcmcuts.cfg_apply_ml_cuts) { + if (pcmcuts.cfg_nclasses_ml == 2) { + fRegistry.add("V0/primary/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTSignalScoreVsPt", "BDT signal score vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } else if (pcmcuts.cfg_nclasses_ml == 3) { + fRegistry.add("V0/primary/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTPrimaryPhotonScoreVsPt", "BDT primary photon score vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTSecondaryPhotonScoreVsPt", "BDT secondary photon score vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } else { + fRegistry.add("V0/primary/hBDTScoreVsPt", "BDT score vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } + } fRegistry.addClone("V0/primary/", "V0/fromWD/"); // from weak decay fRegistry.addClone("V0/primary/", "V0/fromHS/"); // from hadronic shower in detector materials fRegistry.addClone("V0/primary/", "V0/fromPi0Dalitz/"); // misidentified dielectron from pi0 dalitz decay @@ -314,6 +406,31 @@ struct PCMQCMC { fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + + // for ML + fV0PhotonCut.SetApplyMlCuts(pcmcuts.cfg_apply_ml_cuts); + fV0PhotonCut.SetUse2DBinning(pcmcuts.cfg_use_2d_binning); + fV0PhotonCut.SetLoadMlModelsFromCCDB(pcmcuts.cfg_load_ml_models_from_ccdb); + fV0PhotonCut.SetNClassesMl(pcmcuts.cfg_nclasses_ml); + fV0PhotonCut.SetMlTimestampCCDB(pcmcuts.cfg_timestamp_ccdb); + fV0PhotonCut.SetCcdbUrl(ccdburl); + CentType mCentralityTypeMlEnum; + mCentralityTypeMlEnum = static_cast(cfgCentEstimator.value); + fV0PhotonCut.SetCentralityTypeMl(mCentralityTypeMlEnum); + fV0PhotonCut.SetCutDirMl(pcmcuts.cfg_cut_dir_ml); + fV0PhotonCut.SetMlModelPathsCCDB(pcmcuts.cfg_model_paths_ccdb); + fV0PhotonCut.SetMlOnnxFileNames(pcmcuts.cfg_onnx_file_names); + fV0PhotonCut.SetBinsPtMl(pcmcuts.cfg_bins_pt_ml); + fV0PhotonCut.SetBinsCentMl(pcmcuts.cfg_bins_cent_ml); + fV0PhotonCut.SetCutsMl(pcmcuts.cfg_cuts_ml_flat); + fV0PhotonCut.SetNamesInputFeatures(pcmcuts.cfg_input_feature_names); + fV0PhotonCut.SetLabelsBinsMl(pcmcuts.cfg_labels_bins_ml); + fV0PhotonCut.SetLabelsCutScoresMl(pcmcuts.cfg_labels_cut_scores_ml); + fV0PhotonCut.SetD_Bz(0.0f); // dummy value -> only for phiv calculation + + if (pcmcuts.cfg_apply_ml_cuts) { + fV0PhotonCut.initV0MlModels(ccdbApi); + } } template @@ -394,6 +511,28 @@ struct PCMQCMC { o2::math_utils::bringTo02Pi(phi_cp); float eta_cp = std::atanh(v0.vz() / std::sqrt(std::pow(v0.vx(), 2) + std::pow(v0.vy(), 2) + std::pow(v0.vz(), 2))); fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); + + // BDT response histogram can be filled here when apply BDT is true + if (pcmcuts.cfg_apply_ml_cuts) { + const std::span& bdtValue = fV0PhotonCut.getBDTValue(); + float psipair = 999.f; + float phiv = 999.f; + if constexpr( requires{ v0.psipair(); v0.phiv(); } ) { + psipair = v0.psipair(); + phiv = v0.phiv(); + } + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPhiVPsi"), psipair, phiv); + if (pcmcuts.cfg_nclasses_ml == 2 && bdtValue.size() == 2) { + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTSignalScoreVsPt"), v0.pt(), bdtValue[1]); + } else if (pcmcuts.cfg_nclasses_ml == 3 && bdtValue.size() == 3) { + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTPrimaryPhotonScoreVsPt"), v0.pt(), bdtValue[1]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTSecondaryPhotonScoreVsPt"), v0.pt(), bdtValue[2]); + } else if (bdtValue.size() == 1) { + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTCutVsPt"), v0.pt(), bdtValue[0]); + } + } } template @@ -429,16 +568,17 @@ 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()); } - + o2::framework::SliceCache v0cache; 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; - - Preslice perCollision = aod::v0photonkf::emeventId; - void processQCMC(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, MyMCV0Legs const&, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) + + template + void processMC(FilteredMyCollisions const& collisions, TV0Photons const& v0photons, aod::EMMCParticles const& mcparticles, MyMCV0Legs const&, aod::EMMCEvents const&) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { + initCCDB(collision); const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; @@ -452,11 +592,12 @@ struct PCMQCMC { fRegistry.fill(HIST("Event/before/hCollisionCounter"), 10.0); // accepted fRegistry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted - auto V0Photons_coll = v0photons.sliceBy(perCollision, collision.globalIndex()); + fV0PhotonCut.SetCentrality(centralities[cfgCentEstimator]); // set centrality for BDT response + auto V0Photons_coll = v0photons.sliceByCached(aod::v0photonkf::emeventId, collision.globalIndex(), v0cache); int ng_primary = 0, ng_wd = 0, ng_hs = 0, nee_pi0 = 0, nee_eta = 0; - for (auto& v0 : V0Photons_coll) { - auto pos = v0.posTrack_as(); - auto ele = v0.negTrack_as(); + for (const auto& v0 : V0Photons_coll) { + auto pos = v0.template posTrack_as(); + auto ele = v0.template negTrack_as(); auto posmc = pos.template emmcparticle_as(); auto elemc = ele.template emmcparticle_as(); @@ -468,7 +609,7 @@ struct PCMQCMC { fRegistry.fill(HIST("V0/candidate/hPt"), v0.pt()); fRegistry.fill(HIST("V0/candidate/hEtaPhi"), v0.phi(), v0.eta()); - for (auto& leg : {pos, ele}) { + for (const auto& leg : {pos, ele}) { fRegistry.fill(HIST("V0Leg/candidate/hPt"), leg.pt()); fRegistry.fill(HIST("V0Leg/candidate/hEtaPhi"), leg.phi(), leg.eta()); } @@ -488,19 +629,19 @@ struct PCMQCMC { if (mcphoton.isPhysicalPrimary() || mcphoton.producedByGenerator()) { fillV0Info<0>(v0, mcphoton, elemc); - for (auto& leg : {pos, ele}) { + for (const auto& leg : {pos, ele}) { fillV0LegInfo<0>(leg); } ng_primary++; } else if (IsFromWD(mcphoton.template emmcevent_as(), mcphoton, mcparticles) > 0) { fillV0Info<1>(v0, mcphoton, elemc); - for (auto& leg : {pos, ele}) { + for (const auto& leg : {pos, ele}) { fillV0LegInfo<1>(leg); } ng_wd++; } else { fillV0Info<2>(v0, mcphoton, elemc); - for (auto& leg : {pos, ele}) { + for (const auto& leg : {pos, ele}) { fillV0LegInfo<2>(leg); } ng_hs++; @@ -513,7 +654,7 @@ struct PCMQCMC { } if (mcpi0.isPhysicalPrimary() || mcpi0.producedByGenerator()) { fillV0Info<3>(v0, mcpi0, elemc); - for (auto& leg : {pos, ele}) { + for (const auto& leg : {pos, ele}) { fillV0LegInfo<3>(leg); } nee_pi0++; @@ -525,7 +666,7 @@ struct PCMQCMC { } if (mceta.isPhysicalPrimary() || mceta.producedByGenerator()) { fillV0Info<4>(v0, mceta, elemc); - for (auto& leg : {pos, ele}) { + for (const auto& leg : {pos, ele}) { fillV0LegInfo<4>(leg); } nee_eta++; @@ -540,6 +681,16 @@ struct PCMQCMC { } // end of collision loop } // end of process + void processQCMC(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) + { + processMC(collisions, v0photons, mcparticles, mcv0legs, mcevents); + } // end of QC process + + void processQCMCML(FilteredMyCollisions const& collisions, MyV0PhotonsML const& v0photonsML, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) + { + processMC(collisions, v0photonsML, mcparticles, mcv0legs, mcevents); + } // end of QC process with ML cuts + template void fillBinnedData(TBinnedData const& binned_data, const float weight = 1.f) { @@ -570,7 +721,7 @@ struct PCMQCMC { // loop over mc stack and fill histograms for pure MC truth signals // all MC tracks which belong to the MC event corresponding to the current reconstructed event - for (auto& collision : collisions) { + for (const auto& collision : collisions) { const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; @@ -586,12 +737,12 @@ struct PCMQCMC { // LOGF(info, "mccollision.globalIndex() = %d", mccollision.globalIndex()); auto mctracks_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); - for (auto& mctrack : mctracks_coll) { + for (const auto& mctrack : mctracks_coll) { if (std::fabs(mctrack.y()) > pcmcuts.cfg_max_eta_v0) { continue; } - if (std::abs(mctrack.pdgCode()) == 22 && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + if (std::abs(mctrack.pdgCode()) == PDG_t::kGamma && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { auto daughter = mcparticles.iteratorAt(mctrack.daughtersIds()[0]); // choose ele or pos. float rxy_gen_e = std::sqrt(std::pow(daughter.vx(), 2) + std::pow(daughter.vy(), 2)); float phi_cp = std::atan2(daughter.vy(), daughter.vx()); @@ -621,6 +772,7 @@ struct PCMQCMC { PROCESS_SWITCH(PCMQCMC, processQCMC, "run PCM QC in MC", false); PROCESS_SWITCH(PCMQCMC, processGen, "run generated information", false); + PROCESS_SWITCH(PCMQCMC, processQCMCML, "run PCM QC in MC with ML cuts", false); PROCESS_SWITCH(PCMQCMC, processDummy, "Dummy function", true); }; From 2cea0f00b2fb279f3efd4bd25c062a2c19a6cfe0 Mon Sep 17 00:00:00 2001 From: Isabel Kantak Date: Fri, 20 Feb 2026 17:13:59 +0100 Subject: [PATCH 4/7] Update optional ML-based photon cuts in Pi0EtaToGammaGammaPCM task to also be able to use psipair and phiv as parameters for the models. --- PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h | 7 ++-- PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h | 7 ++-- PWGEM/PhotonMeson/Tasks/CMakeLists.txt | 10 +++++ .../Tasks/Pi0EtaToGammaGammaMCPCMPCMML.cxx | 37 +++++++++++++++++++ .../Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx | 36 ++++++++++++++++++ 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCMML.cxx create mode 100644 PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h index 8cc1efd73dd..83e934bbdd0 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h @@ -147,7 +147,6 @@ struct Pi0EtaToGammaGamma { o2::framework::Configurable cfg_load_ml_models_from_ccdb{"cfg_load_ml_models_from_ccdb", true, "flag to load ML models from CCDB"}; o2::framework::Configurable cfg_timestamp_ccdb{"cfg_timestamp_ccdb", -1, "timestamp for CCDB"}; o2::framework::Configurable cfg_nclasses_ml{"cfg_nclasses_ml", static_cast(o2::analysis::em_cuts_ml::NCutScores), "number of classes for ML"}; - o2::framework::Configurable cfg_cent_type_ml{"cfg_cent_type_ml", "CentFT0C", "centrality type for 2D ML application: CentFT0C, CentFT0M, or CentFT0A"}; o2::framework::Configurable> cfg_cut_dir_ml{"cfg_cut_dir_ml", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "cut direction for ML"}; o2::framework::Configurable> cfg_input_feature_names{"cfg_input_feature_names", std::vector{"feature1", "feature2"}, "input feature names for ML models"}; o2::framework::Configurable> cfg_model_paths_ccdb{"cfg_model_paths_ccdb", std::vector{"path_ccdb/BDT_PCM/"}, "CCDB paths for ML models"}; @@ -508,7 +507,9 @@ struct Pi0EtaToGammaGamma { fV0PhotonCut.SetNClassesMl(pcmcuts.cfg_nclasses_ml); fV0PhotonCut.SetMlTimestampCCDB(pcmcuts.cfg_timestamp_ccdb); fV0PhotonCut.SetCcdbUrl(ccdburl); - fV0PhotonCut.SetCentralityTypeMl(pcmcuts.cfg_cent_type_ml); + CentType mCentralityTypeMlEnum; + mCentralityTypeMlEnum = static_cast(cfgCentEstimator.value); + fV0PhotonCut.SetCentralityTypeMl(mCentralityTypeMlEnum); fV0PhotonCut.SetCutDirMl(pcmcuts.cfg_cut_dir_ml); fV0PhotonCut.SetMlModelPathsCCDB(pcmcuts.cfg_model_paths_ccdb); fV0PhotonCut.SetMlOnnxFileNames(pcmcuts.cfg_onnx_file_names); @@ -702,7 +703,6 @@ struct Pi0EtaToGammaGamma { { for (const auto& collision : collisions) { initCCDB(collision); - fV0PhotonCut.SetCentrality(collision.centFT0A(), collision.centFT0C(), collision.centFT0M()); int ndiphoton = 0; if ((pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { continue; @@ -718,6 +718,7 @@ struct Pi0EtaToGammaGamma { } const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + fV0PhotonCut.SetCentrality(centralities[cfgCentEstimator]); if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h index 48dacaddee8..729f76ce5de 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h @@ -136,7 +136,6 @@ struct Pi0EtaToGammaGammaMC { o2::framework::Configurable cfg_load_ml_models_from_ccdb{"cfg_load_ml_models_from_ccdb", true, "flag to load ML models from CCDB"}; o2::framework::Configurable cfg_timestamp_ccdb{"cfg_timestamp_ccdb", -1, "timestamp for CCDB"}; o2::framework::Configurable cfg_nclasses_ml{"cfg_nclasses_ml", static_cast(o2::analysis::em_cuts_ml::NCutScores), "number of classes for ML"}; - o2::framework::Configurable cfg_cent_type_ml{"cfg_cent_type_ml", "CentFT0C", "centrality type for 2D ML application: CentFT0C, CentFT0M, or CentFT0A"}; o2::framework::Configurable> cfg_cut_dir_ml{"cfg_cut_dir_ml", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "cut direction for ML"}; o2::framework::Configurable> cfg_input_feature_names{"cfg_input_feature_names", std::vector{"feature1", "feature2"}, "input feature names for ML models"}; o2::framework::Configurable> cfg_model_paths_ccdb{"cfg_model_paths_ccdb", std::vector{"path_ccdb/BDT_PCM/"}, "CCDB paths for ML models"}; @@ -348,7 +347,9 @@ struct Pi0EtaToGammaGammaMC { fV0PhotonCut.SetNClassesMl(pcmcuts.cfg_nclasses_ml); fV0PhotonCut.SetMlTimestampCCDB(pcmcuts.cfg_timestamp_ccdb); fV0PhotonCut.SetCcdbUrl(ccdburl); - fV0PhotonCut.SetCentralityTypeMl(pcmcuts.cfg_cent_type_ml); + CentType mCentralityTypeMlEnum; + mCentralityTypeMlEnum = static_cast(cfgCentEstimator.value); + fV0PhotonCut.SetCentralityTypeMl(mCentralityTypeMlEnum); fV0PhotonCut.SetCutDirMl(pcmcuts.cfg_cut_dir_ml); fV0PhotonCut.SetMlModelPathsCCDB(pcmcuts.cfg_model_paths_ccdb); fV0PhotonCut.SetMlOnnxFileNames(pcmcuts.cfg_onnx_file_names); @@ -560,7 +561,6 @@ struct Pi0EtaToGammaGammaMC { { for (auto& collision : collisions) { initCCDB(collision); - fV0PhotonCut.SetCentrality(collision.centFT0A(), collision.centFT0C(), collision.centFT0M()); if ((pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { continue; } @@ -575,6 +575,7 @@ struct Pi0EtaToGammaGammaMC { } const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + fV0PhotonCut.SetCentrality(centralities[cfgCentEstimator]); if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } diff --git a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt index 69cc178395c..ba160a3080f 100644 --- a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt @@ -91,6 +91,11 @@ o2physics_add_dpl_workflow(pi0eta-to-gammagamma-pcmpcm PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-pcmpcm-ml + SOURCES Pi0EtaToGammaGammaPCMPCMML.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pi0eta-to-gammagamma-pcmdalitzee SOURCES Pi0EtaToGammaGammaPCMDalitzEE.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore @@ -111,6 +116,11 @@ o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-pcmpcm PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-pcmpcm-ml + SOURCES Pi0EtaToGammaGammaMCPCMPCMML.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-pcmdalitzee SOURCES Pi0EtaToGammaGammaMCPCMDalitzEE.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCMML.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCMML.cxx new file mode 100644 index 00000000000..c5b06741e75 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCMML.cxx @@ -0,0 +1,37 @@ +// 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 Pi0EtaToGammaGammaMCPCMPCMML.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses in MC for PCM-PCM with additional ML-based photon cuts. +/// \author Isabel Kantak, isabel.kantak@cern.ch + +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; + +using MyV0Photons = o2::soa::Filtered>; +using MyMCV0Legs = soa::Join; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-mc-pcmpcm"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx new file mode 100644 index 00000000000..2d25e320339 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx @@ -0,0 +1,36 @@ +// 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 Pi0EtaToGammaGammaPCMPCMML.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses for PCM-PCM with additional ML cuts to photons. +/// \author Isabel Kantak, isabel.kantak@cern.ch + +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; + +using MyV0Photons = o2::soa::Filtered>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-pcmpcm"}), + }; +} \ No newline at end of file From b3f24b1a5b407b845b06dba1c29a61486bfe1aed Mon Sep 17 00:00:00 2001 From: Isabel Kantak Date: Fri, 20 Feb 2026 17:49:31 +0100 Subject: [PATCH 5/7] Update formatting --- PWGEM/PhotonMeson/Core/V0PhotonCandidate.h | 4 ++-- PWGEM/PhotonMeson/Core/V0PhotonCut.h | 2 +- .../TableProducer/photonconversionbuilder.cxx | 6 +++--- .../PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx | 2 +- PWGEM/PhotonMeson/Tasks/pcmQC.cxx | 12 ++++++------ PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h index 07267a2d78f..d81c803ca2c 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h @@ -111,8 +111,8 @@ struct V0PhotonCandidate { alpha = v0.alpha(); qt = v0.qtarm(); psipair = 999.f; // default if V0PhotonPhiVPsi table is not included - phiv = 999.f; // default if V0PhotonPhiVPsi table is not included - if constexpr( requires{ v0.psipair(); v0.phiv(); } ) { + phiv = 999.f; // default if V0PhotonPhiVPsi table is not included + if constexpr (requires { v0.psipair(); v0.phiv(); }) { psipair = v0.psipair(); phiv = v0.phiv(); } diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.h b/PWGEM/PhotonMeson/Core/V0PhotonCut.h index 4fb2c960ec6..0203d87c686 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.h @@ -39,10 +39,10 @@ #include #include #include +#include #include #include #include -#include namespace o2::analysis { diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index a6716ecb72f..d8f9edbf43a 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -485,7 +485,7 @@ struct PhotonConversionBuilder { return cospaRZ; } - template + template void fillTrackTable(TTrack const& track, TShiftedTrack const& shiftedtrack, const float dcaXY, const float dcaZ) { v0legs(track.collisionId(), track.globalIndex(), track.sign(), @@ -609,9 +609,9 @@ struct PhotonConversionBuilder { } } if (phiv == 999.f || psipair == 999.f) { - LOG(debug) << "Propagation failed for all radii ("<< propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f)."; + LOG(debug) << "Propagation failed for all radii (" << propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f)."; } - + KFPTrack kfp_track_pos = createKFPTrackFromTrackParCov(pTrack, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); KFPTrack kfp_track_ele = createKFPTrackFromTrackParCov(nTrack, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); KFParticle kfp_pos(kfp_track_pos, kPositron); diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx index 2d25e320339..2d0fa9f2120 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCMML.cxx @@ -33,4 +33,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) return WorkflowSpec{ adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-pcmpcm"}), }; -} \ No newline at end of file +} diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index eb45e61d764..7c12c13b29c 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -242,7 +242,7 @@ struct PCMQC { fRegistry.add("V0/hKFChi2vsZ", "KF chi2 vs. conversion point in Z;Z (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); fRegistry.add("V0/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, false); fRegistry.add("V0/hNgamma", "Number of #gamma candidates per collision", kTH1F, {{101, -0.5f, 100.5f}}); - + if (pcmcuts.cfg_apply_ml_cuts) { if (pcmcuts.cfg_nclasses_ml == 2) { fRegistry.add("V0/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); @@ -281,7 +281,7 @@ struct PCMQC { fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Pos", "momentum of pos leg vs. conversion point of V0 vs. TPC n sigma pos vs. eta of pos leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Ele", "momentum of neg leg vs. conversion point of V0 vs. TPC n sigma el vs. eta of neg leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); } - // fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {80, -20, 20}}, false); + // fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {80, -20, 20}}, false); // fRegistry.add("V0Leg/hZX", "Z vs. X;Z (cm);X (cm)", kTH2F, {{200, -100, 100}, {100, 0, 100}}, false); // fRegistry.add("V0Leg/hZY", "Z vs. Y;Z (cm);Y (cm)", kTH2F, {{200, -100, 100}, {80, -20, 20}}, false); } @@ -429,9 +429,9 @@ struct PCMQC { // BDT response histogram can be filled here when apply BDT is true if (pcmcuts.cfg_apply_ml_cuts) { const std::span& bdtValue = fV0PhotonCut.getBDTValue(); - float psipair = 999.f; + float psipair = 999.f; float phiv = 999.f; - if constexpr( requires{ v0.psipair(); v0.phiv(); } ) { + if constexpr (requires { v0.psipair(); v0.phiv(); }) { psipair = v0.psipair(); phiv = v0.phiv(); } @@ -483,7 +483,7 @@ struct PCMQC { using FilteredMyCollisions = soa::Filtered; template - void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const& v0legs) + void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const& v0legs) { for (const auto& collision : collisions) { initCCDB(collision); @@ -530,7 +530,7 @@ struct PCMQC { void processQCML(FilteredMyCollisions const& collisions, MyV0PhotonsML const& v0photonsML, aod::V0Legs const& v0legs) { - process(collisions, v0photonsML, v0legs); + process(collisions, v0photonsML, v0legs); } // end of ML process void processDummy(MyCollisions const&) {} diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx index fc954865ec5..eb04bc86b88 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx @@ -517,7 +517,7 @@ struct PCMQCMC { const std::span& bdtValue = fV0PhotonCut.getBDTValue(); float psipair = 999.f; float phiv = 999.f; - if constexpr( requires{ v0.psipair(); v0.phiv(); } ) { + if constexpr (requires { v0.psipair(); v0.phiv(); }) { psipair = v0.psipair(); phiv = v0.phiv(); } @@ -573,7 +573,7 @@ struct PCMQCMC { 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 processMC(FilteredMyCollisions const& collisions, TV0Photons const& v0photons, aod::EMMCParticles const& mcparticles, MyMCV0Legs const&, aod::EMMCEvents const&) { @@ -686,7 +686,7 @@ struct PCMQCMC { processMC(collisions, v0photons, mcparticles, mcv0legs, mcevents); } // end of QC process - void processQCMCML(FilteredMyCollisions const& collisions, MyV0PhotonsML const& v0photonsML, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) + void processQCMCML(FilteredMyCollisions const& collisions, MyV0PhotonsML const& v0photonsML, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) { processMC(collisions, v0photonsML, mcparticles, mcv0legs, mcevents); } // end of QC process with ML cuts From e58d308fc2a86fb9aad2006029327487707a818d Mon Sep 17 00:00:00 2001 From: Isabel Kantak Date: Sat, 21 Feb 2026 10:08:14 +0100 Subject: [PATCH 6/7] Remove unused variable --- PWGEM/PhotonMeson/Tasks/pcmQC.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 7c12c13b29c..9e8a19a51e2 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -483,7 +483,7 @@ struct PCMQC { using FilteredMyCollisions = soa::Filtered; template - void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const& v0legs) + void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const& ) { for (const auto& collision : collisions) { initCCDB(collision); From ae2bdd0ef21365c5eb3b5e55a16743480895ddfd Mon Sep 17 00:00:00 2001 From: Isabel Kantak Date: Sat, 21 Feb 2026 10:14:57 +0100 Subject: [PATCH 7/7] Remove space --- PWGEM/PhotonMeson/Tasks/pcmQC.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 9e8a19a51e2..c741b283be3 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -483,7 +483,7 @@ struct PCMQC { using FilteredMyCollisions = soa::Filtered; template - void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const& ) + void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const&) { for (const auto& collision : collisions) { initCCDB(collision);