From f75d3f368c179d524cbccb88d375b728db98639e Mon Sep 17 00:00:00 2001 From: ddobrigk Date: Sun, 26 Nov 2023 22:19:17 +0100 Subject: [PATCH] [PWGLF] Strangeness data model improvement (#3998) * Extra work * Rename file * Improvements and adjustments * Cleanup * Please consider the following formatting changes (#191) --------- Co-authored-by: ALICE Builder --- PWGLF/DataModel/LFStrangenessTables.h | 271 ++++++----- PWGLF/TableProducer/CMakeLists.txt | 13 +- .../TableProducer/cascadecollisionbuilder.cxx | 88 ---- PWGLF/TableProducer/cascadelabelbuilder.cxx | 223 --------- PWGLF/TableProducer/cascademcbuilder.cxx | 432 ++++++++++++++++++ PWGLF/TableProducer/cascadepid.cxx | 10 +- PWGLF/TableProducer/lambdakzerobuilder.cxx | 27 -- .../lambdakzerocollisionbuilder.cxx | 88 ---- PWGLF/TableProducer/strangederivedbuilder.cxx | 235 ++++++++++ 9 files changed, 844 insertions(+), 543 deletions(-) delete mode 100644 PWGLF/TableProducer/cascadecollisionbuilder.cxx delete mode 100644 PWGLF/TableProducer/cascadelabelbuilder.cxx create mode 100644 PWGLF/TableProducer/cascademcbuilder.cxx delete mode 100644 PWGLF/TableProducer/lambdakzerocollisionbuilder.cxx create mode 100644 PWGLF/TableProducer/strangederivedbuilder.cxx diff --git a/PWGLF/DataModel/LFStrangenessTables.h b/PWGLF/DataModel/LFStrangenessTables.h index fc424228def..08729b1d25f 100644 --- a/PWGLF/DataModel/LFStrangenessTables.h +++ b/PWGLF/DataModel/LFStrangenessTables.h @@ -23,27 +23,80 @@ namespace o2::aod // Collision declarations for derived data analysis // this is optional but will ensure full flexibility // if required (for 2pc, etc) -DECLARE_SOA_TABLE(V0Collisions, "AOD", "V0COLLISION", //! track X positions at minima when using AO2Ds - collision::PosX, collision::PosY, collision::PosZ, - cent::CentFT0M, cent::CentFT0A, - cent::CentFT0C, cent::CentFV0A, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(CascCollisions, "AOD", "CASCCOLLISION", //! track X positions at minima when using AO2Ds +DECLARE_SOA_TABLE(StraCollisions, "AOD", "STRACOLLISION", //! track X positions at minima when using AO2Ds collision::PosX, collision::PosY, collision::PosZ, cent::CentFT0M, cent::CentFT0A, cent::CentFT0C, cent::CentFV0A, o2::soa::Marker<2>); -using V0Collision = V0Collisions::iterator; -using CascCollision = CascCollisions::iterator; +using StraCollision = StraCollisions::iterator; + +namespace dautrack +{ +//______________________________________________________ +// Daughter track declarations for derived data analysis +DECLARE_SOA_COLUMN(DetectorMap, detectorMap, uint8_t); //! detector map for reference +DECLARE_SOA_COLUMN(ITSClusterSizes, itsClusterSizes, uint32_t); //! ITS cluster sizes per layer +DECLARE_SOA_COLUMN(TPCClusters, tpcClusters, uint8_t); //! N TPC clusters +DECLARE_SOA_COLUMN(TPCCrossedRows, tpcCrossedRows, uint8_t); //! N TPC clusters + +//______________________________________________________ +// for extras: replicated here to ensure ease of manipulating the ITS information +// directly from the V0 extras table in simple ways for derived data as well +DECLARE_SOA_DYNAMIC_COLUMN(ITSClusterMap, itsClusterMap, //! ITS cluster map, one bit per layer, starting from the innermost + [](uint32_t itsClusterSizes) -> uint8_t { + uint8_t clmap = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) { + clmap |= (1 << layer); + } + } + return clmap; + }); +DECLARE_SOA_DYNAMIC_COLUMN(ITSNCls, itsNCls, //! Number of ITS clusters + [](uint32_t itsClusterSizes) -> uint8_t { + uint8_t itsNcls = 0; + for (int layer = 0; layer < 7; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) + itsNcls++; + } + return itsNcls; + }); +DECLARE_SOA_DYNAMIC_COLUMN(HasITS, hasITS, //! Flag to check if track has a ITS match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::ITS; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPC, hasTPC, //! Flag to check if track has a TPC match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TPC; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTRD, hasTRD, //! Flag to check if track has a TRD match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TRD; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTOF, hasTOF, //! Flag to check if track has a TOF measurement + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TOF; }); +} // namespace dautrack + +DECLARE_SOA_TABLE(DauTrackExtras, "AOD", "DAUTRACKEXTRA", //! detector properties of decay daughters + dautrack::DetectorMap, dautrack::ITSClusterSizes, + dautrack::TPCClusters, dautrack::TPCCrossedRows, + + // Dynamic columns for manipulating information + dautrack::ITSClusterMap, + dautrack::ITSNCls, + dautrack::HasITS, + dautrack::HasTPC, + dautrack::HasTRD, + dautrack::HasTOF); + +using DauTrackExtra = DauTrackExtras::iterator; namespace v0data { //______________________________________________________ -// REGULAR COLUMNS FOR V0INDICES +// REGULAR COLUMNS FOR INDEXING DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, Tracks, "_Pos"); //! DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, Tracks, "_Neg"); //! DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! DECLARE_SOA_INDEX_COLUMN(V0, v0); //! -DECLARE_SOA_INDEX_COLUMN(V0Collision, v0collision); //! +// FOR DERIVED +DECLARE_SOA_INDEX_COLUMN_FULL(PosTrackExtra, posTrackExtra, int, DauTrackExtras, "_PosExtra"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(NegTrackExtra, negTrackExtra, int, DauTrackExtras, "_NegExtra"); //! +DECLARE_SOA_INDEX_COLUMN(StraCollision, straCollision); //! //______________________________________________________ // REGULAR COLUMNS FOR V0CORES @@ -74,17 +127,6 @@ DECLARE_SOA_COLUMN(MomentumCovMat, momentumCovMat, float[6]); //! covariance mat // Saved from KF particle fit for specic table DECLARE_SOA_COLUMN(KFV0Chi2, kfV0Chi2, float); //! -//______________________________________________________ -// REGULAR COLUMNS FOR V0EXTRAS -DECLARE_SOA_COLUMN(PosTrackDetectorMap, posTrackDetectorMap, uint8_t); //! detector map for reference -DECLARE_SOA_COLUMN(NegTrackDetectorMap, negTrackDetectorMap, uint8_t); //! detector map for reference -DECLARE_SOA_COLUMN(PosTrackITSClusterSizes, posTrackITSClusterSizes, uint32_t); //! ITS cluster sizes per layer -DECLARE_SOA_COLUMN(NegTrackITSClusterSizes, negTrackITSClusterSizes, uint32_t); //! ITS cluster sizes per layer -DECLARE_SOA_COLUMN(PosTrackTPCClusters, posTrackTPCClusters, uint8_t); //! N TPC clusters -DECLARE_SOA_COLUMN(NegTrackTPCClusters, negTrackTPCClusters, uint8_t); //! N TPC clusters -DECLARE_SOA_COLUMN(PosTrackTPCCrossedRows, posTrackTPCCrossedRows, uint8_t); //! N TPC clusters -DECLARE_SOA_COLUMN(NegTrackTPCCrossedRows, negTrackTPCCrossedRows, uint8_t); //! N TPC clusters - //______________________________________________________ // REGULAR COLUMNS FOR V0MCCORES DECLARE_SOA_COLUMN(PDGCode, pdgCode, int); //! V0 PDG Code @@ -136,64 +178,6 @@ DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! Pseudorapidity, conditionally (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg) * (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg)) - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg))))); -//______________________________________________________ -// for extras: replicated here to ensure ease of manipulating the ITS information -// directly from the V0 extras table in simple ways for derived data as well -DECLARE_SOA_DYNAMIC_COLUMN(PosTrackITSClusterMap, posTrackITSClusterMap, //! ITS cluster map, one bit per layer, starting from the innermost - [](uint32_t itsClusterSizes) -> uint8_t { - uint8_t clmap = 0; - for (unsigned int layer = 0; layer < 7; layer++) { - if ((itsClusterSizes >> (layer * 4)) & 0xf) { - clmap |= (1 << layer); - } - } - return clmap; - }); -DECLARE_SOA_DYNAMIC_COLUMN(NegTrackITSClusterMap, negTrackITSClusterMap, //! ITS cluster map, one bit per layer, starting from the innermost - [](uint32_t itsClusterSizes) -> uint8_t { - uint8_t clmap = 0; - for (unsigned int layer = 0; layer < 7; layer++) { - if ((itsClusterSizes >> (layer * 4)) & 0xf) { - clmap |= (1 << layer); - } - } - return clmap; - }); -DECLARE_SOA_DYNAMIC_COLUMN(PosTrackITSNCls, posTrackITSNCls, //! Number of ITS clusters - [](uint32_t itsClusterSizes) -> uint8_t { - uint8_t itsNcls = 0; - for (int layer = 0; layer < 7; layer++) { - if ((itsClusterSizes >> (layer * 4)) & 0xf) - itsNcls++; - } - return itsNcls; - }); -DECLARE_SOA_DYNAMIC_COLUMN(NegTrackITSNCls, negTrackITSNCls, //! Number of ITS clusters - [](uint32_t itsClusterSizes) -> uint8_t { - uint8_t itsNcls = 0; - for (int layer = 0; layer < 7; layer++) { - if ((itsClusterSizes >> (layer * 4)) & 0xf) - itsNcls++; - } - return itsNcls; - }); -DECLARE_SOA_DYNAMIC_COLUMN(PosTrackHasITS, posTrackHasITS, //! Flag to check if track has a ITS match - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::ITS; }); -DECLARE_SOA_DYNAMIC_COLUMN(PosTrackHasTPC, posTrackHasTPC, //! Flag to check if track has a TPC match - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TPC; }); -DECLARE_SOA_DYNAMIC_COLUMN(PosTrackHasTRD, posTrackHasTRD, //! Flag to check if track has a TRD match - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TRD; }); -DECLARE_SOA_DYNAMIC_COLUMN(PosTrackHasTOF, posTrackHasTOF, //! Flag to check if track has a TOF measurement - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TOF; }); -DECLARE_SOA_DYNAMIC_COLUMN(NegTrackHasITS, negTrackHasITS, //! Flag to check if track has a ITS match - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::ITS; }); -DECLARE_SOA_DYNAMIC_COLUMN(NegTrackHasTPC, negTrackHasTPC, //! Flag to check if track has a TPC match - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TPC; }); -DECLARE_SOA_DYNAMIC_COLUMN(NegTrackHasTRD, negTrackHasTRD, //! Flag to check if track has a TRD match - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TRD; }); -DECLARE_SOA_DYNAMIC_COLUMN(NegTrackHasTOF, negTrackHasTOF, //! Flag to check if track has a TOF measurement - [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TOF; }); - //______________________________________________________ // DYNAMIC COLUMNS // Account for rigidity in case of hypertriton @@ -322,7 +306,10 @@ DECLARE_SOA_TABLE(V0Indices, "AOD", "V0INDEX", //! index table when using AO2Ds o2::soa::Index<>, v0data::PosTrackId, v0data::NegTrackId, v0data::CollisionId, v0data::V0Id); DECLARE_SOA_TABLE(V0CollRefs, "AOD", "V0COLLREF", //! optional table to refer back to a collision - o2::soa::Index<>, v0data::V0CollisionId); + o2::soa::Index<>, v0data::StraCollisionId); + +DECLARE_SOA_TABLE(V0Extras, "AOD", "V0EXTRA", //! optional table to refer to custom track extras + o2::soa::Index<>, v0data::PosTrackExtraId, v0data::NegTrackExtraId); DECLARE_SOA_TABLE(V0TrackXs, "AOD", "V0TRACKX", //! track X positions at minima when using AO2Ds v0data::PosX, v0data::NegX); @@ -374,26 +361,6 @@ DECLARE_SOA_EXTENDED_TABLE_USER(V0Cores, StoredV0Cores, "V0COREEXT", DECLARE_SOA_TABLE_FULL(V0Covs, "V0Covs", "AOD", "V0COVS", //! V0 covariance matrices v0data::PositionCovMat, v0data::MomentumCovMat); -DECLARE_SOA_TABLE(V0Extras, "AOD", "V0EXTRA", //! detector properties of the V0 decay - v0data::PosTrackDetectorMap, v0data::NegTrackDetectorMap, - v0data::PosTrackITSClusterSizes, v0data::NegTrackITSClusterSizes, - v0data::PosTrackTPCClusters, v0data::NegTrackTPCClusters, - v0data::PosTrackTPCCrossedRows, v0data::NegTrackTPCCrossedRows, - - // Dynamic columns for manipulating information - v0data::PosTrackITSClusterMap, - v0data::NegTrackITSClusterMap, - v0data::PosTrackITSNCls, - v0data::NegTrackITSNCls, - v0data::PosTrackHasITS, - v0data::PosTrackHasTPC, - v0data::PosTrackHasTRD, - v0data::PosTrackHasTOF, - v0data::NegTrackHasITS, - v0data::NegTrackHasTPC, - v0data::NegTrackHasTRD, - v0data::NegTrackHasTOF); - DECLARE_SOA_TABLE(V0MCCores, "AOD", "V0MCCORE", //! MC properties of the V0 for posterior analysis v0data::PDGCode, v0data::PDGCodeMother, v0data::PDGCodePositive, v0data::PDGCodeNegative, @@ -480,7 +447,11 @@ DECLARE_SOA_INDEX_COLUMN(Cascade, cascade); //! DECLARE_SOA_INDEX_COLUMN_FULL(Bachelor, bachelor, int, Tracks, ""); //! DECLARE_SOA_INDEX_COLUMN_FULL(StrangeTrack, strangeTrack, int, Tracks, ""); //! DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! -DECLARE_SOA_INDEX_COLUMN(CascCollision, cascCollision); //! +// FOR DERIVED +DECLARE_SOA_INDEX_COLUMN_FULL(PosTrackExtra, posTrackExtra, int, DauTrackExtras, "_PosExtra"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(NegTrackExtra, negTrackExtra, int, DauTrackExtras, "_NegExtra"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(BachTrackExtra, bachTrackExtra, int, DauTrackExtras, "_NegExtra"); //! +DECLARE_SOA_INDEX_COLUMN(StraCollision, straCollision); //! //______________________________________________________ // REGULAR COLUMNS FOR CASCCORES @@ -548,6 +519,49 @@ DECLARE_SOA_COLUMN(MatchingChi2, matchingChi2, float); //! DECLARE_SOA_COLUMN(TopologyChi2, topologyChi2, float); //! DECLARE_SOA_COLUMN(ItsClsSize, itsCluSize, float); //! +//______________________________________________________ +// REGULAR COLUMNS FOR CASCEXTRAS +DECLARE_SOA_COLUMN(PosTrackDetectorMap, posTrackDetectorMap, uint8_t); //! detector map for reference +DECLARE_SOA_COLUMN(NegTrackDetectorMap, negTrackDetectorMap, uint8_t); //! detector map for reference +DECLARE_SOA_COLUMN(BachTrackDetectorMap, bachTrackDetectorMap, uint8_t); //! detector map for reference +DECLARE_SOA_COLUMN(PosTrackITSClusterSizes, posTrackITSClusterSizes, uint32_t); //! ITS cluster sizes per layer +DECLARE_SOA_COLUMN(NegTrackITSClusterSizes, negTrackITSClusterSizes, uint32_t); //! ITS cluster sizes per layer +DECLARE_SOA_COLUMN(BachTrackITSClusterSizes, bachTrackITSClusterSizes, uint32_t); //! ITS cluster sizes per layer +DECLARE_SOA_COLUMN(PosTrackTPCClusters, posTrackTPCClusters, uint8_t); //! N TPC clusters +DECLARE_SOA_COLUMN(NegTrackTPCClusters, negTrackTPCClusters, uint8_t); //! N TPC clusters +DECLARE_SOA_COLUMN(BachTrackTPCClusters, bachTrackTPCClusters, uint8_t); //! N TPC clusters +DECLARE_SOA_COLUMN(PosTrackTPCCrossedRows, posTrackTPCCrossedRows, uint8_t); //! N TPC clusters +DECLARE_SOA_COLUMN(NegTrackTPCCrossedRows, negTrackTPCCrossedRows, uint8_t); //! N TPC clusters +DECLARE_SOA_COLUMN(BachTrackTPCCrossedRows, bachTrackTPCCrossedRows, uint8_t); //! N TPC clusters + +//______________________________________________________ +// REGULAR COLUMNS FOR CASCMCCORES +DECLARE_SOA_COLUMN(PDGCode, pdgCode, int); //! cascade PDG Code +DECLARE_SOA_COLUMN(PDGCodeMother, pdgCodeMother, int); //! cascade mother PDG code (for feeddown) +DECLARE_SOA_COLUMN(PDGCodeV0, pdgCodeV0, int); //! cascade PDG Code +DECLARE_SOA_COLUMN(PDGCodePositive, pdgCodePositive, int); //! V0 positive prong PDG code +DECLARE_SOA_COLUMN(PDGCodeNegative, pdgCodeNegative, int); //! V0 negative prong PDG code +DECLARE_SOA_COLUMN(PDGCodeBachelor, pdgCodeBachelor, int); //! cascade bachelor prong PDG code +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! is cascade physical primary +DECLARE_SOA_COLUMN(XMC, xMC, float); //! cascade decay position X (cm) +DECLARE_SOA_COLUMN(YMC, yMC, float); //! cascade decay position Y (cm) +DECLARE_SOA_COLUMN(ZMC, zMC, float); //! cascade decay position Z (cm) +DECLARE_SOA_COLUMN(XlambdaMC, xlambdaMC, float); //! V0 decay position X (cm) +DECLARE_SOA_COLUMN(YlambdaMC, ylambdaMC, float); //! V0 decay position Y (cm) +DECLARE_SOA_COLUMN(ZlambdaMC, zlambdaMC, float); //! V0 decay position Z (cm) +DECLARE_SOA_COLUMN(PxPosMC, pxPosMC, float); //! V0 positive daughter px (GeV/c) +DECLARE_SOA_COLUMN(PyPosMC, pyPosMC, float); //! V0 positive daughter py (GeV/c) +DECLARE_SOA_COLUMN(PzPosMC, pzPosMC, float); //! V0 positive daughter pz (GeV/c) +DECLARE_SOA_COLUMN(PxNegMC, pxNegMC, float); //! V0 positive daughter px (GeV/c) +DECLARE_SOA_COLUMN(PyNegMC, pyNegMC, float); //! V0 positive daughter py (GeV/c) +DECLARE_SOA_COLUMN(PzNegMC, pzNegMC, float); //! V0 positive daughter pz (GeV/c) +DECLARE_SOA_COLUMN(PxBachMC, pxBachMC, float); //! cascade bachelor daughter px (GeV/c) +DECLARE_SOA_COLUMN(PyBachMC, pyBachMC, float); //! cascade bachelor daughter py (GeV/c) +DECLARE_SOA_COLUMN(PzBachMC, pzBachMC, float); //! cascade bachelor daughter pz (GeV/c) +DECLARE_SOA_COLUMN(PxMC, pxMC, float); //! cascade px (GeV/c) +DECLARE_SOA_COLUMN(PyMC, pyMC, float); //! cascade py (GeV/c) +DECLARE_SOA_COLUMN(PzMC, pzMC, float); //! cascade pz (GeV/c) + //______________________________________________________ // DERIVED // Length quantities @@ -641,11 +655,21 @@ DECLARE_SOA_TABLE(TraCascIndices, "AOD", "TraCascINDEX", //! index table when us o2::soa::Index<>, cascdata::V0Id, cascdata::CascadeId, cascdata::BachelorId, cascdata::StrangeTrackId, cascdata::CollisionId); DECLARE_SOA_TABLE(CascCollRefs, "AOD", "CASCCOLLREF", //! optional table to refer back to a collision - o2::soa::Index<>, cascdata::CascCollisionId, o2::soa::Marker<1>); + o2::soa::Index<>, cascdata::StraCollisionId, o2::soa::Marker<1>); DECLARE_SOA_TABLE(KFCascCollRefs, "AOD", "KFCASCCOLLREF", //! optional table to refer back to a collision - o2::soa::Index<>, cascdata::CascCollisionId, o2::soa::Marker<2>); + o2::soa::Index<>, cascdata::StraCollisionId, o2::soa::Marker<2>); DECLARE_SOA_TABLE(TraCascCollRefs, "AOD", "TRACASCCOLLREF", //! optional table to refer back to a collision - o2::soa::Index<>, cascdata::CascCollisionId, o2::soa::Marker<3>); + o2::soa::Index<>, cascdata::StraCollisionId, o2::soa::Marker<3>); + +DECLARE_SOA_TABLE(CascExtras, "AOD", "CASCEXTRA", //! optional table to refer to custom track extras + o2::soa::Index<>, cascdata::PosTrackExtraId, cascdata::NegTrackExtraId, + cascdata::BachTrackExtraId, o2::soa::Marker<1>); +DECLARE_SOA_TABLE(KFCascExtras, "AOD", "KFCASCEXTRA", //! optional table to refer to custom track extras + o2::soa::Index<>, cascdata::PosTrackExtraId, cascdata::NegTrackExtraId, + cascdata::BachTrackExtraId, o2::soa::Marker<2>); +DECLARE_SOA_TABLE(TraCascExtras, "AOD", "TRACASCEXTRA", //! optional table to refer to custom track extras + o2::soa::Index<>, cascdata::PosTrackExtraId, cascdata::NegTrackExtraId, + cascdata::BachTrackExtraId, o2::soa::Marker<3>); DECLARE_SOA_TABLE(StoredCascCores, "AOD", "CASCCORE", //! core information about decay, viable with AO2Ds or derived cascdata::Sign, cascdata::MXi, cascdata::MOmega, @@ -730,6 +754,37 @@ DECLARE_SOA_TABLE(StoredTraCascCores, "AOD", "TRACASCCORE", //! cascdata::YXi, cascdata::YOmega); +DECLARE_SOA_TABLE(CascMCCores, "AOD", "CASCMCCORE", //! bachelor-baryon correlation variables + cascdata::PDGCode, cascdata::PDGCodeMother, cascdata::PDGCodeV0, cascdata::IsPhysicalPrimary, + cascdata::PDGCodePositive, cascdata::PDGCodeNegative, cascdata::PDGCodeBachelor, + cascdata::XMC, cascdata::YMC, cascdata::ZMC, + cascdata::XlambdaMC, cascdata::YlambdaMC, cascdata::ZlambdaMC, + cascdata::PxPosMC, cascdata::PyPosMC, cascdata::PzPosMC, + cascdata::PxNegMC, cascdata::PyNegMC, cascdata::PzNegMC, + cascdata::PxBachMC, cascdata::PyBachMC, cascdata::PzBachMC, + cascdata::PxMC, cascdata::PyMC, cascdata::PzMC, + o2::soa::Marker<1>); +DECLARE_SOA_TABLE(KFCascMCCores, "AOD", "KFCASCMCCORE", //! bachelor-baryon correlation variables + cascdata::PDGCode, cascdata::PDGCodeMother, cascdata::PDGCodeV0, cascdata::IsPhysicalPrimary, + cascdata::PDGCodePositive, cascdata::PDGCodeNegative, cascdata::PDGCodeBachelor, + cascdata::XMC, cascdata::YMC, cascdata::ZMC, + cascdata::XlambdaMC, cascdata::YlambdaMC, cascdata::ZlambdaMC, + cascdata::PxPosMC, cascdata::PyPosMC, cascdata::PzPosMC, + cascdata::PxNegMC, cascdata::PyNegMC, cascdata::PzNegMC, + cascdata::PxBachMC, cascdata::PyBachMC, cascdata::PzBachMC, + cascdata::PxMC, cascdata::PyMC, cascdata::PzMC, + o2::soa::Marker<2>); +DECLARE_SOA_TABLE(TraCascMCCores, "AOD", "TRACASCMCCORE", //! bachelor-baryon correlation variables + cascdata::PDGCode, cascdata::PDGCodeMother, cascdata::PDGCodeV0, cascdata::IsPhysicalPrimary, + cascdata::PDGCodePositive, cascdata::PDGCodeNegative, cascdata::PDGCodeBachelor, + cascdata::XMC, cascdata::YMC, cascdata::ZMC, + cascdata::XlambdaMC, cascdata::YlambdaMC, cascdata::ZlambdaMC, + cascdata::PxPosMC, cascdata::PyPosMC, cascdata::PzPosMC, + cascdata::PxNegMC, cascdata::PyNegMC, cascdata::PzNegMC, + cascdata::PxBachMC, cascdata::PyBachMC, cascdata::PzBachMC, + cascdata::PxMC, cascdata::PyMC, cascdata::PzMC, + o2::soa::Marker<3>); + DECLARE_SOA_TABLE(CascBBs, "AOD", "CASCBB", //! bachelor-baryon correlation variables cascdata::BachBaryonCosPA, cascdata::BachBaryonDCAxyToPV, o2::soa::Marker<1>) DECLARE_SOA_TABLE(KFCascBBs, "AOD", "KFCASCBB", //! bachelor-baryon correlation variables, KF @@ -856,6 +911,16 @@ DECLARE_SOA_TABLE(McCascBBTags, "AOD", "MCCASCBBTAG", //! Table joinable with Ca using McCascLabel = McCascLabels::iterator; using McCascBBTag = McCascBBTags::iterator; +// Definition of labels for kf cascades +namespace mckfcasclabel +{ +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for V0 +} // namespace mckfcasclabel + +DECLARE_SOA_TABLE(McKFCascLabels, "AOD", "MCKFCASCLABEL", //! Table joinable to cascdata containing the MC labels + mckfcasclabel::McParticleId); +using McKFCascLabel = McKFCascLabels::iterator; + // Definition of labels for tracked cascades namespace mctracasclabel { diff --git a/PWGLF/TableProducer/CMakeLists.txt b/PWGLF/TableProducer/CMakeLists.txt index bc07482e481..34078a45cf4 100644 --- a/PWGLF/TableProducer/CMakeLists.txt +++ b/PWGLF/TableProducer/CMakeLists.txt @@ -41,18 +41,13 @@ o2physics_add_dpl_workflow(lambdakzeropid PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lambdakzerocollisionbuilder - SOURCES lambdakzerocollisionbuilder.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(cascadebuilder SOURCES cascadebuilder.cxx PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore KFParticle::KFParticle COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(cascadelabelbuilder - SOURCES cascadelabelbuilder.cxx +o2physics_add_dpl_workflow(cascademcbuilder + SOURCES cascademcbuilder.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -71,8 +66,8 @@ o2physics_add_dpl_workflow(cascadepid PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(cascadecollisionbuilder - SOURCES cascadecollisionbuilder.cxx +o2physics_add_dpl_workflow(strangederivedbuilder + SOURCES strangederivedbuilder.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/cascadecollisionbuilder.cxx b/PWGLF/TableProducer/cascadecollisionbuilder.cxx deleted file mode 100644 index 9b0d63e7bfc..00000000000 --- a/PWGLF/TableProducer/cascadecollisionbuilder.cxx +++ /dev/null @@ -1,88 +0,0 @@ -// 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. -// - -#include -#include -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "DCAFitter/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFStrangenessPIDTables.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/TableProducer/PID/pidTOFBase.h" -#include "Common/DataModel/PIDResponse.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -struct cascadecollisionbuilder { - // TPC pid (copied over from central services for reference) - Produces casccollref; // raw table for checks - Produces casccoll; // table with Nsigmas - - Configurable fillEmptyCollisions{"fillEmptyCollisions", false, "fill collision entries without candidates"}; - - // For manual sliceBy - Preslice perCollision = o2::aod::cascdata::collisionId; - - void init(InitContext& context) - { - } - - void process(soa::Join const& collisions, aod::CascDatas const& Cascades) - { - int currentCollIdx = -1; - for (const auto& collision : collisions) { - const uint64_t collIdx = collision.globalIndex(); - auto CascTable_thisCollision = Cascades.sliceBy(perCollision, collIdx); - // casc table sliced - if (CascTable_thisCollision.size() > 0 || fillEmptyCollisions) { - if (currentCollIdx != collIdx) { - casccoll(collision.posX(), collision.posY(), collision.posZ(), - collision.centFT0M(), collision.centFT0A(), - collision.centFT0C(), collision.centFV0A()); - currentCollIdx = collIdx; - } - } - for (int i = 0; i < CascTable_thisCollision.size(); i++) { - casccollref(casccoll.lastIndex()); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/cascadelabelbuilder.cxx b/PWGLF/TableProducer/cascadelabelbuilder.cxx deleted file mode 100644 index 744d5166195..00000000000 --- a/PWGLF/TableProducer/cascadelabelbuilder.cxx +++ /dev/null @@ -1,223 +0,0 @@ -// 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. -// -// *+-+*+-+*+-+*+-+*+-+*+-+* -// Cascade label builder -// *+-+*+-+*+-+*+-+*+-+*+-+* -// -// Comments, questions, complaints, suggestions? -// Please write to: -// david.dobrigkeit.chinellato@cern.ch -// - -#include -#include -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -// For MC association in pre-selection -using LabeledTracks = soa::Join; - -//*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* -struct cascadeLabelBuilder { - Produces casclabels; // MC labels for cascades - Produces tracasclabels; // MC labels for cascades - Produces bbtags; // MC labels for cascades - void init(InitContext const&) {} - - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - // build cascade labels - void processCascades(aod::CascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const&) - { - for (auto& casc : casctable) { - // Loop over those that actually have the corresponding V0 associated to them - auto v0 = casc.v0_as(); - if (!(v0.has_v0Data())) { - casclabels(-1); - continue; // skip those cascades for which V0 doesn't exist - } - auto v0data = v0.v0Data(); // de-reference index to correct v0data in case it exists - int lLabel = -1; - - // Acquire all three daughter tracks, please - auto lBachTrack = casc.bachelor_as(); - auto lNegTrack = v0data.negTrack_as(); - auto lPosTrack = v0data.posTrack_as(); - - // Association check - // There might be smarter ways of doing this in the future - if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle() && lBachTrack.has_mcParticle()) { - auto lMCBachTrack = lBachTrack.mcParticle_as(); - auto lMCNegTrack = lNegTrack.mcParticle_as(); - auto lMCPosTrack = lPosTrack.mcParticle_as(); - - // Step 1: check if the mother is the same, go up a level - if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { - for (auto& lNegMother : lMCNegTrack.mothers_as()) { - for (auto& lPosMother : lMCPosTrack.mothers_as()) { - if (lNegMother == lPosMother) { - // if we got to this level, it means the mother particle exists and is the same - // now we have to go one level up and compare to the bachelor mother too - for (auto& lV0Mother : lNegMother.mothers_as()) { - for (auto& lBachMother : lMCBachTrack.mothers_as()) { - if (lV0Mother == lBachMother) { - lLabel = lV0Mother.globalIndex(); - } - } - } // end conditional V0-bach pair - } // end neg = pos mother conditional - } - } // end loop neg/pos mothers - } // end conditional of mothers existing - } // end association check - // Construct label table (note: this will be joinable with CascDatas) - casclabels( - lLabel); - } // end casctable loop - } - - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - // build tracked cascade labels - void processTrackedCascades(aod::TraCascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const&) - { - for (auto& casc : casctable) { - // Loop over those that actually have the corresponding V0 associated to them - auto v0 = casc.v0_as(); - if (!(v0.has_v0Data())) { - tracasclabels(-1); - continue; // skip those cascades for which V0 doesn't exist - } - auto v0data = v0.v0Data(); // de-reference index to correct v0data in case it exists - int lLabel = -1; - - // Acquire all three daughter tracks, please - auto lBachTrack = casc.bachelor_as(); - auto lNegTrack = v0data.negTrack_as(); - auto lPosTrack = v0data.posTrack_as(); - - // Association check - // There might be smarter ways of doing this in the future - if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle() && lBachTrack.has_mcParticle()) { - auto lMCBachTrack = lBachTrack.mcParticle_as(); - auto lMCNegTrack = lNegTrack.mcParticle_as(); - auto lMCPosTrack = lPosTrack.mcParticle_as(); - - // Step 1: check if the mother is the same, go up a level - if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { - for (auto& lNegMother : lMCNegTrack.mothers_as()) { - for (auto& lPosMother : lMCPosTrack.mothers_as()) { - if (lNegMother == lPosMother) { - // if we got to this level, it means the mother particle exists and is the same - // now we have to go one level up and compare to the bachelor mother too - for (auto& lV0Mother : lNegMother.mothers_as()) { - for (auto& lBachMother : lMCBachTrack.mothers_as()) { - if (lV0Mother == lBachMother) { - lLabel = lV0Mother.globalIndex(); - } - } - } // end conditional V0-bach pair - } // end neg = pos mother conditional - } - } // end loop neg/pos mothers - } // end conditional of mothers existing - } // end association check - // Construct label table (note: this will be joinable with CascDatas) - tracasclabels( - lLabel); - } // end casctable loop - } - - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - // build cascade labels - void processBBTags(aod::CascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const&) - { - for (auto& casc : casctable) { - bool bbTag = false; // bachelor-baryon correlation tag to pass - - // Loop over those that actually have the corresponding V0 associated to them - auto v0 = casc.v0_as(); - if (!(v0.has_v0Data())) { - bbtags(bbTag); - continue; // skip those cascades for which V0 doesn't exist - } - auto v0data = v0.v0Data(); // de-reference index to correct v0data in case it exists - - // Acquire all three daughter tracks, please - auto lBachTrack = casc.bachelor_as(); - auto lNegTrack = v0data.negTrack_as(); - auto lPosTrack = v0data.posTrack_as(); - - // Bachelor-baryon association checker - // this will allow for analyses to pinpoint the effect of spurious, unwanted correlations! - - if (lBachTrack.has_mcParticle()) { - auto bachelorParticle = lBachTrack.mcParticle_as(); - if (bachelorParticle.pdgCode() == 211) { // pi+, look for antiproton in negative prong - if (lNegTrack.has_mcParticle()) { - auto baryonParticle = lNegTrack.mcParticle_as(); - if (baryonParticle.has_mothers() && bachelorParticle.has_mothers() && baryonParticle.pdgCode() == -2212) { - for (auto& baryonMother : baryonParticle.mothers_as()) { - for (auto& pionMother : bachelorParticle.mothers_as()) { - if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == -3122) { - bbTag = true; - } - } - } - } - } - } // end if-pion - if (bachelorParticle.pdgCode() == -211) { // pi-, look for proton in positive prong - if (lNegTrack.has_mcParticle()) { - auto baryonParticle = lPosTrack.mcParticle_as(); - if (baryonParticle.has_mothers() && bachelorParticle.has_mothers() && baryonParticle.pdgCode() == 2212) { - for (auto& baryonMother : baryonParticle.mothers_as()) { - for (auto& pionMother : bachelorParticle.mothers_as()) { - if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == 3122) { - bbTag = true; - } - } - } - } - } - } // end if-pion - } // end bachelor has mcparticle - // Construct label table (note: this will be joinable with CascDatas) - bbtags(bbTag); - } // end casctable loop - } - - PROCESS_SWITCH(cascadeLabelBuilder, processCascades, "Produce regular cascade label tables", true); - PROCESS_SWITCH(cascadeLabelBuilder, processTrackedCascades, "Produce tracked cascade label tables", false); - PROCESS_SWITCH(cascadeLabelBuilder, processBBTags, "Produce cascade bach-baryon correlation tags", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/cascademcbuilder.cxx b/PWGLF/TableProducer/cascademcbuilder.cxx new file mode 100644 index 00000000000..edfb51d40d0 --- /dev/null +++ b/PWGLF/TableProducer/cascademcbuilder.cxx @@ -0,0 +1,432 @@ +// 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. +// +// *+-+*+-+*+-+*+-+*+-+*+-+* +// Cascade label builder +// *+-+*+-+*+-+*+-+*+-+*+-+* +// +// Comments, questions, complaints, suggestions? +// Please write to: +// david.dobrigkeit.chinellato@cern.ch +// + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +// For MC association in pre-selection +using LabeledTracks = soa::Join; + +//*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +struct cascademcbuilder { + Produces casclabels; // MC labels for cascades + Produces kfcasclabels; // MC labels for tracked cascades + Produces tracasclabels; // MC labels for tracked cascades + Produces bbtags; // bb tags (inv structure tagging) + Produces cascmccores; // optionally aggregate information from MC side for posterior analysis (derived data) + Produces kfcascmccores; // optionally aggregate information from MC side for posterior analysis (derived data) + Produces tracascmccores; // optionally aggregate information from MC side for posterior analysis (derived data) + + Configurable populateCascMCCores{"populateCascMCCores", false, "populate CascMCCores table for derived data analysis"}; + Configurable populateKFCascMCCores{"populateKFCascMCCores", false, "populate KFCascMCCores table for derived data analysis"}; + Configurable populateTraCascMCCores{"populateTraCascMCCores", false, "populate TraCascMCCores table for derived data analysis"}; + + void init(InitContext const&) {} + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // build cascade labels + void processCascades(aod::CascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const&) + { + int pdgCode = -1, pdgCodeMother = -1; + int pdgCodePositive = -1, pdgCodeNegative = -1, pdgCodeBachelor = -1, pdgCodeV0 = -1; + bool isPhysicalPrimary = false; + float xmc = -999.0f, ymc = -999.0f, zmc = -999.0f; + float xlmc = -999.0f, ylmc = -999.0f, zlmc = -999.0f; + float pxposmc = -999.0f, pyposmc = -999.0f, pzposmc = -999.0f; + float pxnegmc = -999.0f, pynegmc = -999.0f, pznegmc = -999.0f; + float pxbachmc = -999.0f, pybachmc = -999.0f, pzbachmc = -999.0f; + float px = -999.0f, py = -999.0f, pz = -999.0f; + for (auto& casc : casctable) { + // Loop over those that actually have the corresponding V0 associated to them + auto v0 = casc.v0_as(); + if (!(v0.has_v0Data())) { + casclabels(-1); + continue; // skip those cascades for which V0 doesn't exist + } + auto v0data = v0.v0Data(); // de-reference index to correct v0data in case it exists + int lLabel = -1; + + // Acquire all three daughter tracks, please + auto lBachTrack = casc.bachelor_as(); + auto lNegTrack = v0data.negTrack_as(); + auto lPosTrack = v0data.posTrack_as(); + + // Association check + // There might be smarter ways of doing this in the future + if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle() && lBachTrack.has_mcParticle()) { + auto lMCBachTrack = lBachTrack.mcParticle_as(); + auto lMCNegTrack = lNegTrack.mcParticle_as(); + auto lMCPosTrack = lPosTrack.mcParticle_as(); + + pdgCodePositive = lMCPosTrack.pdgCode(); + pdgCodeNegative = lMCNegTrack.pdgCode(); + pdgCodeBachelor = lMCBachTrack.pdgCode(); + pxposmc = lMCPosTrack.px(); + pyposmc = lMCPosTrack.py(); + pzposmc = lMCPosTrack.pz(); + pxnegmc = lMCNegTrack.px(); + pynegmc = lMCNegTrack.py(); + pznegmc = lMCNegTrack.pz(); + pxbachmc = lMCBachTrack.px(); + pybachmc = lMCBachTrack.py(); + pzbachmc = lMCBachTrack.pz(); + + // Step 1: check if the mother is the same, go up a level + if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { + for (auto& lNegMother : lMCNegTrack.mothers_as()) { + for (auto& lPosMother : lMCPosTrack.mothers_as()) { + if (lNegMother == lPosMother) { + // acquire information + xlmc = lNegMother.vx(); + ylmc = lNegMother.vy(); + zlmc = lNegMother.vz(); + pdgCodeV0 = lNegMother.pdgCode(); + + // if we got to this level, it means the mother particle exists and is the same + // now we have to go one level up and compare to the bachelor mother too + for (auto& lV0Mother : lNegMother.mothers_as()) { + for (auto& lBachMother : lMCBachTrack.mothers_as()) { + if (lV0Mother == lBachMother) { + lLabel = lV0Mother.globalIndex(); + pdgCode = lV0Mother.pdgCode(); + isPhysicalPrimary = lV0Mother.isPhysicalPrimary(); + xmc = lV0Mother.vx(); + ymc = lV0Mother.vy(); + zmc = lV0Mother.vz(); + px = lV0Mother.px(); + py = lV0Mother.py(); + pz = lV0Mother.pz(); + if (lV0Mother.has_mothers()) { + for (auto& lV0GrandMother : lV0Mother.mothers_as()) { + pdgCodeMother = lV0GrandMother.pdgCode(); + } + } + } + } + } // end conditional V0-bach pair + } // end neg = pos mother conditional + } + } // end loop neg/pos mothers + } // end conditional of mothers existing + } // end association check + // Construct label table (note: this will be joinable with CascDatas) + casclabels( + lLabel); + if (populateCascMCCores) { + cascmccores( + pdgCode, pdgCodeMother, pdgCodeV0, isPhysicalPrimary, + pdgCodePositive, pdgCodeNegative, pdgCodeBachelor, + xmc, ymc, zmc, xlmc, ylmc, zlmc, + pxposmc, pyposmc, pzposmc, + pxnegmc, pynegmc, pznegmc, + pxbachmc, pybachmc, pzbachmc, + px, py, pz); + } + } // end casctable loop + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // build kf cascade labels + void processKFCascades(aod::KFCascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const&) + { + int pdgCode = -1, pdgCodeMother = -1; + int pdgCodePositive = -1, pdgCodeNegative = -1, pdgCodeBachelor = -1, pdgCodeV0 = -1; + bool isPhysicalPrimary = false; + float xmc = -999.0f, ymc = -999.0f, zmc = -999.0f; + float xlmc = -999.0f, ylmc = -999.0f, zlmc = -999.0f; + float pxposmc = -999.0f, pyposmc = -999.0f, pzposmc = -999.0f; + float pxnegmc = -999.0f, pynegmc = -999.0f, pznegmc = -999.0f; + float pxbachmc = -999.0f, pybachmc = -999.0f, pzbachmc = -999.0f; + float px = -999.0f, py = -999.0f, pz = -999.0f; + for (auto& casc : casctable) { + // Loop over those that actually have the corresponding V0 associated to them + auto v0 = casc.v0(); + int lLabel = -1; + + // Acquire all three daughter tracks, please + auto lBachTrack = casc.bachelor_as(); + auto lNegTrack = v0.negTrack_as(); + auto lPosTrack = v0.posTrack_as(); + + // Association check + // There might be smarter ways of doing this in the future + if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle() && lBachTrack.has_mcParticle()) { + auto lMCBachTrack = lBachTrack.mcParticle_as(); + auto lMCNegTrack = lNegTrack.mcParticle_as(); + auto lMCPosTrack = lPosTrack.mcParticle_as(); + + pdgCodePositive = lMCPosTrack.pdgCode(); + pdgCodeNegative = lMCNegTrack.pdgCode(); + pdgCodeBachelor = lMCBachTrack.pdgCode(); + pxposmc = lMCPosTrack.px(); + pyposmc = lMCPosTrack.py(); + pzposmc = lMCPosTrack.pz(); + pxnegmc = lMCNegTrack.px(); + pynegmc = lMCNegTrack.py(); + pznegmc = lMCNegTrack.pz(); + pxbachmc = lMCBachTrack.px(); + pybachmc = lMCBachTrack.py(); + pzbachmc = lMCBachTrack.pz(); + + // Step 1: check if the mother is the same, go up a level + if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { + for (auto& lNegMother : lMCNegTrack.mothers_as()) { + for (auto& lPosMother : lMCPosTrack.mothers_as()) { + if (lNegMother == lPosMother) { + // acquire information + xlmc = lNegMother.vx(); + ylmc = lNegMother.vy(); + zlmc = lNegMother.vz(); + pdgCodeV0 = lNegMother.pdgCode(); + + // if we got to this level, it means the mother particle exists and is the same + // now we have to go one level up and compare to the bachelor mother too + for (auto& lV0Mother : lNegMother.mothers_as()) { + for (auto& lBachMother : lMCBachTrack.mothers_as()) { + if (lV0Mother == lBachMother) { + lLabel = lV0Mother.globalIndex(); + pdgCode = lV0Mother.pdgCode(); + isPhysicalPrimary = lV0Mother.isPhysicalPrimary(); + xmc = lV0Mother.vx(); + ymc = lV0Mother.vy(); + zmc = lV0Mother.vz(); + px = lV0Mother.px(); + py = lV0Mother.py(); + pz = lV0Mother.pz(); + if (lV0Mother.has_mothers()) { + for (auto& lV0GrandMother : lV0Mother.mothers_as()) { + pdgCodeMother = lV0GrandMother.pdgCode(); + } + } + } + } + } // end conditional V0-bach pair + } // end neg = pos mother conditional + } + } // end loop neg/pos mothers + } // end conditional of mothers existing + } // end association check + // Construct label table (note: this will be joinable with CascDatas) + kfcasclabels( + lLabel); + if (populateKFCascMCCores) { + kfcascmccores( + pdgCode, pdgCodeMother, pdgCodeV0, isPhysicalPrimary, + pdgCodePositive, pdgCodeNegative, pdgCodeBachelor, + xmc, ymc, zmc, xlmc, ylmc, zlmc, + pxposmc, pyposmc, pzposmc, + pxnegmc, pynegmc, pznegmc, + pxbachmc, pybachmc, pzbachmc, + px, py, pz); + } + } // end casctable loop + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // build tracked cascade labels + void processTrackedCascades(aod::TraCascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const&) + { + int pdgCode = -1, pdgCodeMother = -1; + int pdgCodePositive = -1, pdgCodeNegative = -1, pdgCodeBachelor = -1, pdgCodeV0 = -1; + bool isPhysicalPrimary = false; + float xmc = -999.0f, ymc = -999.0f, zmc = -999.0f; + float xlmc = -999.0f, ylmc = -999.0f, zlmc = -999.0f; + float pxposmc = -999.0f, pyposmc = -999.0f, pzposmc = -999.0f; + float pxnegmc = -999.0f, pynegmc = -999.0f, pznegmc = -999.0f; + float pxbachmc = -999.0f, pybachmc = -999.0f, pzbachmc = -999.0f; + float px = -999.0f, py = -999.0f, pz = -999.0f; + for (auto& casc : casctable) { + // Loop over those that actually have the corresponding V0 associated to them + auto v0 = casc.v0_as(); + if (!(v0.has_v0Data())) { + tracasclabels(-1); + continue; // skip those cascades for which V0 doesn't exist + } + auto v0data = v0.v0Data(); // de-reference index to correct v0data in case it exists + int lLabel = -1; + + // Acquire all three daughter tracks, please + auto lBachTrack = casc.bachelor_as(); + auto lNegTrack = v0data.negTrack_as(); + auto lPosTrack = v0data.posTrack_as(); + + // Association check + // There might be smarter ways of doing this in the future + if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle() && lBachTrack.has_mcParticle()) { + auto lMCBachTrack = lBachTrack.mcParticle_as(); + auto lMCNegTrack = lNegTrack.mcParticle_as(); + auto lMCPosTrack = lPosTrack.mcParticle_as(); + + pdgCodePositive = lMCPosTrack.pdgCode(); + pdgCodeNegative = lMCNegTrack.pdgCode(); + pdgCodeBachelor = lMCBachTrack.pdgCode(); + pxposmc = lMCPosTrack.px(); + pyposmc = lMCPosTrack.py(); + pzposmc = lMCPosTrack.pz(); + pxnegmc = lMCNegTrack.px(); + pynegmc = lMCNegTrack.py(); + pznegmc = lMCNegTrack.pz(); + pxbachmc = lMCBachTrack.px(); + pybachmc = lMCBachTrack.py(); + pzbachmc = lMCBachTrack.pz(); + + // Step 1: check if the mother is the same, go up a level + if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { + for (auto& lNegMother : lMCNegTrack.mothers_as()) { + for (auto& lPosMother : lMCPosTrack.mothers_as()) { + if (lNegMother == lPosMother) { + // acquire information + xlmc = lNegMother.vx(); + ylmc = lNegMother.vy(); + zlmc = lNegMother.vz(); + pdgCodeV0 = lNegMother.pdgCode(); + + // if we got to this level, it means the mother particle exists and is the same + // now we have to go one level up and compare to the bachelor mother too + for (auto& lV0Mother : lNegMother.mothers_as()) { + for (auto& lBachMother : lMCBachTrack.mothers_as()) { + if (lV0Mother == lBachMother) { + lLabel = lV0Mother.globalIndex(); + pdgCode = lV0Mother.pdgCode(); + isPhysicalPrimary = lV0Mother.isPhysicalPrimary(); + xmc = lV0Mother.vx(); + ymc = lV0Mother.vy(); + zmc = lV0Mother.vz(); + px = lV0Mother.px(); + py = lV0Mother.py(); + pz = lV0Mother.pz(); + if (lV0Mother.has_mothers()) { + for (auto& lV0GrandMother : lV0Mother.mothers_as()) { + pdgCodeMother = lV0GrandMother.pdgCode(); + } + } + } + } + } // end conditional V0-bach pair + } // end neg = pos mother conditional + } + } // end loop neg/pos mothers + } // end conditional of mothers existing + } // end association check + // Construct label table (note: this will be joinable with CascDatas) + tracasclabels( + lLabel); + if (populateTraCascMCCores) { + tracascmccores( + pdgCode, pdgCodeMother, pdgCodeV0, isPhysicalPrimary, + pdgCodePositive, pdgCodeNegative, pdgCodeBachelor, + xmc, ymc, zmc, xlmc, ylmc, zlmc, + pxposmc, pyposmc, pzposmc, + pxnegmc, pynegmc, pznegmc, + pxbachmc, pybachmc, pzbachmc, + px, py, pz); + } + } // end casctable loop + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // build cascade labels + void processBBTags(aod::CascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const&) + { + for (auto& casc : casctable) { + bool bbTag = false; // bachelor-baryon correlation tag to pass + + // Loop over those that actually have the corresponding V0 associated to them + auto v0 = casc.v0_as(); + if (!(v0.has_v0Data())) { + bbtags(bbTag); + continue; // skip those cascades for which V0 doesn't exist + } + auto v0data = v0.v0Data(); // de-reference index to correct v0data in case it exists + + // Acquire all three daughter tracks, please + auto lBachTrack = casc.bachelor_as(); + auto lNegTrack = v0data.negTrack_as(); + auto lPosTrack = v0data.posTrack_as(); + + // Bachelor-baryon association checker + // this will allow for analyses to pinpoint the effect of spurious, unwanted correlations! + + if (lBachTrack.has_mcParticle()) { + auto bachelorParticle = lBachTrack.mcParticle_as(); + if (bachelorParticle.pdgCode() == 211) { // pi+, look for antiproton in negative prong + if (lNegTrack.has_mcParticle()) { + auto baryonParticle = lNegTrack.mcParticle_as(); + if (baryonParticle.has_mothers() && bachelorParticle.has_mothers() && baryonParticle.pdgCode() == -2212) { + for (auto& baryonMother : baryonParticle.mothers_as()) { + for (auto& pionMother : bachelorParticle.mothers_as()) { + if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == -3122) { + bbTag = true; + } + } + } + } + } + } // end if-pion + if (bachelorParticle.pdgCode() == -211) { // pi-, look for proton in positive prong + if (lNegTrack.has_mcParticle()) { + auto baryonParticle = lPosTrack.mcParticle_as(); + if (baryonParticle.has_mothers() && bachelorParticle.has_mothers() && baryonParticle.pdgCode() == 2212) { + for (auto& baryonMother : baryonParticle.mothers_as()) { + for (auto& pionMother : bachelorParticle.mothers_as()) { + if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == 3122) { + bbTag = true; + } + } + } + } + } + } // end if-pion + } // end bachelor has mcparticle + // Construct label table (note: this will be joinable with CascDatas) + bbtags(bbTag); + } // end casctable loop + } + + PROCESS_SWITCH(cascademcbuilder, processCascades, "Produce regular cascade label tables", true); + PROCESS_SWITCH(cascademcbuilder, processKFCascades, "Produce KF cascade label tables", false); + PROCESS_SWITCH(cascademcbuilder, processTrackedCascades, "Produce tracked cascade label tables", false); + PROCESS_SWITCH(cascademcbuilder, processBBTags, "Produce cascade bach-baryon correlation tags", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/cascadepid.cxx b/PWGLF/TableProducer/cascadepid.cxx index 61ed41d4b93..c0132237046 100644 --- a/PWGLF/TableProducer/cascadepid.cxx +++ b/PWGLF/TableProducer/cascadepid.cxx @@ -233,7 +233,7 @@ struct cascadepid { return 0.0299792458 * TMath::Sqrt(lA / (1 + lA)); } - void processTPC(aod::Collisions const& collisions, aod::CascDatas const& Cascades, TracksExtraWithPID const&, aod::BCsWithTimestamps const&, TaggedCascades const& allCascades, aod::V0s const&) + void processTPC(aod::Collisions const& collisions, aod::CascDatas const& Cascades, TracksExtraWithPID const&, aod::BCsWithTimestamps const&, aod::V0s const&) { for (const auto& collision : collisions) { // Fire up CCDB @@ -262,7 +262,7 @@ struct cascadepid { } } - void processTOF(aod::Collisions const& collisions, aod::CascDatas const& Cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&, TaggedCascades const& allCascades, aod::V0s const&) + void processTOF(aod::Collisions const& collisions, aod::CascDatas const& Cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&, aod::V0s const&) { for (const auto& collision : collisions) { // Fire up CCDB @@ -274,10 +274,10 @@ struct cascadepid { // cascade table sliced for (auto const& cascade : CascTable_thisCollision) { // Track casting - auto bachTrack = cascade.bachelor_as(); + auto bachTrack = cascade.bachelor_as(); auto v0 = cascade.v0(); - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); // FIXME: TOF calculation: under construction, to follow diff --git a/PWGLF/TableProducer/lambdakzerobuilder.cxx b/PWGLF/TableProducer/lambdakzerobuilder.cxx index 6b91c44b320..bba4e6070fb 100644 --- a/PWGLF/TableProducer/lambdakzerobuilder.cxx +++ b/PWGLF/TableProducer/lambdakzerobuilder.cxx @@ -93,7 +93,6 @@ struct lambdakzeroBuilder { Produces v0indices; Produces v0cores; Produces v0trackXs; - Produces v0extras; Produces v0covs; // covariances Service ccdb; @@ -124,7 +123,6 @@ struct lambdakzeroBuilder { Configurable d_doTrackQA{"d_doTrackQA", false, "do track QA"}; Configurable d_QA_checkMC{"d_QA_checkMC", true, "check MC truth in QA"}; Configurable d_QA_checkdEdx{"d_QA_checkdEdx", false, "check dEdx in QA"}; - Configurable populateExtras{"populateExtras", false, "populate V0 extras (for derived data)"}; // CCDB options Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -198,14 +196,6 @@ struct lambdakzeroBuilder { float V0radius; float lambdaMass; float antilambdaMass; - uint8_t posTrackDetMap; - uint8_t negTrackDetMap; - uint32_t posTrackITSClusterSizes; - uint32_t negTrackITSClusterSizes; - uint8_t posTrackTPCClusters; - uint8_t negTrackTPCClusters; - uint8_t posTrackTPCCrossedRows; - uint8_t negTrackTPCCrossedRows; } v0candidate; // Helper struct to do bookkeeping of building parameters @@ -635,15 +625,6 @@ struct lambdakzeroBuilder { statisticsRegistry.v0stats[kV0Radius]++; // Return OK: passed all v0 candidate selecton criteria - v0candidate.posTrackDetMap = posTrack.detectorMap(); - v0candidate.negTrackDetMap = negTrack.detectorMap(); - v0candidate.posTrackITSClusterSizes = posTrack.itsClusterSizes(); - v0candidate.negTrackITSClusterSizes = negTrack.itsClusterSizes(); - v0candidate.posTrackTPCClusters = posTrack.tpcNClsFound(); - v0candidate.negTrackTPCClusters = negTrack.tpcNClsFound(); - v0candidate.posTrackTPCCrossedRows = posTrack.tpcNClsCrossedRows(); - v0candidate.negTrackTPCCrossedRows = negTrack.tpcNClsCrossedRows(); - if (d_doTrackQA) { if (posTrack.itsNCls() < 10) statisticsRegistry.posITSclu[posTrack.itsNCls()]++; @@ -786,14 +767,6 @@ struct lambdakzeroBuilder { v0candidate.cosPA, v0candidate.dcav0topv); - // populate V0 extras in case requested - if (populateExtras) { - v0extras(v0candidate.posTrackDetMap, v0candidate.negTrackDetMap, - v0candidate.posTrackITSClusterSizes, v0candidate.negTrackITSClusterSizes, - v0candidate.posTrackTPCClusters, v0candidate.negTrackTPCClusters, - v0candidate.posTrackTPCCrossedRows, v0candidate.negTrackTPCCrossedRows); - } - // populate V0 covariance matrices if required by any other task if (createV0CovMats) { // Calculate position covariance matrix diff --git a/PWGLF/TableProducer/lambdakzerocollisionbuilder.cxx b/PWGLF/TableProducer/lambdakzerocollisionbuilder.cxx deleted file mode 100644 index aa05ae591ae..00000000000 --- a/PWGLF/TableProducer/lambdakzerocollisionbuilder.cxx +++ /dev/null @@ -1,88 +0,0 @@ -// 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. -// - -#include -#include -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "DCAFitter/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFStrangenessPIDTables.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/TableProducer/PID/pidTOFBase.h" -#include "Common/DataModel/PIDResponse.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -struct lambdakzerocollisionbuilder { - // TPC pid (copied over from central services for reference) - Produces v0collref; // raw table for checks - Produces v0coll; // table with Nsigmas - - Configurable fillEmptyCollisions{"fillEmptyCollisions", false, "fill collision entries without candidates"}; - - // For manual sliceBy - Preslice perCollision = o2::aod::v0data::collisionId; - - void init(InitContext& context) - { - } - - void process(soa::Join const& collisions, aod::V0Datas const& V0s) - { - int currentCollIdx = -1; - for (const auto& collision : collisions) { - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - // V0 table sliced - if (V0Table_thisCollision.size() > 0 || fillEmptyCollisions) { - if (currentCollIdx != collIdx) { - v0coll(collision.posX(), collision.posY(), collision.posZ(), - collision.centFT0M(), collision.centFT0A(), - collision.centFT0C(), collision.centFV0A()); - currentCollIdx = collIdx; - } - } - for (int i = 0; i < V0Table_thisCollision.size(); i++) { - v0collref(v0coll.lastIndex()); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/strangederivedbuilder.cxx b/PWGLF/TableProducer/strangederivedbuilder.cxx new file mode 100644 index 00000000000..66377fb3189 --- /dev/null +++ b/PWGLF/TableProducer/strangederivedbuilder.cxx @@ -0,0 +1,235 @@ +// 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. +// +//__________________________________________________ +// this task provides general links between collisions +// and strange objects reconstructed in various ways. +// It is meant to help with providing auxiliary information +// when dealing with derived data. + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "DCAFitter/DCAFitterN.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/DataModel/PIDResponse.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using TracksWithExtra = soa::Join; + +struct strangederivedbuilder { + //__________________________________________________ + // fundamental building blocks of derived data + Produces strangeColl; // characterises collisions + Produces v0collref; // references collisions from V0s + Produces casccollref; // references collisions from cascades + Produces kfcasccollref; // references collisions from cascades + Produces tracasccollref; // references collisions from cascades + + //__________________________________________________ + // track extra references + Produces dauTrackExtras; // DauTrackExtras + Produces v0Extras; // references DauTracks from V0s + Produces cascExtras; // references DauTracks from V0s + Produces kfcascExtras; // references DauTracks from V0s + Produces tracascExtras; // references DauTracks from V0s + + //__________________________________________________ + // correlation information between cascades: standard<->KF, standard<->tracked, KF<->tracked + + Configurable fillEmptyCollisions{"fillEmptyCollisions", false, "fill collision entries without candidates"}; + + // For manual sliceBy + Preslice V0perCollision = o2::aod::v0data::collisionId; + Preslice CascperCollision = o2::aod::cascdata::collisionId; + Preslice KFCascperCollision = o2::aod::cascdata::collisionId; + Preslice TraCascperCollision = o2::aod::cascdata::collisionId; + + void init(InitContext& context) + { + } + + void processCollisions(soa::Join const& collisions, aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades) + { + int currentCollIdx = -1; + for (const auto& collision : collisions) { + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisColl = V0s.sliceBy(V0perCollision, collIdx); + auto CascTable_thisColl = Cascades.sliceBy(CascperCollision, collIdx); + auto KFCascTable_thisColl = KFCascades.sliceBy(KFCascperCollision, collIdx); + auto TraCascTable_thisColl = TraCascades.sliceBy(TraCascperCollision, collIdx); + bool strange = V0Table_thisColl.size() > 0 || + CascTable_thisColl.size() > 0 || + KFCascTable_thisColl.size() > 0 || + TraCascTable_thisColl.size() > 0; + // casc table sliced + if (strange || fillEmptyCollisions) { + if (currentCollIdx != collIdx) { + strangeColl(collision.posX(), collision.posY(), collision.posZ(), + collision.centFT0M(), collision.centFT0A(), + collision.centFT0C(), collision.centFV0A()); + currentCollIdx = collIdx; + } + } + for (int i = 0; i < V0Table_thisColl.size(); i++) + v0collref(strangeColl.lastIndex()); + for (int i = 0; i < CascTable_thisColl.size(); i++) + casccollref(strangeColl.lastIndex()); + for (int i = 0; i < KFCascTable_thisColl.size(); i++) + kfcasccollref(strangeColl.lastIndex()); + for (int i = 0; i < TraCascTable_thisColl.size(); i++) + tracasccollref(strangeColl.lastIndex()); + } + } + + void processTrackExtras(aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, TracksWithExtra const& tracksExtra) + { + std::vector trackMap(tracksExtra.size(), -1); // index -1: not used + + //__________________________________________________ + // mark tracks that belong to V0s + for (auto const& v0 : V0s) { + auto const& posTrack = v0.posTrack_as(); + auto const& negTrack = v0.negTrack_as(); + trackMap[posTrack.globalIndex()] = 0; + trackMap[negTrack.globalIndex()] = 0; + } + + //__________________________________________________ + // index tracks that belong to CascDatas + for (auto const& casc : Cascades) { + auto bachTrack = casc.bachelor_as(); + auto v0 = casc.v0(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + trackMap[posTrack.globalIndex()] = 0; + trackMap[negTrack.globalIndex()] = 0; + trackMap[bachTrack.globalIndex()] = 0; + } + //__________________________________________________ + // index tracks that belong to KFCascDatas + for (auto const& casc : KFCascades) { + auto bachTrack = casc.bachelor_as(); + auto v0 = casc.v0(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + trackMap[posTrack.globalIndex()] = 0; + trackMap[negTrack.globalIndex()] = 0; + trackMap[bachTrack.globalIndex()] = 0; + } + //__________________________________________________ + // index tracks that belong to TraCascDatas + for (auto const& casc : TraCascades) { + auto bachTrack = casc.bachelor_as(); + auto v0 = casc.v0(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + trackMap[posTrack.globalIndex()] = 0; + trackMap[negTrack.globalIndex()] = 0; + trackMap[bachTrack.globalIndex()] = 0; + } + //__________________________________________________ + // Figure out the numbering of the new tracks table + // assume filling per order + int nTracks = 0; + for (int i = 0; i < trackMap.size(); i++) { + if (trackMap[i] >= 0) { + trackMap[i] = nTracks++; + } + } + //__________________________________________________ + // populate track references + for (auto const& v0 : V0s) { + auto const& posTrack = v0.posTrack_as(); + auto const& negTrack = v0.negTrack_as(); + v0Extras(trackMap[posTrack.globalIndex()], + trackMap[negTrack.globalIndex()]); // joinable with V0Datas + } + //__________________________________________________ + // populate track references + for (auto const& casc : Cascades) { + auto bachTrack = casc.bachelor_as(); + auto v0 = casc.v0(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + cascExtras(trackMap[posTrack.globalIndex()], + trackMap[negTrack.globalIndex()], + trackMap[bachTrack.globalIndex()]); // joinable with CascDatas + } + //__________________________________________________ + // populate track references + for (auto const& casc : KFCascades) { + auto bachTrack = casc.bachelor_as(); + auto v0 = casc.v0(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + kfcascExtras(trackMap[posTrack.globalIndex()], + trackMap[negTrack.globalIndex()], + trackMap[bachTrack.globalIndex()]); // joinable with KFCascDatas + } + //__________________________________________________ + // populate track references + for (auto const& casc : TraCascades) { + auto bachTrack = casc.bachelor_as(); + auto v0 = casc.v0(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + tracascExtras(trackMap[posTrack.globalIndex()], + trackMap[negTrack.globalIndex()], + trackMap[bachTrack.globalIndex()]); // joinable with TraCascDatas + } + //__________________________________________________ + // circle back and populate actual DauTrackExtra table + for (auto const& tr : tracksExtra) { + if (trackMap[tr.globalIndex()] >= 0) { + dauTrackExtras(tr.detectorMap(), tr.itsClusterSizes(), + tr.tpcNClsFound(), tr.tpcNClsCrossedRows()); + } + } + // done! + } + + PROCESS_SWITCH(strangederivedbuilder, processCollisions, "Produce collisions", true); + PROCESS_SWITCH(strangederivedbuilder, processTrackExtras, "Produce track extra information", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +}