From 9d1f193231f31485e7efaabeb28cb6c7b9885539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Mon, 2 Feb 2026 12:36:36 +0100 Subject: [PATCH 1/2] AddTask --- EventFiltering/CMakeLists.txt | 5 + EventFiltering/PWGHF/H2fromLbFilter.cxx | 247 ++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 EventFiltering/PWGHF/H2fromLbFilter.cxx diff --git a/EventFiltering/CMakeLists.txt b/EventFiltering/CMakeLists.txt index 311f797b6db..0d67ee1fd64 100644 --- a/EventFiltering/CMakeLists.txt +++ b/EventFiltering/CMakeLists.txt @@ -111,3 +111,8 @@ o2physics_add_dpl_workflow(lf-f1proton-filter SOURCES PWGLF/filterdoublephi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(h2fromlbfilter + SOURCES PWGHF/H2fromLbFilter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/EventFiltering/PWGHF/H2fromLbFilter.cxx b/EventFiltering/PWGHF/H2fromLbFilter.cxx new file mode 100644 index 00000000000..930b8ef6069 --- /dev/null +++ b/EventFiltering/PWGHF/H2fromLbFilter.cxx @@ -0,0 +1,247 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \brief A filter task for non prompt deuterons +/// \author Marta Razza marta.razza@cern.ch +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +/// \since Dec 17, 2025 + +// #include "../filterTables.h" + +#include "PWGLF/DataModel/LFParticleIdentification.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackParametrization.h" + +#include "TVector3.h" + +#include + +struct H2fromLbFilter { + + // Recall the output table + // Produces table; + + o2::framework::Configurable nBinsPt{"nBinsPt", 100, "N bins in pT histo"}; + + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + // Define a histograms and registries + o2::framework::HistogramRegistry QAHistos{"QAHistos", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject, false, true}; + o2::framework::OutputObj hProcessedEvents{TH1D("hProcessedEvents", "Event filtered;; Number of events", 6, 0., 6.)}; + + o2::framework::ConfigurableAxis pTAxis{"pTAxis", {200, -10.f, 10.f}, "p_{T} GeV/c"}; + o2::framework::ConfigurableAxis nSigmaAxis{"nSigmaAxis", {200, -10.f, 10.f}, "p_{T} GeV/c"}; + o2::framework::ConfigurableAxis DCAxyAxis{"DCAxyAxis", {1000, -0.2f, 0.2f}, "DCA xy (cm)"}; + o2::framework::ConfigurableAxis DCAzAxis{"DCAzAxis", {1000, -0.2f, 0.2f}, "DCA z (cm)"}; + + o2::framework::Configurable cutzvertex{"cutzvertex", 20.0f, "Accepted z-vertex range"}; // 20 cm + o2::framework::Configurable isTVX{"isTVX", true, "isTVX event selection"}; + o2::framework::Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", true, "isNoTimeFrameBorder event selection"}; + o2::framework::Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", true, "isNoITSROFrameBorder event selection"}; + o2::framework::Configurable cfgTPCNsigma{"cfgTPCNsigma", 4.0f, "TPC n sigma for deuteron PID"}; + o2::framework::Configurable cfgTOFNsigma{"cfgTOFNsigma", 4.0f, "TOF n sigma for deuteron PID"}; + o2::framework::Configurable cfgEta{"cfgEta", 0.8f, "Track eta selection"}; + o2::framework::Configurable cfgTPCNclsFound{"cfgTPCNclsFound", 100, "Minimum TPC clusters found"}; + o2::framework::Configurable cfgTPCChi2Ncl{"cfgTPCChi2Ncl", 4.0f, "Maximum TPC chi2 per N clusters"}; + o2::framework::Configurable cfgITSChi2Ncl{"cfgITSChi2Ncl", 36.0f, "Maximum ITS chi2 per N clusters"}; + o2::framework::Configurable cfgITScls{"cfgITScls", 2, "Minimum ITS clusters"}; + o2::framework::Configurable cfgMaxPt{"cfgMaxPt", 5.0f, "Maximum pT cut"}; + o2::framework::Configurable cfgMinPt{"cfgMinPt", 1.0f, "Maximum pT cut"}; + o2::framework::Configurable cfgDCAcut{"cfgDCAcut", 0.003f, "DCA cut for non prompt deuteron"}; + using myCompleteTracks = o2::soa::Join; + o2::framework::Service ccdb; + + void init(o2::framework::InitContext&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + + o2::framework::AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + + // general QA histograms + QAHistos.add("hVtxZ", "Z-Vertex distribution after selection;Z (cm)", o2::framework::HistType::kTH1F, {{100, -50, 50}}); + QAHistos.add("hDCAxyVsPt", "DCAxy #bar{d} vs p_{T}", {o2::framework::HistType::kTH2D, {pTAxis, DCAxyAxis}}); + QAHistos.add("hDCAzVsPt", "DCAz #bar{d} vs p_{T}", {o2::framework::HistType::kTH2D, {pTAxis, DCAzAxis}}); + QAHistos.add("hnSigmaTPCVsPt", "n#sigma TPC vs p_{T} for #bar{d} hypothesis; p_{T} (GeV/c); n#sigma TPC", {o2::framework::HistType::kTH2D, {pTAxis, nSigmaAxis}}); + QAHistos.add("hnSigmaTOFVsPt", "n#sigma TOF vs p_{T} for #bar{d} hypothesis; p_{T} (GeV/c); n#sigma TOF", {o2::framework::HistType::kTH2D, {pTAxis, nSigmaAxis}}); + QAHistos.add("ptAntiDeuteron", "ptAntiDeuteron", {o2::framework::HistType::kTH1F, {ptAxis}}); + QAHistos.add("etaAntideuteron", "etaAntideuteron", {o2::framework::HistType::kTH1F, {{100, -1.0f, 1.0f, "eta #bar{d}"}}}); + QAHistos.add("hDCAxyVsPt-pre_selection", "DCAxy #bar{d} vs p_{T}", {o2::framework::HistType::kTH2D, {pTAxis, DCAxyAxis}}); + QAHistos.add("hDCAzVsPt-pre-selection", "DCAz #bar{d} vs p_{T}", {o2::framework::HistType::kTH2D, {pTAxis, DCAzAxis}}); + + // processed events + hProcessedEvents->GetXaxis()->SetBinLabel(1, "Events processed"); + hProcessedEvents->GetXaxis()->SetBinLabel(2, "TVX"); + hProcessedEvents->GetXaxis()->SetBinLabel(3, "TF border"); + hProcessedEvents->GetXaxis()->SetBinLabel(4, "ITS-RO border"); + hProcessedEvents->GetXaxis()->SetBinLabel(5, "z-vertex"); + hProcessedEvents->GetXaxis()->SetBinLabel(6, "Trigger"); + } + + // Tables + using CollisionCandidates = o2::soa::Join; + using TrackCandidates = o2::soa::Join; + + // Single-Track Selection + template + bool passedSingleTrackSelection(const T1& track) + { + // Single-Track Selections + if (std::abs(track.eta()) > cfgEta) + return false; + if (!track.hasITS()) + return false; + if (!track.hasTPC()) + return false; + if (!track.hasTOF()) + return false; + if (track.tpcNClsFound() < cfgTPCNclsFound) + return false; + if (track.tpcChi2NCl() > cfgTPCChi2Ncl) + return false; + if (track.itsChi2NCl() > cfgITSChi2Ncl) + return false; + if (track.itsNCls() < cfgITScls) + return false; + if (track.pt() > cfgMaxPt) + return false; + if (track.pt() < cfgMinPt) + return false; + if (track.sign() > 0) + return false; + + return true; + } + + /*void fillTriggerTable(bool keepEvent[]) + { + table(keepEvent[0]); + }*/ + + o2::framework::Preslice trackIndicesPerCollision = o2::aod::track_association::collisionId; + int mCurrentRun = -1; + void process(CollisionCandidates const& collisions, + o2::aod::TrackAssoc const& trackIndices, + TrackCandidates const& tracks, + o2::aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) // start loop over collisions + { + LOG(info) << "Processing collision with ID: " << collision.globalIndex(); + if (mCurrentRun != collision.bc_as().runNumber()) { // If the run is new then we need to initialize the propagator field + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", collision.bc_as().timestamp()); + o2::base::Propagator::initFieldFromGRP(grpo); + mCurrentRun = collision.bc_as().runNumber(); + } + + // Is event good? keepEvent[0] = non promp deuteron + bool keepEvent[1]{}; // explicitly zero-initialised + hProcessedEvents->Fill(0.5); + // Event selection cuts + if (isTVX && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + // fillTriggerTable(keepEvent); + continue; + } + hProcessedEvents->Fill(1.5); + if (isNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + // fillTriggerTable(keepEvent); + continue; + } + hProcessedEvents->Fill(2.5); + if (isNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + // fillTriggerTable(keepEvent); + continue; + } + hProcessedEvents->Fill(3.5); + if (std::abs(collision.posZ()) > cutzvertex) { + // fillTriggerTable(keepEvent); + continue; + } + LOG(info) << "Accepted collision!"; + hProcessedEvents->Fill(4.5); + QAHistos.fill(HIST("hVtxZ"), collision.posZ()); + + // Loop over tracks + LOG(info) << "Trying the slice"; + const auto& trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + LOG(info) << "Sliced!"; + for (const auto& trackId : trackIdsThisCollision) { // start loop over tracks + LOG(info) << "Processing track with ID: " << trackId.trackId(); + const auto& track = tracks.rawIteratorAt(trackId.trackId()); + + std::array dca{track.dcaXY(), track.dcaZ()}; + std::array pVec = track.pVector(); + + if (track.collisionId() != collision.globalIndex()) { + auto trackPar = getTrackParCov(track); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, noMatCorr, &dca); + getPxPyPz(trackPar, pVec); + } + + if (!passedSingleTrackSelection(track)) { + continue; + } + + const bool isTOFDe = std::abs(track.tofNSigmaDe()) < cfgTOFNsigma; + const bool isTPCDe = std::abs(track.tpcNSigmaDe()) < cfgTPCNsigma; + + if (isTPCDe && isTOFDe) { + + QAHistos.fill(HIST("hDCAxyVsPt-pre_selection"), track.pt(), dca[0]); + QAHistos.fill(HIST("hDCAzVsPt-pre-selection"), track.pt(), dca[1]); + if (std::abs(dca[0]) < cfgDCAcut) { + continue; + } + keepEvent[0] = true; + QAHistos.fill(HIST("ptAntiDeuteron"), track.pt()); + QAHistos.fill(HIST("etaAntideuteron"), track.eta()); + QAHistos.fill(HIST("hDCAxyVsPt"), track.pt(), dca[0]); + QAHistos.fill(HIST("hDCAzVsPt"), track.pt(), dca[1]); + QAHistos.fill(HIST("hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe()); + QAHistos.fill(HIST("hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe()); + } + + } // end track loop + if (keepEvent[0]) { + hProcessedEvents->Fill(5.5); + } + // fillTriggerTable(keepEvent); + } + } +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + return o2::framework::WorkflowSpec{o2::framework::adaptAnalysisTask(cfgc)}; +} From abc1ff8e0d397e6d7c7be83971db1ac6560b7ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Mon, 2 Feb 2026 12:37:15 +0100 Subject: [PATCH 2/2] UpdateLog --- EventFiltering/PWGHF/H2fromLbFilter.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EventFiltering/PWGHF/H2fromLbFilter.cxx b/EventFiltering/PWGHF/H2fromLbFilter.cxx index 930b8ef6069..5b56c29dca1 100644 --- a/EventFiltering/PWGHF/H2fromLbFilter.cxx +++ b/EventFiltering/PWGHF/H2fromLbFilter.cxx @@ -158,7 +158,7 @@ struct H2fromLbFilter { { for (const auto& collision : collisions) // start loop over collisions { - LOG(info) << "Processing collision with ID: " << collision.globalIndex(); + LOG(debug) << "Processing collision with ID: " << collision.globalIndex(); if (mCurrentRun != collision.bc_as().runNumber()) { // If the run is new then we need to initialize the propagator field o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", collision.bc_as().timestamp()); o2::base::Propagator::initFieldFromGRP(grpo); @@ -188,16 +188,16 @@ struct H2fromLbFilter { // fillTriggerTable(keepEvent); continue; } - LOG(info) << "Accepted collision!"; + LOG(debug) << "Accepted collision!"; hProcessedEvents->Fill(4.5); QAHistos.fill(HIST("hVtxZ"), collision.posZ()); // Loop over tracks - LOG(info) << "Trying the slice"; + LOG(debug) << "Trying the slice"; const auto& trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); - LOG(info) << "Sliced!"; + LOG(debug) << "Sliced!"; for (const auto& trackId : trackIdsThisCollision) { // start loop over tracks - LOG(info) << "Processing track with ID: " << trackId.trackId(); + LOG(debug) << "Processing track with ID: " << trackId.trackId(); const auto& track = tracks.rawIteratorAt(trackId.trackId()); std::array dca{track.dcaXY(), track.dcaZ()};