From 508938f1227c7e50ad8eb4f3a63168dd47b75d81 Mon Sep 17 00:00:00 2001 From: smaff92 Date: Sun, 9 Nov 2025 19:39:18 +0900 Subject: [PATCH 1/4] [PWGLF] temporary location for tutorial files, will restage them to the tutorial folder after O2AT --- PWGLF/Tasks/Resonances/CMakeLists.txt | 20 ++ PWGLF/Tasks/Resonances/phitutorial.cxx | 226 +++++++++++++++++++ PWGLF/Tasks/Resonances/phitutorial_step0.cxx | 135 +++++++++++ PWGLF/Tasks/Resonances/phitutorial_step1.cxx | 141 ++++++++++++ PWGLF/Tasks/Resonances/phitutorial_step2.cxx | 162 +++++++++++++ PWGLF/Tasks/Resonances/phitutorial_step3.cxx | 211 +++++++++++++++++ 6 files changed, 895 insertions(+) create mode 100644 PWGLF/Tasks/Resonances/phitutorial.cxx create mode 100644 PWGLF/Tasks/Resonances/phitutorial_step0.cxx create mode 100644 PWGLF/Tasks/Resonances/phitutorial_step1.cxx create mode 100644 PWGLF/Tasks/Resonances/phitutorial_step2.cxx create mode 100644 PWGLF/Tasks/Resonances/phitutorial_step3.cxx diff --git a/PWGLF/Tasks/Resonances/CMakeLists.txt b/PWGLF/Tasks/Resonances/CMakeLists.txt index c04f076bef2..f466c75e7e3 100644 --- a/PWGLF/Tasks/Resonances/CMakeLists.txt +++ b/PWGLF/Tasks/Resonances/CMakeLists.txt @@ -267,3 +267,23 @@ o2physics_add_dpl_workflow(phi-1020-spherocity-analysis SOURCES phi1020SpherocityAnalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial + SOURCES phitutorial.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phitutorial-step0 + SOURCES phitutorial_step0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial-step1 + SOURCES phitutorial_step1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial-step2 + SOURCES phitutorial_step2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial-step3 + SOURCES phitutorial_step3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Resonances/phitutorial.cxx b/PWGLF/Tasks/Resonances/phitutorial.cxx new file mode 100644 index 00000000000..1001b85268a --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial.cxx @@ -0,0 +1,226 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + histos.add("Nch_LSS_Minv", "Nch_LSS_Minv", kTH1F, {MinvAxis}); + + histos.add("Nch_ME_Minv", "Nch_ME_Minv", kTH1F, {MinvAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) + return false; + if (std::abs(event.posZ()) > 10) + return false; + if (!event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (!event.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (!event.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) + return false; + + return true; + }; + //********************************************// + template + bool trackSelection(const TracksType track) + { + if (!track.isGlobalTrack()) + return false; + if (track.pt() < 0.15) + return false; + if (std::abs(track.eta()) > 1.0) + return false; + + return true; + }; + //********************************************// + template + bool trackPIDKaon(const TrackPID& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + // TPC + if (std::abs(candidate.tpcNSigmaKa()) < 3) + tpcPIDPassed = true; + // TOF + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < 3) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + for (const auto& track : tracks) { + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (!trackSelection(trk1) || !trackSelection(trk2)) { + continue; + } + if (!trackPIDKaon(trk1) || !trackPIDKaon(trk2)) { + continue; + } + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } else { + histos.fill(HIST("Nch_LSS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial, processDataSameEvent, "process Data Same Event", false); + + //**************************************************************************************************************************// + + // MIXED EVENT + + //*********************************************************// + // DEFINITION OF SLICE CACHE, BINNING AND MIXING STRUCTURE + //*********************************************************// + Preslice perCollision = aod::track::collisionId; + std::vector zBins{10, -10, 10}; + std::vector multBins{VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}; + using BinningType = ColumnBinningPolicy; + BinningType binning{{zBins, multBins}, true}; + SameKindPair pair{binning, 5, -1, &cache}; + + void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + { + LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); + + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + if (!eventSelection(c1) || !eventSelection(c2)) + continue; + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (track1.sign() * track2.sign() > 0) + continue; + + if (!trackSelection(track1) || !trackSelection(track2)) { + continue; + } + if (!trackPIDKaon(track1) || !trackPIDKaon(track2)) { + continue; + } + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, mother; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + + mother = lDecayDaughter1 + lDecayDaughter2; + + histos.fill(HIST("Nch_ME_Minv"), mother.M()); + } + } + } // processMixedEvent + PROCESS_SWITCH(phitutorial, processDataMixedEvent, "process Data Mixed Event", false); +}; + +//***************************************// +// TASK COMPLETE! +//**************************************// + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx new file mode 100644 index 00000000000..480b653e5c6 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx @@ -0,0 +1,135 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step0 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) //This is required to extract good events + return false; + + return true; + }; + //********************************************// + //Space for more helper functions! + + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks){ + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + // Now, time to start coding the task! + // Keep in mind that: + // M_inv = sqrt( (E1+E2)^2 - |P1 + P2|^2 ) + // Where you use the energies and momenta of the individual Kaons. + + // You should fill: histos.fill(HIST("Minv"), M_inv), calculated as above. + + //Usefull tips: + // E = sqrt(p^2 + m^2). The Kaon mass is found above in the constant massKa + // pz = pT*sinh(eta) + // track.pt() + // track.eta(); + // std::sinh(x) + + // For more concise techinques, check out: + // ROOT::Math::PxPyPzMVector //Check google + // combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy.... //check ALICE O2 documentation + + for (const auto& track : tracks) { + histos.fill(HIST("Nch_pT"), track.pt()); + //.. + //.. + //.. + } + + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step0, processDataSameEvent, "process Data Same Event", false); + +//***************************************// +// TASK COMPLETE! +//**************************************// + +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx new file mode 100644 index 00000000000..3d510ea8cb8 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx @@ -0,0 +1,141 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step1 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) //This is required to extract good events + return false; + + return true; + }; + //********************************************// + //Space for more helper functions! + + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + // Now, we want to add some kind of filter for our tracks! + // Tracks we want to accept: + // track.isGlobalTrack() <.... this menas that it is a good track + // track.pt() >0.15 <.... we want to remove really low momentum tracks + // -0.8 0.15f; + // then you have to modify the subscription + // soa::Filtered const& tracks + + for (const auto& track : tracks) { + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step1, processDataSameEvent, "process Data Same Event", false); + +//***************************************// +// TASK COMPLETE! +//**************************************// + +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx new file mode 100644 index 00000000000..06f98893a6d --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx @@ -0,0 +1,162 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step2 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) //This is required to extract good events + return false; + + return true; + }; + //********************************************// + template + bool trackSelection(const TracksType track) + { + if (!track.isGlobalTrack()) + return false; + if (track.pt() < 0.15) + return false; + if (std::abs(track.eta()) > 1.0) + return false; + + return true; + }; + //Space for more helper functions! + //********************************************// + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + // Now, we want to add some PID to ensure that we are with a higher likelhood pairing Kaons. + // Three ways to do this: + // 1.) Directly cut on the tracks in the looping functions (not recommended) + + // 2.) Create a helper function above similar to trackSelection + + // 3.) Partition your tracks with a preselection by adding this outside of your process function: + // Partition kaon (nabs(aod::pidtpc::tpcNSigmaKa) <= X); // X is a cfg value or a hardcoded integer. + // Then inside the function: auto tracks1 = kaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); Do the same for tracks2. + + + //Getters for PID: + // tracks.tpcNSigmaKa() + // tracks.tofNSigmaKa() + // Good starting value for the selected nsigma value is "3". + // You might not want to have a STRICT TOF cut, a lot of tracks with good TPC PID does not have TOF information. You can make a conditional cut on TOF by only implementing the TOF cut if track.hasTOF() returns TRUE. + + for (const auto& track : tracks) { + if (!trackSelection(track)) { + continue; + } + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (!trackSelection(trk1) || !trackSelection(trk2)) { + continue; + } + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step2, processDataSameEvent, "process Data Same Event", false); + +//***************************************// +// TASK COMPLETE! +//**************************************// + +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx new file mode 100644 index 00000000000..566cee136a9 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx @@ -0,0 +1,211 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step3 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + + histos.add("Nch_LSS_Minv", "Nch_LSS_Minv", kTH1F, {MinvAxis}); + + histos.add("Nch_ME_Minv", "Nch_ME_Minv", kTH1F, {MinvAxis}); + + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) //This is required to extract good events + return false; + + return true; + }; + //********************************************// + template + bool trackSelection(const TracksType track) + { + if (!track.isGlobalTrack()) + return false; + if (track.pt() < 0.15) + return false; + if (std::abs(track.eta()) > 1.0) + return false; + + return true; + }; + + //********************************************// + + template + bool trackPIDKaon(const TrackPID& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + // TPC + if (std::abs(candidate.tpcNSigmaKa()) < 3) + tpcPIDPassed = true; + // TOF + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < 3) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + //Last step, we want to remove the cominbatorial background to get a clean peak. We want to fill our new two booked historams, Nch_LSS_Minv and Nch_ME_Minv + + //LSS is easy, you simply need to fill the histogram if the conjugate argument below is NOT true. + // For event mixing, we have to now copy our logic into a new process function below, and iterate over track pairs between different events! + + for (const auto& track : tracks) { + if (!trackSelection(track)) { + continue; + } + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (!trackSelection(trk1) || !trackSelection(trk2)) { + continue; + } + if (!trackPIDKaon(trk1) || !trackPIDKaon(trk2)) { + continue; + } + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step3, processDataSameEvent, "process Data Same Event", false); + + //**************************************************************************************************************************// + + // MIXED EVENT + + //*********************************************************// + // DEFINITION OF SLICE CACHE, BINNING AND MIXING STRUCTURE + //*********************************************************// + Preslice perCollision = aod::track::collisionId; + //We ensure here that we mix events that have relatively similar characteristics. + std::vector zBins{10, -10, 10}; + std::vector multBins{VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}; + using BinningType = ColumnBinningPolicy; + BinningType binning{{zBins, multBins}, true}; + SameKindPair pair{binning, 5, -1, &cache}; + + void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks)//notice the collisions subscrition, it is not an iterator here! + { + + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + if (!eventSelection(c1) || !eventSelection(c2)) + continue; + //Fill your event mixing logic here. + //.. + //.. + //.. + } //pairs + } // processMixedEvent + PROCESS_SWITCH(phitutorial_step3, processDataMixedEvent, "process Data Mixed Event", false); + +//***************************************// +// TASK COMPLETE! +//**************************************// + +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; From 16b3d76dd89686d09b550554e991c88d6d23c61a Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Sun, 9 Nov 2025 10:41:32 +0000 Subject: [PATCH 2/4] Please consider the following formatting changes --- PWGLF/Tasks/Resonances/phitutorial.cxx | 2 +- PWGLF/Tasks/Resonances/phitutorial_step0.cxx | 36 +++++++++----------- PWGLF/Tasks/Resonances/phitutorial_step1.cxx | 18 +++++----- PWGLF/Tasks/Resonances/phitutorial_step2.cxx | 32 ++++++++--------- PWGLF/Tasks/Resonances/phitutorial_step3.cxx | 34 +++++++++--------- 5 files changed, 57 insertions(+), 65 deletions(-) diff --git a/PWGLF/Tasks/Resonances/phitutorial.cxx b/PWGLF/Tasks/Resonances/phitutorial.cxx index 1001b85268a..9034004daa6 100644 --- a/PWGLF/Tasks/Resonances/phitutorial.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial.cxx @@ -57,7 +57,7 @@ struct phitutorial { histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); histos.add("Nch_LSS_Minv", "Nch_LSS_Minv", kTH1F, {MinvAxis}); - + histos.add("Nch_ME_Minv", "Nch_ME_Minv", kTH1F, {MinvAxis}); }; // end of init diff --git a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx index 480b653e5c6..25a66f53a98 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx @@ -71,14 +71,13 @@ struct phitutorial_step0 { template bool eventSelection(const EventType event) { - if (!event.sel8()) //This is required to extract good events + if (!event.sel8()) // This is required to extract good events return false; - + return true; }; //********************************************// - //Space for more helper functions! - + // Space for more helper functions! //********************************************// // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS @@ -86,7 +85,8 @@ struct phitutorial_step0 { // SAME EVENT int nEvents = 0; - void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks){ + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { nEvents++; if ((nEvents + 1) % 10000 == 0) { std::cout << "Processed Data Events: " << nEvents << std::endl; @@ -99,16 +99,16 @@ struct phitutorial_step0 { // Keep in mind that: // M_inv = sqrt( (E1+E2)^2 - |P1 + P2|^2 ) // Where you use the energies and momenta of the individual Kaons. - + // You should fill: histos.fill(HIST("Minv"), M_inv), calculated as above. - - //Usefull tips: - // E = sqrt(p^2 + m^2). The Kaon mass is found above in the constant massKa - // pz = pT*sinh(eta) - // track.pt() - // track.eta(); - // std::sinh(x) - + + // Usefull tips: + // E = sqrt(p^2 + m^2). The Kaon mass is found above in the constant massKa + // pz = pT*sinh(eta) + // track.pt() + // track.eta(); + // std::sinh(x) + // For more concise techinques, check out: // ROOT::Math::PxPyPzMVector //Check google // combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy.... //check ALICE O2 documentation @@ -120,14 +120,12 @@ struct phitutorial_step0 { //.. } - } // proccessSameEvent PROCESS_SWITCH(phitutorial_step0, processDataSameEvent, "process Data Same Event", false); -//***************************************// -// TASK COMPLETE! -//**************************************// - + //***************************************// + // TASK COMPLETE! + //**************************************// }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx index 3d510ea8cb8..fdfe69538f4 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx @@ -72,14 +72,13 @@ struct phitutorial_step1 { template bool eventSelection(const EventType event) { - if (!event.sel8()) //This is required to extract good events + if (!event.sel8()) // This is required to extract good events return false; - + return true; }; //********************************************// - //Space for more helper functions! - + // Space for more helper functions! //********************************************// // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS @@ -102,14 +101,14 @@ struct phitutorial_step1 { // track.isGlobalTrack() <.... this menas that it is a good track // track.pt() >0.15 <.... we want to remove really low momentum tracks // -0.8 0.15f; // then you have to modify the subscription // soa::Filtered const& tracks - + for (const auto& track : tracks) { histos.fill(HIST("Nch_pT"), track.pt()); } @@ -130,10 +129,9 @@ struct phitutorial_step1 { } // proccessSameEvent PROCESS_SWITCH(phitutorial_step1, processDataSameEvent, "process Data Same Event", false); -//***************************************// -// TASK COMPLETE! -//**************************************// - + //***************************************// + // TASK COMPLETE! + //**************************************// }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx index 06f98893a6d..c4e238a6b7f 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx @@ -72,9 +72,9 @@ struct phitutorial_step2 { template bool eventSelection(const EventType event) { - if (!event.sel8()) //This is required to extract good events + if (!event.sel8()) // This is required to extract good events return false; - + return true; }; //********************************************// @@ -89,9 +89,9 @@ struct phitutorial_step2 { return false; return true; - }; - //Space for more helper functions! - //********************************************// + }; + // Space for more helper functions! + //********************************************// //********************************************// // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS @@ -112,20 +112,19 @@ struct phitutorial_step2 { // Now, we want to add some PID to ensure that we are with a higher likelhood pairing Kaons. // Three ways to do this: // 1.) Directly cut on the tracks in the looping functions (not recommended) - + // 2.) Create a helper function above similar to trackSelection - + // 3.) Partition your tracks with a preselection by adding this outside of your process function: // Partition kaon (nabs(aod::pidtpc::tpcNSigmaKa) <= X); // X is a cfg value or a hardcoded integer. // Then inside the function: auto tracks1 = kaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); Do the same for tracks2. + // Getters for PID: + // tracks.tpcNSigmaKa() + // tracks.tofNSigmaKa() + // Good starting value for the selected nsigma value is "3". + // You might not want to have a STRICT TOF cut, a lot of tracks with good TPC PID does not have TOF information. You can make a conditional cut on TOF by only implementing the TOF cut if track.hasTOF() returns TRUE. - //Getters for PID: - // tracks.tpcNSigmaKa() - // tracks.tofNSigmaKa() - // Good starting value for the selected nsigma value is "3". - // You might not want to have a STRICT TOF cut, a lot of tracks with good TPC PID does not have TOF information. You can make a conditional cut on TOF by only implementing the TOF cut if track.hasTOF() returns TRUE. - for (const auto& track : tracks) { if (!trackSelection(track)) { continue; @@ -151,10 +150,9 @@ struct phitutorial_step2 { } // proccessSameEvent PROCESS_SWITCH(phitutorial_step2, processDataSameEvent, "process Data Same Event", false); -//***************************************// -// TASK COMPLETE! -//**************************************// - + //***************************************// + // TASK COMPLETE! + //**************************************// }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx index 566cee136a9..2c488381e17 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx @@ -58,9 +58,8 @@ struct phitutorial_step3 { histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); histos.add("Nch_LSS_Minv", "Nch_LSS_Minv", kTH1F, {MinvAxis}); - - histos.add("Nch_ME_Minv", "Nch_ME_Minv", kTH1F, {MinvAxis}); + histos.add("Nch_ME_Minv", "Nch_ME_Minv", kTH1F, {MinvAxis}); }; // end of init @@ -77,9 +76,9 @@ struct phitutorial_step3 { template bool eventSelection(const EventType event) { - if (!event.sel8()) //This is required to extract good events + if (!event.sel8()) // This is required to extract good events return false; - + return true; }; //********************************************// @@ -96,7 +95,7 @@ struct phitutorial_step3 { return true; }; - //********************************************// + //********************************************// template bool trackPIDKaon(const TrackPID& candidate) @@ -136,11 +135,11 @@ struct phitutorial_step3 { if (!eventSelection(collision)) return; - //Last step, we want to remove the cominbatorial background to get a clean peak. We want to fill our new two booked historams, Nch_LSS_Minv and Nch_ME_Minv + // Last step, we want to remove the cominbatorial background to get a clean peak. We want to fill our new two booked historams, Nch_LSS_Minv and Nch_ME_Minv + + // LSS is easy, you simply need to fill the histogram if the conjugate argument below is NOT true. + // For event mixing, we have to now copy our logic into a new process function below, and iterate over track pairs between different events! - //LSS is easy, you simply need to fill the histogram if the conjugate argument below is NOT true. - // For event mixing, we have to now copy our logic into a new process function below, and iterate over track pairs between different events! - for (const auto& track : tracks) { if (!trackSelection(track)) { continue; @@ -178,32 +177,31 @@ struct phitutorial_step3 { // DEFINITION OF SLICE CACHE, BINNING AND MIXING STRUCTURE //*********************************************************// Preslice perCollision = aod::track::collisionId; - //We ensure here that we mix events that have relatively similar characteristics. + // We ensure here that we mix events that have relatively similar characteristics. std::vector zBins{10, -10, 10}; std::vector multBins{VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}; using BinningType = ColumnBinningPolicy; BinningType binning{{zBins, multBins}, true}; SameKindPair pair{binning, 5, -1, &cache}; - void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks)//notice the collisions subscrition, it is not an iterator here! + void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) // notice the collisions subscrition, it is not an iterator here! { - + for (const auto& [c1, tracks1, c2, tracks2] : pair) { if (!eventSelection(c1) || !eventSelection(c2)) continue; - //Fill your event mixing logic here. + // Fill your event mixing logic here. //.. //.. //.. - } //pairs + } // pairs } // processMixedEvent PROCESS_SWITCH(phitutorial_step3, processDataMixedEvent, "process Data Mixed Event", false); - -//***************************************// -// TASK COMPLETE! -//**************************************// + //***************************************// + // TASK COMPLETE! + //**************************************// }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { From 1cdb275a786fe9514d7ac73f8e00de618306fbb4 Mon Sep 17 00:00:00 2001 From: smaff92 Date: Sun, 9 Nov 2025 19:59:23 +0900 Subject: [PATCH 3/4] [PWGLF] temporary location for tutorial files, will restage them to the tutorial folder after O2AT. Now added iostream to comply with Megalinter --- PWGLF/Tasks/Resonances/phitutorial.cxx | 1 + PWGLF/Tasks/Resonances/phitutorial_step0.cxx | 1 + PWGLF/Tasks/Resonances/phitutorial_step1.cxx | 1 + PWGLF/Tasks/Resonances/phitutorial_step2.cxx | 1 + PWGLF/Tasks/Resonances/phitutorial_step3.cxx | 1 + 5 files changed, 5 insertions(+) diff --git a/PWGLF/Tasks/Resonances/phitutorial.cxx b/PWGLF/Tasks/Resonances/phitutorial.cxx index 9034004daa6..5e93f7c39bc 100644 --- a/PWGLF/Tasks/Resonances/phitutorial.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial.cxx @@ -30,6 +30,7 @@ #include // C++ includes +#include #include #include diff --git a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx index 25a66f53a98..16394389c91 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx @@ -30,6 +30,7 @@ #include // C++ includes +#include #include #include diff --git a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx index fdfe69538f4..32b1760b809 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx @@ -30,6 +30,7 @@ #include // C++ includes +#include #include #include diff --git a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx index c4e238a6b7f..0a97f6d1afe 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx @@ -30,6 +30,7 @@ #include // C++ includes +#include #include #include diff --git a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx index 2c488381e17..27746974027 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx @@ -30,6 +30,7 @@ #include // C++ includes +#include #include #include From bbe681644fa80f478bc9f5307b4e0ed94f93c470 Mon Sep 17 00:00:00 2001 From: smaff92 Date: Mon, 10 Nov 2025 21:49:53 +0900 Subject: [PATCH 4/4] [PWGLF] temporary location for tutorial files, will restage them to the tutorial folder after O2AT. Now added iostream to comply with Megalinter --- PWGLF/Tasks/Resonances/phitutorial_step3.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx index 27746974027..1ccf59aa9c2 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx @@ -187,6 +187,7 @@ struct phitutorial_step3 { void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) // notice the collisions subscrition, it is not an iterator here! { + LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); for (const auto& [c1, tracks1, c2, tracks2] : pair) {