diff --git a/PWGCF/GenericFramework/Tasks/CMakeLists.txt b/PWGCF/GenericFramework/Tasks/CMakeLists.txt index bc5feb0779c..90b65bdba93 100644 --- a/PWGCF/GenericFramework/Tasks/CMakeLists.txt +++ b/PWGCF/GenericFramework/Tasks/CMakeLists.txt @@ -31,5 +31,5 @@ o2physics_add_dpl_workflow(flow-gfw-nonflow o2physics_add_dpl_workflow(energy-flow-gfw SOURCES energyFlowGfw.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCCDB O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) diff --git a/PWGCF/GenericFramework/Tasks/energyFlowGfw.cxx b/PWGCF/GenericFramework/Tasks/energyFlowGfw.cxx index e1d2ea659cc..db7d4c1cdb5 100644 --- a/PWGCF/GenericFramework/Tasks/energyFlowGfw.cxx +++ b/PWGCF/GenericFramework/Tasks/energyFlowGfw.cxx @@ -18,6 +18,7 @@ #include "PWGCF/GenericFramework/Core/GFWConfig.h" #include "PWGCF/GenericFramework/Core/GFWWeights.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/TriggerAliases.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -39,7 +40,6 @@ #include #include -#include #include #include #include @@ -136,6 +136,7 @@ struct EnergyFlowGfw { Configurable cfgMaxCentrality{"cfgMaxCentrality", 100.f, "Maximum accepted centrality percentile"}; Configurable cfgFillEfficiency{"fillEfficiency", false, "Fill MC tracking efficiency; ignored by data processes"}; Configurable cfgFillAcceptance{"fillAcceptance", false, "Fill GFW acceptance weights instead of running the reconstructed analysis"}; + Configurable cfgUseRun2EventSelectionWithoutZdc{"cfgUseRun2EventSelectionWithoutZdc", false, "For Run 2 data, require kINT7 and every CCDB-enabled barrel sel7 criterion except the ZDC beam-beam criteria; retain the ZDC beam-gas vetoes"}; Configurable cfgSpectatorEnergyPerNucleon{"cfgSpectatorEnergyPerNucleon", 1.f, "ZDC energy corresponding to one spectator nucleon"}; Configurable cfgMaxTotalSpectators{"cfgMaxTotalSpectators", 500.f, "Maximum accepted spectator count from ZNA+ZNC+ZPA+ZPC"}; @@ -145,8 +146,10 @@ struct EnergyFlowGfw { Configurable cfgZdcResponseZPC{"cfgZdcResponseZPC", 1.f, "ZPC efficiency/acceptance response factor alpha; corrected energy is E_ZPC/alpha_ZPC"}; Configurable cfgZdcMaxAbsTimeForQa{"cfgZdcMaxAbsTimeForQa", 100.f, "Maximum absolute ZDC time considered available in QA; excludes missing-time sentinels"}; - Configurable efficiencyPath{"efficiencyPath", "", "CCDB path or local ROOT file containing a 4D efficiency-correction THn"}; - Configurable efficiencyFromLocalFile{"efficiencyFromLocalFile", false, "Load efficiencyPath from a local ROOT file"}; + struct : ConfigurableGroup { + Configurable cfgEfficiencyPath{"cfgEfficiencyPath", "", "CCDB path to efficiency object"}; + Configurable cfgUsePIDEfficiencies{"cfgUsePIDEfficiencies", false, "Use separate charged, pion, kaon, and proton efficiencies"}; + } cfgEfficiency; Configurable acceptancePath{"acceptancePath", "", "CCDB path to GFW acceptance weights"}; Configurable acceptanceRunByRun{"acceptanceRunByRun", false, "Load acceptance weights from the RunByRun subdirectory"}; @@ -197,8 +200,9 @@ struct EnergyFlowGfw { std::vector zeroHarmonicConfigs; int gfwMask = 0; - std::unique_ptr localEfficiency; - THn* efficiency = nullptr; + TH1* efficiency = nullptr; + std::vector pidEfficiencies; + bool efficiencyLoaded = false; GFWWeights* acceptance = nullptr; int acceptanceRunNumber = -1; @@ -601,39 +605,70 @@ struct EnergyFlowGfw { return true; } - void loadEfficiency(uint64_t timestamp) + static bool isZdcBeamBeamSelectionFlag(int flag) { - if (efficiencyPath.value.empty()) { - efficiency = nullptr; - return; + return flag == aod::evsel::kIsBBZNA || flag == aod::evsel::kIsBBZNC || flag == aod::evsel::kIsBBZAC; + } + + template + bool run2EventSelected(TCollision const& collision) + { + if (!collision.alias_bit(kINT7)) { + return false; } - if (efficiencyFromLocalFile) { - if (localEfficiency) { - efficiency = localEfficiency.get(); - return; - } - std::unique_ptr input(TFile::Open(efficiencyPath.value.c_str(), "READ")); - if (!input || input->IsZombie()) { - LOGF(fatal, "Could not open efficiency file %s", efficiencyPath.value.c_str()); - return; - } - auto* source = dynamic_cast(input->Get("ccdb_object")); - if (!source || source->GetNdimensions() != 4) { - LOGF(fatal, "Efficiency object must be a 4D THn with axes eta, pT, centrality, z-vtx"); + if (!cfgUseRun2EventSelectionWithoutZdc) { + return collision.sel7(); + } + if (!collision.has_foundBC()) { + return false; + } + + const auto& bc = collision.template foundBC_as(); + auto* selectionParameters = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", bc.timestamp()); + if (!selectionParameters) { + LOGF(fatal, "Could not load the Run 2 event-selection parameters"); + } + const bool* enabledSelections = selectionParameters->getSelection(0); + for (int flag = 0; flag < aod::evsel::kNsel; ++flag) { + if (isZdcBeamBeamSelectionFlag(flag)) { + continue; } - localEfficiency.reset(dynamic_cast(source->Clone("eecEfficiency"))); - if (!localEfficiency) { - LOGF(fatal, "Could not clone the efficiency object from %s", efficiencyPath.value.c_str()); + if (enabledSelections[flag] && !collision.selection_bit(flag)) { + return false; } - efficiency = localEfficiency.get(); + } + return true; + } + + void loadEfficiency(uint64_t timestamp) + { + if (efficiencyLoaded) { return; } - if (!efficiency || !ccdb->isCachedObjectValid(efficiencyPath.value, timestamp)) { - efficiency = ccdb->getForTimeStamp>(efficiencyPath.value, timestamp); - if (!efficiency || efficiency->GetNdimensions() != 4) { - LOGF(fatal, "Could not load a 4D efficiency correction from %s", efficiencyPath.value.c_str()); + if (cfgEfficiency.cfgEfficiencyPath.value.empty()) { + efficiencyLoaded = true; + return; + } + + if (!cfgEfficiency.cfgUsePIDEfficiencies) { + efficiency = ccdb->getForTimeStamp(cfgEfficiency.cfgEfficiencyPath.value, timestamp); + if (!efficiency) { + LOGF(fatal, "Could not load efficiency histogram from %s", cfgEfficiency.cfgEfficiencyPath.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s", cfgEfficiency.cfgEfficiencyPath.value.c_str()); + } else { + static constexpr std::array EfficiencySpeciesNames{"ch", "pi", "ka", "pr"}; + pidEfficiencies.reserve(EfficiencySpeciesNames.size()); + for (const auto& speciesName : EfficiencySpeciesNames) { + const std::string path = cfgEfficiency.cfgEfficiencyPath.value + "/" + speciesName; + pidEfficiencies.push_back(ccdb->getForTimeStamp(path, timestamp)); + if (!pidEfficiencies.back()) { + LOGF(fatal, "Could not load PID efficiency histogram from %s", path.c_str()); + } + LOGF(info, "Loaded PID efficiency histogram from %s", path.c_str()); } } + efficiencyLoaded = true; } void loadAcceptance(uint64_t timestamp, int runNumber) @@ -659,17 +694,20 @@ struct EnergyFlowGfw { acceptanceRunNumber = runNumber; } - double efficiencyWeight(float eta, float pt, float centrality, float posZ) const + double getEfficiency(float pt, int pid) const { - if (!efficiency) { + TH1* efficiencyHistogram = efficiency; + if (cfgEfficiency.cfgUsePIDEfficiencies.value) { + if (pidEfficiencies.empty()) { + return 1.; + } + efficiencyHistogram = pidEfficiencies[pid]; + } else if (!efficiencyHistogram) { return 1.; } - std::array bins{ - efficiency->GetAxis(0)->FindBin(eta), - efficiency->GetAxis(1)->FindBin(pt), - efficiency->GetAxis(2)->FindBin(centrality), - efficiency->GetAxis(3)->FindBin(posZ)}; - return efficiency->GetBinContent(bins.data()); + + const double value = efficiencyHistogram->GetBinContent(efficiencyHistogram->FindBin(pt)); + return value == 0. ? -1. : 1. / value; } template @@ -816,9 +854,10 @@ struct EnergyFlowGfw { gfw->Clear(); for (const auto& track : tracks) { - const int pid = energy.weightMode.value == PtWeight ? Unidentified : particleId(track); + const bool needsParticleId = energy.weightMode.value != PtWeight || cfgEfficiency.cfgUsePIDEfficiencies; + const int pid = needsParticleId ? particleId(track) : Unidentified; const double et = transverseEnergy(track, pid); - const double weff = efficiencyWeight(track.eta(), track.pt(), centrality, collision.posZ()); + const double weff = getEfficiency(track.pt(), pid); const double wacc = acceptance ? acceptance->getNUA(track.phi(), track.eta(), collision.posZ()) : 1.; if (!std::isfinite(et) || !std::isfinite(weff) || !std::isfinite(wacc) || et <= 0. || weff <= 0. || wacc <= 0.) { continue; @@ -868,7 +907,7 @@ struct EnergyFlowGfw { void processRun2(CollisionsRun2::iterator const& collision, Tracks const& tracks, BCsRun2 const&, aod::Zdcs const&) { float spectators = -1.f; - if (!eventSelected(collision, collision.alias_bit(kINT7) && collision.sel7(), static_cast(tracks.size()), collision.centRun2V0M(), spectators)) { + if (!eventSelected(collision, run2EventSelected(collision), static_cast(tracks.size()), collision.centRun2V0M(), spectators)) { return; } if (cfgFillAcceptance) {