From f9ac39b05a1aea2cda23088bfdfe1e26b922e5a0 Mon Sep 17 00:00:00 2001 From: Daiki Sekihata Date: Fri, 13 Feb 2026 19:07:35 +0100 Subject: [PATCH 1/2] PWGEM/Dilepton: add option to calculate TOF n sigma with delta BC with TTCA --- .../TableProducer/skimmerPrimaryElectron.cxx | 328 ++++++++++++------ PWGEM/Dilepton/Utils/MlResponseO2Track.h | 31 +- 2 files changed, 249 insertions(+), 110 deletions(-) diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx index f28cf0b8755..7ddcadb3dc2 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx @@ -54,7 +54,7 @@ using MyCollisionsWithSWT = soa::Join; using MyTracks = soa::Join; + aod::pidTOFFullEl, /*aod::pidTOFFullMu,*/ aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr, aod::pidTOFbeta, aod::TOFSignal, aod::TOFEvTime>; using MyTrack = MyTracks::iterator; using MyTracksMC = soa::Join; using MyTrackMC = MyTracksMC::iterator; @@ -101,11 +101,10 @@ struct skimmerPrimaryElectron { Configurable min_pin_for_pion_rejection{"min_pin_for_pion_rejection", 0.0, "pion rejection is applied above this pin"}; // this is used only in TOFreq Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 0.5, "pion rejection is applied below this pin"}; Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; - Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; - Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; Configurable storeOnlyTrueElectronMC{"storeOnlyTrueElectronMC", false, "Flag to store only true electron in MC"}; Configurable minNelectron{"minNelectron", 0, "min number of electron candidates per collision"}; + Configurable useTOFNSigmaDeltaBC{"useTOFNSigmaDeltaBC", false, "Flag to shift delta BC for TOF n sigma (only with TTCA)"}; // configuration for PID ML Configurable usePIDML{"usePIDML", false, "Flag to use PID ML"}; @@ -131,8 +130,9 @@ struct skimmerPrimaryElectron { const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; o2::base::MatLayerCylSet* lut = nullptr; o2::ccdb::CcdbApi ccdbApi; + Service mTOFResponse; - void init(InitContext&) + void init(InitContext& initContext) { mRunNumber = 0; d_bz = 0; @@ -143,6 +143,9 @@ struct skimmerPrimaryElectron { ccdb->setFatalWhenNull(false); ccdbApi.init(ccdburl); + LOGF(info, "intializing TOFResponse"); + mTOFResponse->initSetup(ccdb, initContext); + if (fillQAHistogram) { fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{4000, -20, 20}}, false); @@ -171,9 +174,9 @@ struct skimmerPrimaryElectron { fRegistry.add("Track/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); // fRegistry.add("Track/hTOFNsigmaMu", "TOF n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/hTOFNsigmaKa", "TOF n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/hTOFNsigmaPr", "TOF n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + // fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + // fRegistry.add("Track/hTOFNsigmaKa", "TOF n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + // fRegistry.add("Track/hTOFNsigmaPr", "TOF n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); fRegistry.add("Track/hMeanClusterSizeITSib", "mean cluster size ITSib;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); fRegistry.add("Track/hMeanClusterSizeITSob", "mean cluster size ITSob;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); @@ -204,6 +207,7 @@ struct skimmerPrimaryElectron { mlResponseSingleTrack.cacheInputFeaturesIndices(namesInputFeatures); mlResponseSingleTrack.cacheBinningIndex(nameBinningFeature); mlResponseSingleTrack.init(enableOptimizations.value); + mlResponseSingleTrack.useReassociatedTOF(useTOFNSigmaDeltaBC.value); } // end of PID ML } @@ -279,11 +283,12 @@ struct skimmerPrimaryElectron { } } - if (requireTOF && !(track.hasTOF() && std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl)) { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + if (requireTOF && !(track.hasTOF() && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl)) { return false; } - if (!track.hasITS()) { + if (!track.hasITS() || !track.hasTPC()) { return false; } @@ -297,30 +302,24 @@ struct skimmerPrimaryElectron { return false; } - if (!includeITSsa && (!track.hasITS() || !track.hasTPC())) { + if (track.tpcChi2NCl() < 0.f || maxchi2tpc < track.tpcChi2NCl()) { return false; } - if (track.hasTPC()) { - if (track.tpcChi2NCl() < 0.f || maxchi2tpc < track.tpcChi2NCl()) { - return false; - } - - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { - return false; - } + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } - if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { - return false; - } + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; } o2::dataformats::DCA mDcaInfoCov; @@ -356,10 +355,6 @@ struct skimmerPrimaryElectron { return false; } - if ((track.hasITS() && !track.hasTPC() && !track.hasTOF() && !track.hasTRD()) && maxpt_itssa < trackParCov.getPt()) { - return false; - } - int total_cluster_size = 0, nl = 0; for (unsigned int layer = 0; layer < 7; layer++) { int cluster_size_per_layer = track.itsClsSizeInLayer(layer); @@ -380,12 +375,9 @@ struct skimmerPrimaryElectron { bool isElectron(TCollision const& collision, TTrack const& track, float& probaEl) { probaEl = 1.f; - if (includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { - return true; - } - if (usePIDML) { - if (!isElectron_TOFif(track)) { + if (!isElectron_TOFif(track, collision)) { + probaEl = 0.0; return false; } o2::dataformats::DCA mDcaInfoCov; @@ -396,19 +388,11 @@ struct skimmerPrimaryElectron { mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); if (!isPropOK) { + probaEl = 0.0; return false; } - std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision); - float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision); - - // std::vector outputs = {}; - // bool isSelected = mlResponseSingleTrack.isSelectedMl(inputFeatures, binningFeature, outputs); // 0: hadron, 1:electron - // probaEl = outputs[1]; - // outputs.clear(); - // outputs.shrink_to_fit(); - - // std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision); - // float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision); + std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision, mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); int pbin = lower_bound(binsMl.value.begin(), binsMl.value.end(), binningFeature) - binsMl.value.begin() - 1; if (pbin < 0) { @@ -420,23 +404,28 @@ struct skimmerPrimaryElectron { probaEl = mlResponseSingleTrack.getModelOutput(inputFeatures, pbin)[1]; // 0: hadron, 1:electron return probaEl > cutsMl.value[pbin]; - // return isSelected; } else { - return isElectron_TPChadrej(track) || isElectron_TOFreq(track); + probaEl = 1.f; + return isElectron_TPChadrej(track, collision) || isElectron_TOFreq(track, collision); } } - template - bool isElectron_TOFif(TTrack const& track) + template + bool isElectron_TOFif(TTrack const& track, TCollision const& collision) { + // collisionId must be collisionId after reassociation. + // track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCascade.globalBC()) + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; bool is_EL_TPC = minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl; - bool is_EL_TOF = track.hasTOF() ? (std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl) : true; // TOFif + bool is_EL_TOF = track.hasTOF() ? (std::fabs(tofNSigmaEl) < maxTOFNsigmaEl) : true; // TOFif return is_EL_TPC && is_EL_TOF; } - template - bool isElectron_TPChadrej(TTrack const& track) + template + bool isElectron_TPChadrej(TTrack const& track, TCollision const& collision) { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { return false; } @@ -449,19 +438,21 @@ struct skimmerPrimaryElectron { if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { return false; } - if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(track.tofNSigmaEl()))) { + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(tofNSigmaEl))) { return false; } return true; } - template - bool isElectron_TOFreq(TTrack const& track) + template + bool isElectron_TOFreq(TTrack const& track, TCollision const& collision) { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && (min_pin_for_pion_rejection < track.tpcInnerParam() && track.tpcInnerParam() < max_pin_for_pion_rejection)) { return false; } - return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl; + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl; } template @@ -486,6 +477,9 @@ struct skimmerPrimaryElectron { float phi_recalc = trackParCov.getPhi(); o2::math_utils::bringTo02Pi(phi_recalc); + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + float beta = mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); float mcTunedTPCSignal = 0.f; if constexpr (isMC) { @@ -498,7 +492,7 @@ struct skimmerPrimaryElectron { track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusPID(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), track.tpcChi2NCl(), track.tpcInnerParam(), track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.beta(), track.tofNSigmaEl(), /*track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(),*/ + beta, tofNSigmaEl, track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), isAssociatedToMPC, false, probaEl, mcTunedTPCSignal); @@ -581,12 +575,12 @@ struct skimmerPrimaryElectron { fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); fRegistry.fill(HIST("Track/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); fRegistry.fill(HIST("Track/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); - fRegistry.fill(HIST("Track/hTOFbeta"), trackParCov.getP(), track.beta()); - fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFbeta"), trackParCov.getP(), beta); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), tofNSigmaEl); // fRegistry.fill(HIST("Track/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); - fRegistry.fill(HIST("Track/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); - fRegistry.fill(HIST("Track/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); + // fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); + // fRegistry.fill(HIST("Track/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); + // fRegistry.fill(HIST("Track/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), trackParCov.getP(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))); fRegistry.fill(HIST("Track/hMeanClusterSizeITSib"), trackParCov.getP(), static_cast(total_cluster_size_ib) / static_cast(nl_ib) * std::cos(std::atan(trackParCov.getTgl()))); fRegistry.fill(HIST("Track/hMeanClusterSizeITSob"), trackParCov.getP(), static_cast(total_cluster_size_ob) / static_cast(nl_ob) * std::cos(std::atan(trackParCov.getTgl()))); @@ -595,23 +589,103 @@ struct skimmerPrimaryElectron { } } + template + void calculateTOFNSigmaWithReassociation(TCollisions const& collisions, TBCs const&, TTracks const& tracks, TTrackAssoc const& trackIndices) + { + if (useTOFNSigmaDeltaBC) { + if constexpr (withTTCA) { + for (const auto& collision : collisions) { + if (mapCollisionTime.find(collision.globalIndex()) == mapCollisionTime.end()) { + continue; + } + auto bcCollision = collision.template bc_as(); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + + if (track.hasTOF() && track.has_collision()) { // TTCA may use orphan tracks. + auto bcTrack = track.template collision_as().template bc_as(); + float tofNSigmaEl = mTOFResponse->nSigma(track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()), track.tofExpMom(), track.length(), track.p(), track.eta(), mapCollisionTime[collision.globalIndex()], mapCollisionTimeError[collision.globalIndex()]); + float beta = track.length() / (track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()) - mapCollisionTime[collision.globalIndex()]) / (TMath::C() * 1e+2 * 1e-12); + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = tofNSigmaEl; + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = beta; + } else { + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + } + + } // end of track loop + } // end of collision loop + } else { + for (const auto& collision : collisions) { + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + } + } // end of track loop + } // end of collision loop + } else { + if constexpr (withTTCA) { + for (const auto& collision : collisions) { + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + } // end of track loop + } // end of collision loop + } else { + for (const auto& collision : collisions) { + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + } + } // end of track loop + } // end of collision loop + } + } + Preslice trackIndicesPerCollision = aod::track_association::collisionId; std::vector> stored_trackIds; - Filter trackFilter = o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true; + Filter trackFilter = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; using MyFilteredTracks = soa::Filtered; - Partition posTracks = o2::aod::track::signed1Pt > 0.f; - Partition negTracks = o2::aod::track::signed1Pt < 0.f; + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; std::map, float> mapProbEl; // map pair(collisionId, trackId) -> probaEl std::unordered_multimap multiMapTracksPerCollision; // collisionId -> trackIds + std::unordered_map mapCollisionTime; + std::unordered_map mapCollisionTimeError; + + std::map, float> mapTOFNsigmaReassociated; + std::map, float> mapTOFBetaReassociated; + // ---------- for data ---------- - void processRec_SA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + void processRec_SA(MyCollisions const& collisions, aod::BCsWithTimestamps const& bcs, MyFilteredTracks const& tracks) { stored_trackIds.reserve(tracks.size()); + mTOFResponse->processSetup(bcs.iteratorAt(0)); + + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, nullptr); + for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); @@ -652,13 +726,33 @@ struct skimmerPrimaryElectron { multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); + + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); } PROCESS_SWITCH(skimmerPrimaryElectron, processRec_SA, "process reconstructed info only", true); // standalone - void processRec_TTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + void processRec_TTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const& bcs, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) { stored_trackIds.reserve(tracks.size() * 2); + // for (const auto& collision : collisions) { + // auto bc = collision.template foundBC_as(); + // initCCDB(bc); + // } + mTOFResponse->processSetup(bcs.iteratorAt(0)); + + for (const auto& track : tracks) { + if (mapCollisionTime.find(track.collisionId()) == mapCollisionTime.end()) { + // LOGF(info, "track.collisionId() = %d, track.tofEvTime() = %f, track.tofEvTimeErr() = %f", track.collisionId(), track.tofEvTime(), track.tofEvTimeErr()); + mapCollisionTime[track.collisionId()] = track.tofEvTime(); + mapCollisionTimeError[track.collisionId()] = track.tofEvTimeErr(); + } + } + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); + for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); @@ -701,12 +795,18 @@ struct skimmerPrimaryElectron { multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); } PROCESS_SWITCH(skimmerPrimaryElectron, processRec_TTCA, "process reconstructed info only", false); // with TTCA - void processRec_SA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + void processRec_SA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const& bcs, MyFilteredTracks const& tracks) { stored_trackIds.reserve(tracks.size()); + mTOFResponse->processSetup(bcs.iteratorAt(0)); + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, nullptr); for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); @@ -753,12 +853,25 @@ struct skimmerPrimaryElectron { multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); } PROCESS_SWITCH(skimmerPrimaryElectron, processRec_SA_SWT, "process reconstructed info only", false); // standalone with swt - void processRec_TTCA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + void processRec_TTCA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const& bcs, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) { stored_trackIds.reserve(tracks.size() * 2); + mTOFResponse->processSetup(bcs.iteratorAt(0)); + for (const auto& track : tracks) { + if (mapCollisionTime.find(track.collisionId()) == mapCollisionTime.end()) { + // LOGF(info, "track.collisionId() = %d, track.tofEvTime() = %f, track.tofEvTimeErr() = %f", track.collisionId(), track.tofEvTime(), track.tofEvTimeErr()); + mapCollisionTime[track.collisionId()] = track.tofEvTime(); + mapCollisionTimeError[track.collisionId()] = track.tofEvTimeErr(); + } + } + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); @@ -805,17 +918,23 @@ struct skimmerPrimaryElectron { multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); } PROCESS_SWITCH(skimmerPrimaryElectron, processRec_TTCA_SWT, "process reconstructed info only", false); // with TTCA with swt // ---------- for MC ---------- using MyFilteredTracksMC = soa::Filtered; - Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; - Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; - void processMC_SA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const&) + Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; + Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; + void processMC_SA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const& bcs, MyFilteredTracksMC const& tracks, aod::McParticles const&) { stored_trackIds.reserve(tracks.size()); + mTOFResponse->processSetup(bcs.iteratorAt(0)); + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, nullptr); for (const auto& collision : collisions) { if (!collision.has_mcCollision()) { @@ -860,12 +979,25 @@ struct skimmerPrimaryElectron { multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); } PROCESS_SWITCH(skimmerPrimaryElectron, processMC_SA, "process reconstructed and MC info ", false); - void processMC_TTCA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyTracksMC const& tracks, aod::TrackAssoc const& trackIndices, aod::McParticles const&) + void processMC_TTCA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const& bcs, MyTracksMC const& tracks, aod::TrackAssoc const& trackIndices, aod::McParticles const&) { stored_trackIds.reserve(tracks.size() * 2); + mTOFResponse->processSetup(bcs.iteratorAt(0)); + for (const auto& track : tracks) { + if (mapCollisionTime.find(track.collisionId()) == mapCollisionTime.end()) { + // LOGF(info, "track.collisionId() = %d, track.tofEvTime() = %f, track.tofEvTimeErr() = %f", track.collisionId(), track.tofEvTime(), track.tofEvTimeErr()); + mapCollisionTime[track.collisionId()] = track.tofEvTime(); + mapCollisionTimeError[track.collisionId()] = track.tofEvTimeErr(); + } + } + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); for (const auto& collision : collisions) { if (!collision.has_mcCollision()) { @@ -912,6 +1044,10 @@ struct skimmerPrimaryElectron { multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); } PROCESS_SWITCH(skimmerPrimaryElectron, processMC_TTCA, "process reconstructed info only", false); // with TTCA }; @@ -951,7 +1087,6 @@ struct prefilterPrimaryElectron { Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.0, "max. TPC n sigma for electron inclusion"}; Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; Configurable intercept{"intercept", -0.0280, "intercept for m vs. phiv"}; - Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; @@ -1053,7 +1188,7 @@ struct prefilterPrimaryElectron { template bool checkTrack(TCollision const& collision, TTrack const& track) { - if (!track.hasITS()) { + if (!track.hasITS() || !track.hasTPC()) { return false; } if (track.itsChi2NCl() > maxchi2its) { @@ -1066,29 +1201,23 @@ struct prefilterPrimaryElectron { return false; } - if (!includeITSsa && (!track.hasITS() || !track.hasTPC())) { + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { return false; } - - if (track.hasTPC()) { - if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { - return false; - } - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { - return false; - } - if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { - return false; - } - if (track.tpcChi2NCl() > maxchi2tpc) { - return false; - } + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + if (track.tpcChi2NCl() > maxchi2tpc) { + return false; } o2::dataformats::DCA mDcaInfoCov; @@ -1177,7 +1306,7 @@ struct prefilterPrimaryElectron { Preslice trackIndicesPerCollision = aod::track_association::collisionId; - Filter trackFilter = o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true; + Filter trackFilter = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; using MyFilteredTracks = soa::Filtered; Partition posTracks = o2::aod::track::signed1Pt > 0.f; Partition negTracks = o2::aod::track::signed1Pt < 0.f; @@ -1624,6 +1753,7 @@ struct associateAmbiguousElectron { }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + o2::pid::tof::TOFResponseImpl::metadataInfo.initMetadata(cfgc); return WorkflowSpec{ adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-electron"}), adaptAnalysisTask(cfgc, TaskName{"prefilter-primary-electron"}), diff --git a/PWGEM/Dilepton/Utils/MlResponseO2Track.h b/PWGEM/Dilepton/Utils/MlResponseO2Track.h index d898d9da5f6..df5b59bd007 100644 --- a/PWGEM/Dilepton/Utils/MlResponseO2Track.h +++ b/PWGEM/Dilepton/Utils/MlResponseO2Track.h @@ -11,8 +11,7 @@ /// \file MlResponseO2Track.h /// \brief Class to compute the ML response for dielectron analyses at the single track level -/// \author Daniel Samitz , SMI Vienna -/// Elisa Meninno, , SMI Vienna +/// \author Daiki Sekihata #ifndef PWGEM_DILEPTON_UTILS_MLRESPONSEO2TRACK_H_ #define PWGEM_DILEPTON_UTILS_MLRESPONSEO2TRACK_H_ @@ -26,10 +25,9 @@ // Fill the map of available input features // the key is the feature's name (std::string) // the value is the corresponding value in EnumInputFeatures -#define FILL_MAP_O2_TRACK(FEATURE) \ - { \ - #FEATURE, static_cast(InputFeaturesO2Track::FEATURE) \ - } +#define FILL_MAP_O2_TRACK(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesO2Track::FEATURE)} // Check if the index of mCachedIndices (index associated to a FEATURE) // matches the entry in EnumInputFeatures associated to this FEATURE @@ -192,7 +190,7 @@ class MlResponseO2Track : public MlResponse virtual ~MlResponseO2Track() = default; template - float return_feature(uint8_t idx, T const& track, U const& trackParCov, V const& collision) + float return_feature(uint8_t idx, T const& track, U const& trackParCov, V const& collision, const float beta, const float tofNSigmaEl) { float inputFeature = 0.; switch (idx) { @@ -237,6 +235,14 @@ class MlResponseO2Track : public MlResponse CHECK_AND_FILL_DIELECTRON_COLLISION(trackOccupancyInTimeRange); CHECK_AND_FILL_DIELECTRON_COLLISION(ft0cOccupancyInTimeRange); } + + if (mUseReassociatedTOF) { // vector of map may be better. + if (idx == static_cast(InputFeaturesO2Track::tofNSigmaEl)) { + inputFeature = tofNSigmaEl; + } else if (idx == static_cast(InputFeaturesO2Track::beta)) { + inputFeature = beta; + } + } return inputFeature; } @@ -244,11 +250,11 @@ class MlResponseO2Track : public MlResponse /// \param track is the single track, \param collision is the collision /// \return inputFeatures vector template - std::vector getInputFeatures(T const& track, U const& trackParCov, V const& collision) + std::vector getInputFeatures(T const& track, U const& trackParCov, V const& collision, const float beta = -1.f, const float tofNSigmaEl = -999.f) { std::vector inputFeatures; for (const auto& idx : MlResponse::mCachedIndices) { - float inputFeature = return_feature(idx, track, trackParCov, collision); + float inputFeature = return_feature(idx, track, trackParCov, collision, beta, tofNSigmaEl); inputFeatures.emplace_back(inputFeature); } return inputFeatures; @@ -258,9 +264,9 @@ class MlResponseO2Track : public MlResponse /// \param track is the single track, \param collision is the collision /// \return binning variable template - float getBinningFeature(T const& track, U const& trackParCov, V const& collision) + float getBinningFeature(T const& track, U const& trackParCov, V const& collision, const float beta = -1.f, const float tofNSigmaEl = -999.f) { - return return_feature(mCachedIndexBinning, track, trackParCov, collision); + return return_feature(mCachedIndexBinning, track, trackParCov, collision, beta, tofNSigmaEl); } void cacheBinningIndex(std::string const& cfgBinningFeature) @@ -273,6 +279,8 @@ class MlResponseO2Track : public MlResponse } } + void useReassociatedTOF(const bool flag) { mUseReassociatedTOF = flag; } + protected: /// Method to fill the map of available input features void setAvailableInputFeatures() @@ -321,6 +329,7 @@ class MlResponseO2Track : public MlResponse } uint8_t mCachedIndexBinning; // index correspondance between configurable and available input features + bool mUseReassociatedTOF{false}; }; } // namespace o2::analysis From bae7d74c004d5588e9aef233e9d366bb064640dc Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Fri, 13 Feb 2026 18:08:51 +0000 Subject: [PATCH 2/2] Please consider the following formatting changes --- PWGEM/Dilepton/Utils/MlResponseO2Track.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/PWGEM/Dilepton/Utils/MlResponseO2Track.h b/PWGEM/Dilepton/Utils/MlResponseO2Track.h index df5b59bd007..e526eb9a3db 100644 --- a/PWGEM/Dilepton/Utils/MlResponseO2Track.h +++ b/PWGEM/Dilepton/Utils/MlResponseO2Track.h @@ -25,9 +25,10 @@ // Fill the map of available input features // the key is the feature's name (std::string) // the value is the corresponding value in EnumInputFeatures -#define FILL_MAP_O2_TRACK(FEATURE) \ - { \ - #FEATURE, static_cast(InputFeaturesO2Track::FEATURE)} +#define FILL_MAP_O2_TRACK(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesO2Track::FEATURE) \ + } // Check if the index of mCachedIndices (index associated to a FEATURE) // matches the entry in EnumInputFeatures associated to this FEATURE