From 8ecc833d36a468b9e81b999bfbbeda0b30cc4b55 Mon Sep 17 00:00:00 2001 From: Marvin Hemmer Date: Wed, 29 Jul 2026 11:10:48 +0200 Subject: [PATCH] [PWGEM] Add option to separate EMCal and DCal cluster pairing for flow task --- .../PhotonMeson/DataModel/GammaTablesRedux.h | 2 +- PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx | 17 +++++++--- PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx | 10 +++--- PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx | 33 ++++++++++++++++--- PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx | 4 +-- PWGEM/PhotonMeson/Utils/MCUtilities.h | 1 + 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h b/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h index d666265af2a..d9d2485206d 100644 --- a/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h +++ b/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h @@ -47,7 +47,7 @@ enum Observable { }; // Values in tables are stored in downscaled format to save disk space -const std::array downscalingFactors{ +constexpr std::array downscalingFactors{ 1E0, // Cluster definition 1E3, // Cluster energy 1E4, // Cluster eta diff --git a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx index 3ee4a6e928d..507046750d5 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx @@ -27,12 +27,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -51,7 +53,12 @@ #include #include +#include + +#include #include +#include +#include #include #include #include @@ -148,14 +155,16 @@ ClusterMcInfo classifyCluster(const TGroup& g, TIter& mcCluster, TIter& mcCluste info.isPhoton = true; } - info.photonId = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); + info.photonId = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); info.isFromPi0 = info.photonId >= 0; return info; } + struct EmcalPhotonMcTask { static constexpr float EMCALRadius = 440.f; static constexpr float PhiVUndefined = -999.f; + static constexpr float Epsilon = 1.e-6f; Produces convTagCandidates; @@ -241,7 +250,7 @@ struct EmcalPhotonMcTask { using McColls = o2::soa::Join; using McParticles = EMMCParticles; - PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; @@ -515,7 +524,7 @@ struct EmcalPhotonMcTask { ROOT::Math::XYZVector nRef = u.Cross(zAxis); // normal to the plane containing u and z float phiV = PhiVUndefined; // sentinel for degenerate geometry - if (nDecay.R() > 1e-6f && nRef.R() > 1e-6f) { + if (nDecay.R() > Epsilon && nRef.R() > Epsilon) { float cosPhiV = static_cast(nDecay.Unit().Dot(nRef.Unit())); cosPhiV = std::clamp(cosPhiV, -1.f, 1.f); phiV = std::acos(cosPhiV); @@ -627,7 +636,7 @@ struct EmcalPhotonMcTask { } mcCluster1.setCursor(cluster.emmcparticleIds()[0]); - int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); + int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); int motherId = -1; if (photonid1 >= 0) { mcPhoton1.setCursor(photonid1); diff --git a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx index c14add8b083..62865a5afb0 100644 --- a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx @@ -50,7 +50,7 @@ using namespace o2::aod::pwgem::photon; enum QvecEstimator { FT0M = 0, - FT0A = 1, + FT0A, FT0C, TPCPos, TPCNeg, @@ -60,7 +60,7 @@ enum QvecEstimator { enum CentralityEstimator { None = 0, - CFT0A = 1, + CFT0A, CFT0C, CFT0M, NCentralityEstimators @@ -382,7 +382,7 @@ struct TaskFlowReso { // no selection on the centrality is applied on purpose to allow for the resolution study in post-processing return; } - if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange()) || !(collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { return; } float cent = getCentrality(collision); @@ -530,7 +530,7 @@ struct TaskFlowReso { }; // End struct TaskFlowReso -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index aa3745d9503..af98c86de85 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -172,6 +173,7 @@ struct TaskPi0FlowEMC { Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + Configurable separateEMCalDCal{"separateEMCalDCal", false, "flag to only pair EMCal with EMCal and DCal with DCal clusters"}; } emccuts; V0PhotonCut fV0PhotonCut; @@ -251,6 +253,8 @@ struct TaskPi0FlowEMC { int runNow = 0; int runBefore = -1; + static constexpr float MaxPhiEMCal = 3.5f; + // Filter clusterFilter = aod::skimmedcluster::time >= emccuts.cfgEMCminTime && aod::skimmedcluster::time <= emccuts.cfgEMCmaxTime && aod::skimmedcluster::m02 >= emccuts.cfgEMCminM02 && aod::skimmedcluster::m02 <= emccuts.cfgEMCmaxM02 && aod::skimmedcluster::e >= emccuts.cfgEMCminE; Filter collisionFilter = (nabs(aod::collision::posZ) <= eventcuts.cfgZvtxMax) && (aod::evsel::ft0cOccupancyInTimeRange <= eventcuts.cfgFT0COccupancyMax) && (aod::evsel::ft0cOccupancyInTimeRange >= eventcuts.cfgFT0COccupancyMin); // using FilteredEMCalPhotons = soa::Filtered>; @@ -260,10 +264,13 @@ struct TaskPi0FlowEMC { using CollsWithQvecs = soa::Join; using Colls = soa::Join; + Partition emcalPhotons = aod::mincluster::storedPhi < std::lround(MaxPhiEMCal * emcdownscaling::downscalingFactors[emcdownscaling::kPhi]); + Partition dcalPhotons = aod::mincluster::storedPhi >= std::lround(MaxPhiEMCal * emcdownscaling::downscalingFactors[emcdownscaling::kPhi]); + static constexpr std::size_t NQVecEntries = 6; - PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; - PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; @@ -481,6 +488,13 @@ struct TaskPi0FlowEMC { }; // end init + /// \brief Check whether a photon (by its phi) falls in the EMCal or DCal acceptance + /// \param phi azimuthal angle of the photon + static bool isEMCalRegion(float phi) + { + return phi < MaxPhiEMCal; + } + /// Change radians to degree /// \param angle in radians /// \return angle in degree @@ -1047,7 +1061,7 @@ struct TaskPi0FlowEMC { continue; } if (rotationConfig.cfgDoRotation.value && nColl % rotationConfig.cfgDownsampling == 0) { - rotationBackground(vMeson, v1, v2, photons1, g1.globalIndex(), g2.globalIndex(), collision); + rotationBackground(vMeson, v1, v2, photons1, g1.globalIndex(), g2.globalIndex(), collision); } if (thnConfigAxisInvMass.value[1] > vMeson.M() || thnConfigAxisInvMass.value.back() < vMeson.M()) { registry.fill(HIST("hMesonCuts"), 3); @@ -1093,6 +1107,8 @@ struct TaskPi0FlowEMC { } auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + auto emcalPhotonsPerCollision = emcalPhotons.sliceBy(perCollisionEMC, collision.globalIndex()); + auto dcalPhotonsPerCollision = dcalPhotons.sliceBy(perCollisionEMC, collision.globalIndex()); if (emccuts.cfgEnableQA.value) { for (const auto& photon : photonsPerCollision) { @@ -1108,7 +1124,12 @@ struct TaskPi0FlowEMC { registry.fill(HIST("clusterQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // after cuts } } - runPairingLoop(collision, photonsPerCollision, photonsPerCollision, flags, flags); + if (emccuts.separateEMCalDCal.value) { + runPairingLoop(collision, emcalPhotonsPerCollision, emcalPhotonsPerCollision, flags, flags); + runPairingLoop(collision, dcalPhotonsPerCollision, dcalPhotonsPerCollision, flags, flags); + } else { + runPairingLoop(collision, photonsPerCollision, photonsPerCollision, flags, flags); + } if (rotationConfig.cfgDoRotation.value) { if (nColl % rotationConfig.cfgDownsampling == 0) { nColl = 1; // reset counter @@ -1163,6 +1184,10 @@ struct TaskPi0FlowEMC { if (!(flags.test(g1.globalIndex())) || !(flags.test(g2.globalIndex()))) { continue; } + if (emccuts.separateEMCalDCal.value && isEMCalRegion(g1.phi()) != isEMCalRegion(g2.phi())) { + continue; // only pair EMCal-EMCal or DCal-DCal + } + // Cut edge clusters away, similar to rotation method to ensure same acceptance is used if (cfgDistanceToEdge.value > 0) { if (checkEtaPhi1D(g1.eta(), RecoDecay::constrainAngle(g1.phi())) >= cfgEMCalMapLevelBackground.value) { diff --git a/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx b/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx index c10b30fc3a6..ad2b5594c15 100644 --- a/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx +++ b/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx @@ -172,7 +172,7 @@ struct TestTaskEmc { PROCESS_SWITCH(TestTaskEmc, processEMCalCalib, "Process EMCal calibration same event", true); }; // End struct TestTaskEmc -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Utils/MCUtilities.h b/PWGEM/PhotonMeson/Utils/MCUtilities.h index dce6d127bf5..94fceb68445 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -17,6 +17,7 @@ #define PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ #include +#include #include