From f00ddc5b098f75b8a4dd497a8939e9e57495713a Mon Sep 17 00:00:00 2001 From: Daiki Sekihata Date: Tue, 20 Aug 2024 00:01:10 +0200 Subject: [PATCH] PWGEM/Dilepton: add a skimming task for EoI (#7360) --- PWGEM/Dilepton/DataModel/dileptonTables.h | 2 +- PWGEM/Dilepton/TableProducer/CMakeLists.txt | 5 + .../TableProducer/filterDielectronEvent.cxx | 1029 +++++++++++++++++ PWGEM/PhotonMeson/DataModel/gammaTables.h | 8 + .../TableProducer/photonconversionbuilder.cxx | 90 +- 5 files changed, 1116 insertions(+), 18 deletions(-) create mode 100644 PWGEM/Dilepton/TableProducer/filterDielectronEvent.cxx diff --git a/PWGEM/Dilepton/DataModel/dileptonTables.h b/PWGEM/Dilepton/DataModel/dileptonTables.h index f1622704452..71fe7dca2d6 100644 --- a/PWGEM/Dilepton/DataModel/dileptonTables.h +++ b/PWGEM/Dilepton/DataModel/dileptonTables.h @@ -186,7 +186,7 @@ DECLARE_SOA_TABLE(EMEventsProperty, "AOD", "EMEVENTPROP", //! joinable to EMEven emevent::SpherocityPtWeighted, emevent::SpherocityPtUnWeighted, emevent::NtrackSpherocity); using EMEventProperty = EMEventsProperty::iterator; -DECLARE_SOA_TABLE(EMEventsNee, "AOD", "EMEVENTNEE", emevent::NeeULS, emevent::NeeLSpp, emevent::NeeLSmm); // joinable to EMEvents +DECLARE_SOA_TABLE(EMEventsNee, "AOD", "EMEVENTNEE", emevent::NeeULS, emevent::NeeLSpp, emevent::NeeLSmm); // joinable to EMEvents or aod::Collisions using EMEventNee = EMEventsNee::iterator; namespace emmcevent diff --git a/PWGEM/Dilepton/TableProducer/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/CMakeLists.txt index 00189858282..d0daf2c914f 100644 --- a/PWGEM/Dilepton/TableProducer/CMakeLists.txt +++ b/PWGEM/Dilepton/TableProducer/CMakeLists.txt @@ -55,3 +55,8 @@ o2physics_add_dpl_workflow(associate-mc-info-dilepton PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(filter-dielectron-event + SOURCES filterDielectronEvent.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + diff --git a/PWGEM/Dilepton/TableProducer/filterDielectronEvent.cxx b/PWGEM/Dilepton/TableProducer/filterDielectronEvent.cxx new file mode 100644 index 00000000000..d9c3ea60477 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/filterDielectronEvent.cxx @@ -0,0 +1,1029 @@ +// 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 write relevant information about primary electrons. +/// \author daiki.sekihata@cern.ch + +#include +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/Core/TableHelper.h" +#include "EventFiltering/Zorro.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +using MyTracksMC = soa::Join; +using MyTrackMC = MyTracksMC::iterator; + +struct filterDielectronEvent { + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Produces emprimaryelectrons; + Produces emprimaryelectronscov; + Produces filter; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // for software triggers + Configurable enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; + Configurable cfg_swt_names{"cfg_swt_names", "", "comma-separated software trigger names"}; + Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; + + // Operation and minimisation criteria + Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable max_mean_its_cluster_size{"max_mean_its_cluster_size", 16.f, "max. x cos(lambda)"}; // this is to suppress random combination. default 4 + 1 for skimming. + Configurable minitsncls{"minitsncls", 4, "min. number of ITS clusters"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.15, "min pt for track"}; + Configurable maxeta{"maxeta", 0.8, "eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 1.0f, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 1.0f, "max DCAz in cm"}; + Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 1e+10, "max DCA 3D in sigma"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.5, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.5, "max. TPC n sigma for electron inclusion"}; + Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", 3.5, "max. TOF n sigma for electron inclusion"}; + Configurable maxMee{"maxMee", 0.04, "max mee for virtual photon selection"}; + Configurable slope{"slope", 0.0181, "slope for mee vs. phiv"}; + Configurable intercept{"intercept", -0.0370, "intercept for mee vs. phiv"}; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. + + Zorro zorro; + int mRunNumber; + float d_bz; + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + 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, {{400, -20, 20}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {20, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + 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/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); + fRegistry.add("Track/hMeanClusterSizeITS_TPCNsigmaEl", "mean cluster size ITS vs. n #sigma_{e}^{TPC} in p_{pv} < 0.2 GeV/c;n #sigma_{e}^{TPC}; on ITS #times cos(#lambda)", kTH2F, {{100, -5, 5}, {160, 0, 16}}, false); + fRegistry.add("Pair/before/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {100, 0, 1}}, false); + fRegistry.add("Pair/before/hMvsPhiV", "mee vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/after/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {100, 0, 1}}, false); + fRegistry.add("Pair/after/hMvsPhiV", "m_{ee} vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0, 0.1}}, false); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + if (enable_swt) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + template + bool checkTrack(TCollision const& collision, TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (track.tpcChi2NCl() > maxchi2tpc) { + return false; + } + + if (track.itsChi2NCl() > maxchi2its) { + return false; + } + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + if (track.itsNCls() < minitsncls) { + return false; + } + + auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hits < itsRequirement.first) { + return false; + } + + uint32_t itsClusterSizes = track.itsClusterSizes(); + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + if (static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl())) > max_mean_its_cluster_size) { + 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; + } + + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + // std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + // getPxPyPz(track_par_cov_recalc, pVec_recalc); + float dcaXY = dcaInfo[0]; + float dcaZ = dcaInfo[1]; + + if (abs(dcaXY) > dca_xy_max || abs(dcaZ) > dca_z_max) { + return false; + } + + if (track_par_cov_recalc.getPt() < minpt || abs(track_par_cov_recalc.getEta()) > maxeta) { + return false; + } + + float dca_3d = 999.f; + float det = track_par_cov_recalc.getSigmaY2() * track_par_cov_recalc.getSigmaZ2() - track_par_cov_recalc.getSigmaZY() * track_par_cov_recalc.getSigmaZY(); + if (det < 0) { + dca_3d = 999.f; + } else { + float chi2 = (dcaXY * dcaXY * track_par_cov_recalc.getSigmaZ2() + dcaZ * dcaZ * track_par_cov_recalc.getSigmaY2() - 2. * dcaXY * dcaZ * track_par_cov_recalc.getSigmaZY()) / det; + dca_3d = std::sqrt(std::abs(chi2) / 2.); + } + if (dca_3d > dca_3d_sigma_max) { + return false; + } + + return true; + } + + template + bool isElectron(TTrack const& track) + { + if (track.hasTOF()) { + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && abs(track.tofNSigmaEl()) < maxTOFNsigmaEl; + } else { + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl; + } + } + + template + void fillTrackTable(TCollision const& collision, TTrack const& track) + { + if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::pair{collision.globalIndex(), track.globalIndex()}) == stored_trackIds.end()) { + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + // std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + // getPxPyPz(track_par_cov_recalc, pVec_recalc); + float dcaXY = dcaInfo[0]; + float dcaZ = dcaInfo[1]; + + float pt_recalc = track_par_cov_recalc.getPt(); + float eta_recalc = track_par_cov_recalc.getEta(); + float phi_recalc = track_par_cov_recalc.getPhi(); + + bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); + + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + pt_recalc, eta_recalc, phi_recalc, dcaXY, dcaZ, + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap(), + track_par_cov_recalc.getX(), track_par_cov_recalc.getAlpha(), track_par_cov_recalc.getY(), track_par_cov_recalc.getZ(), track_par_cov_recalc.getSnp(), track_par_cov_recalc.getTgl(), isAssociatedToMPC); + + emprimaryelectronscov( + track_par_cov_recalc.getSigmaY2(), + track_par_cov_recalc.getSigmaZY(), + track_par_cov_recalc.getSigmaZ2(), + track_par_cov_recalc.getSigmaSnpY(), + track_par_cov_recalc.getSigmaSnpZ(), + track_par_cov_recalc.getSigmaSnp2(), + track_par_cov_recalc.getSigmaTglY(), + track_par_cov_recalc.getSigmaTglZ(), + track_par_cov_recalc.getSigmaTglSnp(), + track_par_cov_recalc.getSigmaTgl2(), + track_par_cov_recalc.getSigma1PtY(), + track_par_cov_recalc.getSigma1PtZ(), + track_par_cov_recalc.getSigma1PtSnp(), + track_par_cov_recalc.getSigma1PtTgl(), + track_par_cov_recalc.getSigma1Pt2()); + + stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); + + if (fillQAHistogram) { + uint32_t itsClusterSizes = track.itsClusterSizes(); + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + fRegistry.fill(HIST("Track/hPt"), pt_recalc); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / pt_recalc); + fRegistry.fill(HIST("Track/hEtaPhi"), phi_recalc, eta_recalc); + fRegistry.fill(HIST("Track/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), dcaXY / sqrt(track_par_cov_recalc.getSigmaY2()), dcaZ / sqrt(track_par_cov_recalc.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt_recalc, sqrt(track_par_cov_recalc.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt_recalc, sqrt(track_par_cov_recalc.getSigmaZ2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + 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"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), track.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()); + + if (track.p() < 0.2) { + fRegistry.fill(HIST("Track/hMeanClusterSizeITS_TPCNsigmaEl"), track.tpcNSigmaEl(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + } + } + } + } + + template + o2::track::TrackParCov propagateTrack(TCollision const& collision, TTrack const& track) + { + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + // std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + // getPxPyPz(track_par_cov_recalc, pVec_recalc); + return track_par_cov_recalc; + } + + std::vector> stored_trackIds; + std::vector> stored_pairIds; + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; + Filter pidFilter = minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + using MyFilteredTracks = soa::Filtered; + + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + // ---------- for data ---------- + + void processRec_SA(Join const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&) + { + stored_trackIds.reserve(posTracks.size() + negTracks.size()); + + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + filter(0, 0, 0); + continue; + } + if (enable_swt && !zorro.isSelected(bc.globalBC())) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, pos) || !checkTrack(collision, ele)) { + continue; + } + if (!isElectron(pos) || !isElectron(ele)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (v12.M() < maxMee && slope * phiv + intercept < v12.M()) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of pairing loop + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + filter(nee_uls, 0, 0); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + stored_pairIds.clear(); + stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processRec_SA, "process reconstructed info only", true); // standalone + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + void processRec_TTCA(Join const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + { + stored_trackIds.reserve(tracks.size() * 2); + + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + filter(0, 0, 0); + continue; + } + if (enable_swt && !zorro.isSelected(bc.globalBC())) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + std::vector posTracks_per_coll; + std::vector negTracks_per_coll; + posTracks_per_coll.reserve(trackIdsThisCollision.size()); + negTracks_per_coll.reserve(trackIdsThisCollision.size()); + + for (auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + + if (track.sign() > 0) { + posTracks_per_coll.emplace_back(track); + } else { + negTracks_per_coll.emplace_back(track); + } + } // end of track loop + + for (auto& pos : posTracks_per_coll) { + for (auto& ele : negTracks_per_coll) { + + auto pos_prop = propagateTrack(collision, pos); + auto ele_prop = propagateTrack(collision, ele); + + std::array pVec_pos = {0, 0, 0}; // px, py, pz + getPxPyPz(pos_prop, pVec_pos); + std::array pVec_ele = {0, 0, 0}; // px, py, pz + getPxPyPz(ele_prop, pVec_ele); + + ROOT::Math::PtEtaPhiMVector v1(pos_prop.getPt(), pos_prop.getEta(), pos_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele_prop.getPt(), ele_prop.getEta(), ele_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_pos[0], pVec_pos[1], pVec_pos[2], pVec_ele[0], pVec_ele[1], pVec_ele[2], pos.sign(), ele.sign(), d_bz); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (v12.M() < maxMee && slope * phiv + intercept < v12.M()) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of negative track loop + } // end of postive track loop + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + + filter(nee_uls, 0, 0); + + posTracks_per_coll.clear(); + negTracks_per_coll.clear(); + posTracks_per_coll.shrink_to_fit(); + negTracks_per_coll.shrink_to_fit(); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + stored_pairIds.clear(); + stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processRec_TTCA, "process reconstructed info only", false); // with TTCA + + // ---------- 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) + { + stored_trackIds.reserve(tracks.size()); + + for (auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + filter(0, 0, 0); + continue; + } + if (enable_swt && !zorro.isSelected(bc.globalBC())) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, pos) || !checkTrack(collision, ele)) { + continue; + } + if (!isElectron(pos) || !isElectron(ele)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (v12.M() < maxMee && slope * phiv + intercept < v12.M()) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of pairing loop + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + filter(nee_uls, 0, 0); + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + stored_pairIds.clear(); + stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, 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) + { + stored_trackIds.reserve(tracks.size() * 2); + + for (auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + filter(0, 0, 0); + continue; + } + if (enable_swt && !zorro.isSelected(bc.globalBC())) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + std::vector posTracks_per_coll; + std::vector negTracks_per_coll; + posTracks_per_coll.reserve(trackIdsThisCollision.size()); + negTracks_per_coll.reserve(trackIdsThisCollision.size()); + + for (auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + + if (track.sign() > 0) { + posTracks_per_coll.emplace_back(track); + } else { + negTracks_per_coll.emplace_back(track); + } + } // end of track loop + + for (auto& pos : posTracks_per_coll) { + for (auto& ele : negTracks_per_coll) { + auto pos_prop = propagateTrack(collision, pos); + auto ele_prop = propagateTrack(collision, ele); + std::array pVec_pos = {0, 0, 0}; // px, py, pz + getPxPyPz(pos_prop, pVec_pos); + std::array pVec_ele = {0, 0, 0}; // px, py, pz + getPxPyPz(ele_prop, pVec_ele); + + ROOT::Math::PtEtaPhiMVector v1(pos_prop.getPt(), pos_prop.getEta(), pos_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele_prop.getPt(), ele_prop.getEta(), ele_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_pos[0], pVec_pos[1], pVec_pos[2], pVec_ele[0], pVec_ele[1], pVec_ele[2], pos.sign(), ele.sign(), d_bz); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (v12.M() < maxMee && slope * phiv + intercept < v12.M()) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of negative track loop + } // end of postive track loop + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + filter(nee_uls, 0, 0); + + posTracks_per_coll.clear(); + negTracks_per_coll.clear(); + posTracks_per_coll.shrink_to_fit(); + negTracks_per_coll.shrink_to_fit(); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + stored_pairIds.clear(); + stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processMC_TTCA, "process reconstructed info only", false); // with TTCA +}; +struct prefilterPrimaryElectron { + Produces ele_pfb; + void process(aod::EMPrimaryElectrons const& primaryelectrons) + { + for (int i = 0; i < primaryelectrons.size(); i++) { + ele_pfb(0); + } + } +}; +struct associateAmbiguousElectron { + Produces em_amb_ele_ids; + + SliceCache cache; + PresliceUnsorted perTrack = o2::aod::emprimaryelectron::trackId; + std::vector ambele_self_Ids; + + void process(aod::EMPrimaryElectrons const& electrons) + { + for (auto& electron : electrons) { + auto electrons_with_same_trackId = electrons.sliceBy(perTrack, electron.trackId()); + ambele_self_Ids.reserve(electrons_with_same_trackId.size()); + for (auto& amb_ele : electrons_with_same_trackId) { + if (amb_ele.globalIndex() == electron.globalIndex()) { // don't store myself. + continue; + } + ambele_self_Ids.emplace_back(amb_ele.globalIndex()); + } + em_amb_ele_ids(ambele_self_Ids); + ambele_self_Ids.clear(); + ambele_self_Ids.shrink_to_fit(); + } + } +}; +struct createEMEvent2VP { + using MyBCs = soa::Join; + using MyQvectors = soa::Join; + + using MyCollisions = soa::Join; + using MyCollisions_Cent = soa::Join; // centrality table has dependency on multiplicity table. + using MyCollisions_Cent_Qvec = soa::Join; + + using MyCollisionsMC = soa::Join; + using MyCollisionsMC_Cent = soa::Join; // centrality table has dependency on multiplicity table. + using MyCollisionsMC_Cent_Qvec = soa::Join; + + Produces event; + // Produces eventcov; + Produces event_mult; + Produces event_cent; + Produces event_qvec; + Produces emswtbit; + + enum class EMEventType : int { + kEvent = 0, + kEvent_Cent = 1, + kEvent_Cent_Qvec = 2, + }; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable inherit_from_filter_dielectron_event{"inherit_from_filter_dielectron_event", true, "flag to inherit task options from filter-dielectron-event"}; + Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; + Configurable enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; + Configurable cfg_swt_names{"cfg_swt_names", "fHighTrackMult,fHighFt0Mult", "comma-separated software trigger names"}; // !trigger names have to be pre-registered in dileptonTable.h for bit operation! + + HistogramRegistry registry{"registry"}; + void init(o2::framework::InitContext& initContext) + { + if (inherit_from_filter_dielectron_event) { + getTaskOptionValue(initContext, "filter-dielectron-event", "applyEveSel_at_skimming", applyEveSel_at_skimming.value, true); // for EM users. + getTaskOptionValue(initContext, "filter-dielectron-event", "enable_swt", enable_swt.value, true); // for EM users. + getTaskOptionValue(initContext, "filter-dielectron-event", "cfg_swt_names", cfg_swt_names.value, true); // for EM users. + } + + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{7, 0.5f, 7.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "sel8"); + + registry.add("hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + } + + ~createEMEvent2VP() + { + swt_names.clear(); + swt_names.shrink_to_fit(); + } + + Zorro zorro; + std::vector mTOIidx; + std::vector swt_names; + uint64_t mNinspectedTVX{0}; + + int mRunNumber; + Service ccdb; + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + if (enable_swt) { + LOGF(info, "enable software triggers : %s", cfg_swt_names.value.data()); + mTOIidx = zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); + std::stringstream tokenizer(cfg_swt_names.value); + std::string token; + while (std::getline(tokenizer, token, ',')) { + swt_names.emplace_back(token); + } + for (auto& idx : mTOIidx) { + LOGF(info, "Trigger of Interest : index = %d", idx); + } + mNinspectedTVX = zorro.getInspectedTVX()->GetBinContent(1); + LOGF(info, "total inspected TVX events = %d in run number %d", mNinspectedTVX, bc.runNumber()); + registry.fill(HIST("hNInspectedTVX"), bc.runNumber(), mNinspectedTVX); + } + mRunNumber = bc.runNumber(); + } + + template + void skimEvent(TCollisions const& collisions, TBCs const&) + { + for (auto& collision : collisions) { + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + continue; + } + + if (enable_swt) { + if (zorro.isSelected(bc.globalBC())) { // triggered event + auto swt_bitset = zorro.getLastResult(); // this has to be called after zorro::isSelected, or simply call zorro.fetch + // LOGF(info, "swt_bitset.to_string().c_str() = %s", swt_bitset.to_string().c_str()); + uint16_t trigger_bitmap = 0; + for (size_t idx = 0; idx < mTOIidx.size(); idx++) { + if (swt_bitset.test(mTOIidx[idx])) { + auto swtname = swt_names[idx]; + trigger_bitmap |= BIT(o2::aod::pwgem::dilepton::swt::aliasLabels.at(swtname)); + // LOGF(info, "swtname = %s is fired. swt index in original swt table = %d, swt index for EM table = %d", swtname.data(), mTOIidx[idx], o2::aod::pwgem::dilepton::swt::aliasLabels.at(swtname)); + } + } + emswtbit(trigger_bitmap, mNinspectedTVX); + } else { // rejected + continue; + } + } + + if (!(collision.neeuls() >= 1 || collision.neeuls() + collision.ngpcm() >= 2)) { + continue; + } + + // LOGF(info, "collision.neeuls() = %d, collision.ngpcm() = %d", collision.neeuls(), collision.ngpcm()); + + // LOGF(info, "collision.multNTracksPV() = %d, collision.multFT0A() = %f, collision.multFT0C() = %f", collision.multNTracksPV(), collision.multFT0A(), collision.multFT0C()); + + registry.fill(HIST("hEventCounter"), 1); + + event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), + collision.posX(), collision.posY(), collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange()); + + // eventcov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + + event_mult(collision.multFT0A(), collision.multFT0C(), collision.multTPC(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); + + if constexpr (eventype == EMEventType::kEvent) { + event_cent(105.f, 105.f, 105.f, 105.f); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } else if constexpr (eventype == EMEventType::kEvent_Cent) { + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } else if constexpr (eventype == EMEventType::kEvent_Cent_Qvec) { + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); + float q2xft0m = 999.f, q2yft0m = 999.f, q2xft0a = 999.f, q2yft0a = 999.f, q2xft0c = 999.f, q2yft0c = 999.f, q2xbpos = 999.f, q2ybpos = 999.f, q2xbneg = 999.f, q2ybneg = 999.f, q2xbtot = 999.f, q2ybtot = 999.f; + float q3xft0m = 999.f, q3yft0m = 999.f, q3xft0a = 999.f, q3yft0a = 999.f, q3xft0c = 999.f, q3yft0c = 999.f, q3xbpos = 999.f, q3ybpos = 999.f, q3xbneg = 999.f, q3ybneg = 999.f, q3xbtot = 999.f, q3ybtot = 999.f; + float q4xft0m = 999.f, q4yft0m = 999.f, q4xft0a = 999.f, q4yft0a = 999.f, q4xft0c = 999.f, q4yft0c = 999.f, q4xbpos = 999.f, q4ybpos = 999.f, q4xbneg = 999.f, q4ybneg = 999.f, q4xbtot = 999.f, q4ybtot = 999.f; + + if (collision.qvecFT0CReVec().size() >= 3) { // harmonics 2,3,4 + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xbpos = collision.qvecBPosReVec()[0], q2xbneg = collision.qvecBNegReVec()[0], q2xbtot = collision.qvecBTotReVec()[0]; + q2yft0m = collision.qvecFT0MImVec()[0], q2yft0a = collision.qvecFT0AImVec()[0], q2yft0c = collision.qvecFT0CImVec()[0], q2ybpos = collision.qvecBPosImVec()[0], q2ybneg = collision.qvecBNegImVec()[0], q2ybtot = collision.qvecBTotImVec()[0]; + q3xft0m = collision.qvecFT0MReVec()[1], q3xft0a = collision.qvecFT0AReVec()[1], q3xft0c = collision.qvecFT0CReVec()[1], q3xbpos = collision.qvecBPosReVec()[1], q3xbneg = collision.qvecBNegReVec()[1], q3xbtot = collision.qvecBTotReVec()[1]; + q3yft0m = collision.qvecFT0MImVec()[1], q3yft0a = collision.qvecFT0AImVec()[1], q3yft0c = collision.qvecFT0CImVec()[1], q3ybpos = collision.qvecBPosImVec()[1], q3ybneg = collision.qvecBNegImVec()[1], q3ybtot = collision.qvecBTotImVec()[1]; + q4xft0m = collision.qvecFT0MReVec()[2], q4xft0a = collision.qvecFT0AReVec()[2], q4xft0c = collision.qvecFT0CReVec()[2], q4xbpos = collision.qvecBPosReVec()[2], q4xbneg = collision.qvecBNegReVec()[2], q4xbtot = collision.qvecBTotReVec()[2]; + q4yft0m = collision.qvecFT0MImVec()[2], q4yft0a = collision.qvecFT0AImVec()[2], q4yft0c = collision.qvecFT0CImVec()[2], q4ybpos = collision.qvecBPosImVec()[2], q4ybneg = collision.qvecBNegImVec()[2], q4ybtot = collision.qvecBTotImVec()[2]; + } else if (collision.qvecFT0CReVec().size() >= 2) { // harmonics 2,3 + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xbpos = collision.qvecBPosReVec()[0], q2xbneg = collision.qvecBNegReVec()[0], q2xbtot = collision.qvecBTotReVec()[0]; + q2yft0m = collision.qvecFT0MImVec()[0], q2yft0a = collision.qvecFT0AImVec()[0], q2yft0c = collision.qvecFT0CImVec()[0], q2ybpos = collision.qvecBPosImVec()[0], q2ybneg = collision.qvecBNegImVec()[0], q2ybtot = collision.qvecBTotImVec()[0]; + q3xft0m = collision.qvecFT0MReVec()[1], q3xft0a = collision.qvecFT0AReVec()[1], q3xft0c = collision.qvecFT0CReVec()[1], q3xbpos = collision.qvecBPosReVec()[1], q3xbneg = collision.qvecBNegReVec()[1], q3xbtot = collision.qvecBTotReVec()[1]; + q3yft0m = collision.qvecFT0MImVec()[1], q3yft0a = collision.qvecFT0AImVec()[1], q3yft0c = collision.qvecFT0CImVec()[1], q3ybpos = collision.qvecBPosImVec()[1], q3ybneg = collision.qvecBNegImVec()[1], q3ybtot = collision.qvecBTotImVec()[1]; + } else if (collision.qvecFT0CReVec().size() >= 1) { // harmonics 2 + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xbpos = collision.qvecBPosReVec()[0], q2xbneg = collision.qvecBNegReVec()[0], q2xbtot = collision.qvecBTotReVec()[0]; + q2yft0m = collision.qvecFT0MImVec()[0], q2yft0a = collision.qvecFT0AImVec()[0], q2yft0c = collision.qvecFT0CImVec()[0], q2ybpos = collision.qvecBPosImVec()[0], q2ybneg = collision.qvecBNegImVec()[0], q2ybtot = collision.qvecBTotImVec()[0]; + } + event_qvec( + q2xft0m, q2yft0m, q2xft0a, q2yft0a, q2xft0c, q2yft0c, q2xbpos, q2ybpos, q2xbneg, q2ybneg, q2xbtot, q2ybtot, + q3xft0m, q3yft0m, q3xft0a, q3yft0a, q3xft0c, q3yft0c, q3xbpos, q3ybpos, q3xbneg, q3ybneg, q3xbtot, q3ybtot, + q4xft0m, q4yft0m, q4xft0a, q4yft0a, q4xft0c, q4yft0c, q4xbpos, q4ybpos, q4xbneg, q4ybneg, q4xbtot, q4ybtot); + } else { + event_cent(105.f, 105.f, 105.f, 105.f); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } + } // end of collision loop + } // end of skimEvent + + void processEvent(MyCollisions const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent, "process event info", false); + + void processEvent_Cent(MyCollisions_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent_Cent, "process event info", false); + + void processEvent_Cent_Qvec(MyCollisions_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent_Cent_Qvec, "process event info", false); + + void processEventMC(MyCollisionsMC const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEventMC, "process event info", false); + + void processEventMC_Cent(MyCollisionsMC_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEventMC_Cent, "process event info", false); + + void processEventMC_Cent_Qvec(MyCollisionsMC_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEventMC_Cent_Qvec, "process event info", false); + + void processDummy(aod::Collisions const&) {} + PROCESS_SWITCH(createEMEvent2VP, processDummy, "processDummy", true); +}; +struct AssociateDileptonToEMEvent2VP { + Produces v0kfeventid; + Produces prmeleventid; + + Preslice perCollision_pcm = aod::v0photonkf::collisionId; + PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; + + void init(o2::framework::InitContext&) {} + + template + void fillEventId(TCollisions const& collisions, TLeptons const& leptons, TEventIds& eventIds, TPreslice const& perCollision) + { + for (auto& collision : collisions) { + auto leptons_coll = leptons.sliceBy(perCollision, collision.collisionId()); + int nl = leptons_coll.size(); + // LOGF(info, "collision.collisionId() = %d , nl = %d", collision.collisionId(), nl); + for (int il = 0; il < nl; il++) { + eventIds(collision.globalIndex()); + } // end of photon loop + } // end of collision loop + } + + // This struct is for both data and MC. + // Note that reconstructed collisions without mc collisions are already rejected in CreateEMEventDilepton in MC. + + void processPCM(aod::EMEvents const& collisions, aod::V0PhotonsKF const& photons) + { + fillEventId(collisions, photons, v0kfeventid, perCollision_pcm); + } + + void processElectron(aod::EMEvents const& collisions, aod::EMPrimaryElectrons const& tracks) + { + fillEventId(collisions, tracks, prmeleventid, perCollision_el); + } + + void processDummy(aod::EMEvents const&) {} + + PROCESS_SWITCH(AssociateDileptonToEMEvent2VP, processPCM, "process pcm-event indexing", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent2VP, processElectron, "process dalitzee-event indexing", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent2VP, processDummy, "process dummy", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"filter-dielectron-event"}), + adaptAnalysisTask(cfgc, TaskName{"prefilter-primary-electron"}), + adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-electron"}), + adaptAnalysisTask(cfgc, TaskName{"create-emevent-2vp"}), + adaptAnalysisTask(cfgc, TaskName{"associate-dilepton-to-emevent2VP"}), + }; +} diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index d4f638ed28a..830645f2865 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -202,6 +202,14 @@ DECLARE_SOA_TABLE(V0Legs, "AOD", "V0LEG", //! // iterators using V0Leg = V0Legs::iterator; +namespace emevent +{ +DECLARE_SOA_COLUMN(NgPCM, ngpcm, int); +} // namespace emevent + +DECLARE_SOA_TABLE(EMEventsNgPCM, "AOD", "EMEVENTNGPCM", emevent::NgPCM); // joinable to EMEvents or aod::Collisions +using EMEventNgPCM = EMEventsNgPCM::iterator; + namespace v0photonkf { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index 6684618483a..1b877526828 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -65,6 +65,7 @@ using MyTracksIUMC = soa::Join; struct PhotonConversionBuilder { Produces v0photonskf; Produces v0legs; + Produces events_ngpcm; // CCDB options Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -73,6 +74,7 @@ struct PhotonConversionBuilder { Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable inherit_from_filter_dielectron_event{"inherit_from_filter_dielectron_event", false, "flag to inherit task options from filter-dielectron-event"}; Configurable inherit_from_emevent_dilepton{"inherit_from_emevent_dilepton", false, "flag to inherit task options from emevent-dilepton"}; Configurable inherit_from_emevent_photon{"inherit_from_emevent_photon", false, "flag to inherit task options from emevent-photon"}; Configurable enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; @@ -84,8 +86,8 @@ struct PhotonConversionBuilder { Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; // single track cuts - Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 10, "min crossed rows"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 40, "min crossed rows"}; Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; // default 4.0 + 1.0 Configurable maxchi2its{"maxchi2its", 6.0, "max chi2/NclsITS"}; // default 5.0 + 1.0 Configurable maxpt_itsonly{"maxpt_itsonly", 0.15, "max pT for ITSonly tracks at SV"}; @@ -176,10 +178,18 @@ struct PhotonConversionBuilder { ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + if (inherit_from_emevent_dilepton && inherit_from_filter_dielectron_event) { + LOGF(fatal, "Cannot enable inherit_from_emevent_dilepton and inherit_from_filter_dielectron_event at the same time. Please choose one."); + } + if (inherit_from_emevent_dilepton) { getTaskOptionValue(initContext, "create-emevent-dilepton", "applyEveSel_at_skimming", applyEveSel_at_skimming.value, true); // for EM users. getTaskOptionValue(initContext, "create-emevent-dilepton", "enable_swt", enable_swt.value, true); // for EM users. getTaskOptionValue(initContext, "create-emevent-dilepton", "cfg_swt_names", cfg_swt_names.value, true); // for EM users. + } else if (inherit_from_filter_dielectron_event) { + getTaskOptionValue(initContext, "filter-dielectron-event", "applyEveSel_at_skimming", applyEveSel_at_skimming.value, true); // for EM users. + getTaskOptionValue(initContext, "filter-dielectron-event", "enable_swt", enable_swt.value, true); // for EM users. + getTaskOptionValue(initContext, "filter-dielectron-event", "cfg_swt_names", cfg_swt_names.value, true); // for EM users. } if (useMatCorrType == 1) { @@ -365,13 +375,13 @@ struct PhotonConversionBuilder { track.x(), track.y(), track.z(), track.tgl()); } - template + template void fillV0Table(TV0 const& v0, const bool filltable) { // Get tracks - auto pos = v0.template posTrack_as(); - auto ele = v0.template negTrack_as(); - auto collision = v0.template collision_as(); // collision where this v0 belongs to. + auto pos = v0.template posTrack_as(); + auto ele = v0.template negTrack_as(); + auto collision = v0.template collision_as(); // collision where this v0 belongs. if (pos.sign() * ele.sign() > 0) { // reject same sign pair return; @@ -647,12 +657,14 @@ struct PhotonConversionBuilder { } Preslice perCollision = o2::aod::v0::collisionId; - std::map, float> pca_map; //(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> pca - std::map, float> cospa_map; //(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> cospa - std::vector> stored_v0Ids; //(pos.globalIndex(), ele.globalIndex()) - - template - void build(TCollisions const& collisions, TV0s const& v0s, TTracks const& /*tracks*/, TBCs const&) + std::map, float> pca_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> pca + std::map, float> cospa_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> cospa + std::vector> stored_v0Ids; // (pos.globalIndex(), ele.globalIndex()) + std::vector> stored_fullv0Ids; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) + std::unordered_map nv0_map; // map collisionId -> nv0 + + template + void build(TCollisions const& collisions, TV0s const& v0s, TTracks const&, TBCs const&) { for (auto& collision : collisions) { if constexpr (isMC) { @@ -661,6 +673,8 @@ struct PhotonConversionBuilder { } } + nv0_map[collision.globalIndex()] = 0; + auto bc = collision.template foundBC_as(); initCCDB(bc); registry.fill(HIST("hCollisionCounter"), 1); @@ -680,7 +694,8 @@ struct PhotonConversionBuilder { } // end of v0 loop } // end of collision loop - stored_v0Ids.reserve(pca_map.size()); // number of photon candidates per DF + stored_v0Ids.reserve(pca_map.size()); // number of photon candidates per DF + stored_fullv0Ids.reserve(pca_map.size()); // number of photon candidates per DF // find minimal pca for (const auto& [key, value] : pca_map) { @@ -720,20 +735,55 @@ struct PhotonConversionBuilder { bool is_stored = std::find(stored_v0Ids.begin(), stored_v0Ids.end(), std::make_pair(posId, eleId)) != stored_v0Ids.end(); if (is_closest_v0 && is_most_aligned_v0 && !is_stored) { - auto v0 = v0s.rawIteratorAt(v0Id); + // auto v0 = v0s.rawIteratorAt(v0Id); // auto collision = collisions.rawIteratorAt(collisionId); // auto pos = tracks.rawIteratorAt(posId); // auto ele = tracks.rawIteratorAt(eleId); // LOGF(info, "!accept! | collision id = %d | v0id1 = %d , posid1 = %d , eleid1 = %d , pca1 = %f , cospa = %f", collisionId, v0Id, posId, eleId, v0pca, cospa); - fillV0Table(v0, true); + + // fillV0Table(v0, true); stored_v0Ids.emplace_back(std::make_pair(posId, eleId)); + stored_fullv0Ids.emplace_back(std::make_tuple(v0Id, collisionId, posId, eleId)); + nv0_map[collisionId]++; } } // end of pca_map loop // LOGF(info, "pca_map.size() = %d", pca_map.size()); + + for (auto& fullv0Id : stored_fullv0Ids) { + auto v0Id = std::get<0>(fullv0Id); + // auto collisionId = std::get<1>(fullv0Id); + // auto posId = std::get<2>(fullv0Id); + // auto eleId = std::get<3>(fullv0Id); + // LOGF(info, "!accept! | collision id = %d | v0id = %d , posid = %d , eleid = %d", collisionId, v0Id, posId, eleId); + + auto v0 = v0s.rawIteratorAt(v0Id); + if constexpr (enableFilter) { + auto collision_tmp = v0.template collision_as(); // collision where this v0 belongs. + if (!(collision_tmp.neeuls() >= 1 || collision_tmp.neeuls() + nv0_map[collision_tmp.globalIndex()] >= 2)) { + continue; + } + // LOGF(info, "collision_tmp.globalIndex() = %d, collision_tmp.neeuls() = %d, nv0_map = %d", collision_tmp.globalIndex(), collision_tmp.neeuls(), nv0_map[collision_tmp.globalIndex()]); + } + + fillV0Table(v0, true); + } // end of fullv0Id loop + + for (auto& collision : collisions) { + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + events_ngpcm(nv0_map[collision.globalIndex()]); + } // end of collision loop + pca_map.clear(); cospa_map.clear(); + nv0_map.clear(); stored_v0Ids.clear(); stored_v0Ids.shrink_to_fit(); + stored_fullv0Ids.clear(); + stored_fullv0Ids.shrink_to_fit(); } // end of build //! type of V0. 0: built solely for cascades (does not pass standard V0 cuts), 1: standard 2, 3: photon-like with TPC-only use. Regular analysis should always use type 1 or 3. @@ -742,15 +792,21 @@ struct PhotonConversionBuilder { void processRec(MyCollisions const& collisions, filteredV0s const& v0s, MyTracksIU const& tracks, aod::BCsWithTimestamps const& bcs) { - build(collisions, v0s, tracks, bcs); + build(collisions, v0s, tracks, bcs); } PROCESS_SWITCH(PhotonConversionBuilder, processRec, "process reconstructed info for data", true); void processMC(MyCollisionsMC const& collisions, filteredV0s const& v0s, MyTracksIUMC const& tracks, aod::BCsWithTimestamps const& bcs) { - build(collisions, v0s, tracks, bcs); + build(collisions, v0s, tracks, bcs); } PROCESS_SWITCH(PhotonConversionBuilder, processMC, "process reconstructed info for MC", false); + + void processRec_OnlyIfDielectron(soa::Join const& collisions, filteredV0s const& v0s, MyTracksIU const& tracks, aod::BCsWithTimestamps const& bcs) + { + build(collisions, v0s, tracks, bcs); + } + PROCESS_SWITCH(PhotonConversionBuilder, processRec_OnlyIfDielectron, "process reconstructed info for data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)