Skip to content

Commit 6532150

Browse files
authored
[PWGCF] Add MC processing to derived-to-derived femto producer (#17852)
1 parent 2044255 commit 6532150

4 files changed

Lines changed: 348 additions & 25 deletions

File tree

PWGCF/Femto/Core/mcBuilder.h

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,182 @@ class McBuilder
748748
std::unordered_map<int64_t, int64_t> mMcMotherMap;
749749
std::unordered_map<int64_t, int64_t> mMcPartonicMotherMap;
750750
};
751+
752+
struct McBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup {
753+
o2::framework::Produces<o2::aod::StoredFMcCols> producedMcCollisions;
754+
o2::framework::Produces<o2::aod::StoredFMcParticles> producedMcParticles;
755+
o2::framework::Produces<o2::aod::StoredFMcMothers> producedMothers;
756+
o2::framework::Produces<o2::aod::StoredFMcPartMoths> producedPartonicMothers;
757+
o2::framework::Produces<o2::aod::StoredFMcMotherLabels> producedMcMotherLabels;
758+
759+
o2::framework::Produces<o2::aod::StoredFColLabels> producedCollisionLabels;
760+
o2::framework::Produces<o2::aod::StoredFTrackLabels> producedTrackLabels;
761+
};
762+
763+
struct ConfMcTablesDerivedToDerived : o2::framework::ConfigurableGroup {
764+
std::string prefix = std::string("McTables");
765+
o2::framework::Configurable<bool> requireMcLabel{"requireMcLabel", false, "Reject particles without an associated MC particle instead of writing a -1 label"}; // dummy configuration for now
766+
};
767+
768+
/// Copies MC information from one femto derived file into another.
769+
/// The ancestry is already resolved upstream (FMcMothers / FMcPartMoths /
770+
/// FMcMotherLabels), so this only remaps indices: each source row is copied on
771+
/// first use and cached for the rest of the dataframe.
772+
class McBuilderDerivedToDerived
773+
{
774+
public:
775+
McBuilderDerivedToDerived() = default;
776+
~McBuilderDerivedToDerived() = default;
777+
778+
template <typename T>
779+
void init(T& config)
780+
{
781+
LOG(info) << "Initialize derived-to-derived monte carlo builder...";
782+
mRequireMcLabel = config.requireMcLabel.value;
783+
LOG(info) << "Initialization done...";
784+
}
785+
786+
/// Write one FColLabels row. Call exactly once per produced collision,
787+
/// directly after collisionBuilder.processCollision().
788+
template <typename T1, typename T2, typename T3>
789+
void fillCollisionWithLabel(T1 const& col, T2 const& /*mcCols*/, T3& mcProducts)
790+
{
791+
if (!col.has_fMcCol()) {
792+
mcProducts.producedCollisionLabels(-1);
793+
return;
794+
}
795+
auto mcCol = col.template fMcCol_as<T2>();
796+
mcProducts.producedCollisionLabels(this->getOrCreateMcCollisionRow(mcCol, mcProducts));
797+
}
798+
799+
/// True if this track has no MC particle and we are configured to drop such tracks.
800+
template <typename T>
801+
bool rejectParticle(T const& particle) const
802+
{
803+
return mRequireMcLabel && !particle.has_fMcParticle();
804+
}
805+
806+
/// Write one FTrackLabels row. Call exactly once per produced track row.
807+
/// mcParticles must be joined with FMcMotherLabels so the mother indices resolve.
808+
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
809+
void fillTrackWithLabel(T1 const& track, T2 const& mcCols, T3 const& /*mcParticles*/, T4 const& mcMothers, T5 const& mcPartonicMothers, T6& mcProducts)
810+
{
811+
if (!track.has_fMcParticle()) {
812+
mcProducts.producedTrackLabels(-1);
813+
return;
814+
}
815+
auto mcParticle = track.template fMcParticle_as<T3>();
816+
mcProducts.producedTrackLabels(
817+
this->getOrCreateMcParticleRow(mcParticle, mcCols, mcMothers, mcPartonicMothers, mcProducts));
818+
}
819+
820+
template <typename T1, typename T2>
821+
void reset(T1 const& mcCols, T2 const& mcParticles)
822+
{
823+
mCollisionMap.clear();
824+
mCollisionMap.reserve(mcCols.size());
825+
mMcParticleMap.clear();
826+
mMcParticleMap.reserve(mcParticles.size());
827+
mMcMotherMap.clear();
828+
mMcMotherMap.reserve(mcParticles.size());
829+
mMcPartonicMotherMap.clear();
830+
mMcPartonicMotherMap.reserve(mcParticles.size());
831+
}
832+
833+
private:
834+
template <typename T1, typename T2>
835+
int64_t getOrCreateMcCollisionRow(T1 const& mcCol, T2& mcProducts)
836+
{
837+
const int64_t gid = mcCol.globalIndex();
838+
auto it = mCollisionMap.find(gid);
839+
if (it != mCollisionMap.end()) {
840+
return it->second;
841+
}
842+
mcProducts.producedMcCollisions(mcCol.posZ(),
843+
mcCol.mult(),
844+
mcCol.cent());
845+
const int64_t row = mcProducts.producedMcCollisions.lastIndex();
846+
mCollisionMap.emplace(gid, row);
847+
return row;
848+
}
849+
850+
/// Find-or-create the FMcParticles row. On first creation the mother and
851+
/// partonic mother rows are copied and the single matching FMcMotherLabels row
852+
/// is written, so the two tables stay in lockstep exactly as in McBuilder.
853+
template <typename T1, typename T2, typename T3, typename T4, typename T5>
854+
int64_t getOrCreateMcParticleRow(T1 const& mcParticle, T2 const& /*mcCols*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/, T5& mcProducts)
855+
{
856+
const int64_t gid = mcParticle.globalIndex();
857+
auto it = mMcParticleMap.find(gid);
858+
if (it != mMcParticleMap.end()) {
859+
return it->second;
860+
}
861+
862+
// NOTE: the MC collision of the particle, not of the reconstructed collision.
863+
// These differ for wrongly associated particles, which is the point of keeping it.
864+
int64_t mcColId = -1;
865+
if (mcParticle.has_fMcCol()) {
866+
auto mcCol = mcParticle.template fMcCol_as<T2>();
867+
mcColId = this->getOrCreateMcCollisionRow(mcCol, mcProducts);
868+
}
869+
870+
mcProducts.producedMcParticles(mcColId,
871+
mcParticle.origin(),
872+
mcParticle.pdgCode(),
873+
mcParticle.signedPt(),
874+
mcParticle.eta(),
875+
mcParticle.phi());
876+
const int64_t row = mcProducts.producedMcParticles.lastIndex();
877+
mMcParticleMap.emplace(gid, row);
878+
879+
// --- mother ---
880+
int64_t mcMotherRow = -1;
881+
if (mcParticle.has_fMcMother()) {
882+
auto mother = mcParticle.template fMcMother_as<T3>();
883+
const int64_t motherGid = mother.globalIndex();
884+
auto itM = mMcMotherMap.find(motherGid);
885+
if (itM != mMcMotherMap.end()) {
886+
mcMotherRow = itM->second;
887+
} else {
888+
mcProducts.producedMothers(mother.origin(),
889+
mother.pdgCode(),
890+
mother.signedPt(),
891+
mother.eta(),
892+
mother.phi());
893+
mcMotherRow = mcProducts.producedMothers.lastIndex();
894+
mMcMotherMap.emplace(motherGid, mcMotherRow);
895+
}
896+
}
897+
898+
// --- partonic mother ---
899+
int64_t mcPartonicMotherRow = -1;
900+
if (mcParticle.has_fMcPartMoth()) {
901+
auto partonicMother = mcParticle.template fMcPartMoth_as<T4>();
902+
const int64_t partonicGid = partonicMother.globalIndex();
903+
auto itPM = mMcPartonicMotherMap.find(partonicGid);
904+
if (itPM != mMcPartonicMotherMap.end()) {
905+
mcPartonicMotherRow = itPM->second;
906+
} else {
907+
mcProducts.producedPartonicMothers(partonicMother.pdgCode());
908+
mcPartonicMotherRow = mcProducts.producedPartonicMothers.lastIndex();
909+
mMcPartonicMotherMap.emplace(partonicGid, mcPartonicMotherRow);
910+
}
911+
}
912+
913+
// exactly one FMcMotherLabels row per FMcParticles row, written here and only here
914+
mcProducts.producedMcMotherLabels(mcMotherRow, mcPartonicMotherRow);
915+
916+
return row;
917+
}
918+
919+
bool mRequireMcLabel = false;
920+
921+
std::unordered_map<int64_t, int64_t> mCollisionMap;
922+
std::unordered_map<int64_t, int64_t> mMcParticleMap;
923+
std::unordered_map<int64_t, int64_t> mMcMotherMap;
924+
std::unordered_map<int64_t, int64_t> mMcPartonicMotherMap;
925+
};
926+
751927
} // namespace o2::analysis::femto::mcbuilder
752928

753929
#endif // PWGCF_FEMTO_CORE_MCBUILDER_H_

PWGCF/Femto/Core/trackBuilder.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ struct ConfTrackSelection : public o2::framework::ConfigurableGroup {
134134
std::string prefix = Prefix; // Unique prefix based on the template argument
135135
// configuration parameters
136136
o2::framework::Configurable<int> pdgCodeAbs{"pdgCodeAbs", 2212, "Absolute value of PDG code. Set sign of charge to -1 for antiparticle."};
137-
o2::framework::Configurable<int> chargeAbs{"chargeAbs", 1, "Absolute value of charge (e.g. 1 for most tracks, 2 for He3). Set sign of charge to -1 for antiparticle"};
137+
o2::framework::Configurable<int> chargeAbs{"chargeAbs", 1, "Absolute value of charge (e.g. 1 for most tracks, 2 for He3)"};
138138
o2::framework::Configurable<int> chargeSign{"chargeSign", 1, "Track charge sign: +1 for positive, -1 for negative, 0 for both"};
139139
// filters for kinematics
140140
o2::framework::Configurable<float> ptMin{"ptMin", 0.0f, "Minimum pT (GeV/c)"};
@@ -920,6 +920,41 @@ class TrackBuilderDerivedToDerived
920920
return idx;
921921
}
922922

923+
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12>
924+
void processTracksWithMc(T1& col, T2& /*trackTable*/, T3& partitionTrack1, T4& partitionTrack2, T5& cache,
925+
T6& newTrackTable, T7& newCollisionTable,
926+
T8& mcBuilder, T9 const& mcCols, T10 const& mcParticles, T11 const& mcMothers, T12 const& mcPartonicMothers, auto& mcProducts)
927+
{
928+
if (mLimitTrack1 > 0) {
929+
auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache);
930+
for (auto const& track : trackSlice1) {
931+
this->fillTrackWithMcLabel(track, newTrackTable, newCollisionTable, mcBuilder, mcCols, mcParticles, mcMothers, mcPartonicMothers, mcProducts);
932+
}
933+
}
934+
if (mLimitTrack2 > 0) {
935+
auto trackSlice2 = partitionTrack2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache);
936+
for (auto const& track : trackSlice2) {
937+
this->fillTrackWithMcLabel(track, newTrackTable, newCollisionTable, mcBuilder, mcCols, mcParticles, mcMothers, mcPartonicMothers, mcProducts);
938+
}
939+
}
940+
}
941+
942+
/// Same as fillTrack, but writes the matching FTrackLabels row. The indexMap
943+
/// lookup happens first, so a track selected by both partitions produces
944+
/// exactly one track row and exactly one label row.
945+
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
946+
int64_t fillTrackWithMcLabel(T1 const& track, T2& trackProducts, T3& collisionProducts,
947+
T4& mcBuilder, T5 const& mcCols, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& mcProducts)
948+
{
949+
auto index = utils::getIndex(track.globalIndex(), indexMap);
950+
if (index) {
951+
return index.value();
952+
}
953+
const int64_t idx = this->fillTrack(track, trackProducts, collisionProducts);
954+
mcBuilder.fillTrackWithLabel(track, mcCols, mcParticles, mcMothers, mcPartonicMothers, mcProducts);
955+
return idx;
956+
}
957+
923958
template <typename T1, typename T2, typename T3>
924959
int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionProducts)
925960
{

PWGCF/Femto/DataModel/FemtoTables.h

Lines changed: 88 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,11 +1295,13 @@ namespace femtomccollisions
12951295

12961296
DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcCols_001, "FMCCOL", 1, //! femto mc collisions
12971297
o2::soa::Index<>,
1298-
femtocollisions::PosZ, //! Multiplicity of the event as given by the generator in |eta|<0.8
1298+
femtocollisions::PosZ,
12991299
femtocollisions::Mult,
13001300
femtocollisions::Cent);
13011301
using FMcCols = FMcCols_001;
13021302
using FMcCol = FMcCols_001::iterator;
1303+
using StoredFMcCols = StoredFMcCols_001;
1304+
using StoredFMcCol = StoredFMcCols_001::iterator;
13031305

13041306
namespace femtomcparticle
13051307
{
@@ -1326,6 +1328,8 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcParticles_001, "FMCPARTICLE", 1, //! femto
13261328
femtobase::dynamic::Theta<femtobase::stored::Eta>);
13271329
using FMcParticles = FMcParticles_001;
13281330
using FMcParticle = FMcParticles::iterator;
1331+
using StoredFMcParticles = StoredFMcParticles_001;
1332+
using StoredFMcParticle = StoredFMcParticles::iterator;
13291333

13301334
DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcMothers_001, "FMCMOTHER", 1, //! first direct mother of the monte carlo particle
13311335
o2::soa::Index<>, // no collision index needed since the mother is retrieved from the daughter mc particle
@@ -1344,12 +1348,16 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcMothers_001, "FMCMOTHER", 1, //! first dir
13441348

13451349
using FMcMothers = FMcMothers_001;
13461350
using FMcMother = FMcMothers::iterator;
1351+
using StoredFMcMothers = StoredFMcMothers_001;
1352+
using StoredFMcMother = StoredFMcMothers::iterator;
13471353

13481354
DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcPartMoths_001, "FMCPARTMOTH", 1, //! first partonic mother of the monte carlo particle after hadronization
13491355
o2::soa::Index<>,
13501356
femtomcparticle::PdgCode);
13511357
using FMcPartMoths = FMcPartMoths_001;
13521358
using FMcPartMoth = FMcPartMoths::iterator;
1359+
using StoredFMcPartMoths = StoredFMcPartMoths_001;
1360+
using StoredFMcPartMoth = StoredFMcPartMoths::iterator;
13531361

13541362
namespace femtolabels
13551363
{
@@ -1360,30 +1368,87 @@ DECLARE_SOA_INDEX_COLUMN(FMcMother, fMcMother); //!
13601368
DECLARE_SOA_INDEX_COLUMN(FMcPartMoth, fMcPartMoth); //!
13611369
} // namespace femtolabels
13621370

1363-
DECLARE_SOA_TABLE(FColLabels, "AOD", "FCOLMCLABEL", femtolabels::FMcColId);
1364-
1365-
DECLARE_SOA_TABLE(FTrackLabels, "AOD", "FTRACKLABEL", femtolabels::FMcParticleId);
1366-
1367-
DECLARE_SOA_TABLE(FLambdaLabels, "AOD", "FLAMBDALABEL", femtolabels::FMcParticleId);
1368-
1369-
DECLARE_SOA_TABLE(FK0shortLabels, "AOD", "FK0SHORTLABEL", femtolabels::FMcParticleId);
1370-
1371-
DECLARE_SOA_TABLE(FD0Labels, "AOD", "FD0LABEL", femtolabels::FMcParticleId);
1372-
1373-
DECLARE_SOA_TABLE(FLcLabels, "AOD", "FLCLABEL", femtolabels::FMcParticleId);
1374-
1375-
DECLARE_SOA_TABLE(FSigmaLabels, "AOD", "FSIGMALABEL", femtolabels::FMcParticleId);
1376-
1377-
DECLARE_SOA_TABLE(FSigmaPlusLabels, "AOD", "FSIGMAPLUSLABEL", femtolabels::FMcParticleId);
1378-
1379-
DECLARE_SOA_TABLE(FXiLabels, "AOD", "FXILABEL", femtolabels::FMcParticleId);
1380-
1381-
DECLARE_SOA_TABLE(FOmegaLabels, "AOD", "FOMEGALABEL", femtolabels::FMcParticleId);
1371+
// Labels are staged like the tables they point into: the derived-to-derived
1372+
// producer writes the Stored* variant, so MC information survives a second
1373+
// derived-data pass.
1374+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FColLabels_001, "FCOLMCLABEL", 1, //! label from femto collision to femto mc collision
1375+
femtolabels::FMcColId);
1376+
using FColLabels = FColLabels_001;
1377+
using FColLabel = FColLabels::iterator;
1378+
using StoredFColLabels = StoredFColLabels_001;
1379+
using StoredFColLabel = StoredFColLabels::iterator;
1380+
1381+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FTrackLabels_001, "FTRACKLABEL", 1, //! label from femto track to femto mc particle
1382+
femtolabels::FMcParticleId);
1383+
using FTrackLabels = FTrackLabels_001;
1384+
using FTrackLabel = FTrackLabels::iterator;
1385+
using StoredFTrackLabels = StoredFTrackLabels_001;
1386+
using StoredFTrackLabel = StoredFTrackLabels::iterator;
1387+
1388+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaLabels_001, "FLAMBDALABEL", 1, //! label from femto lambda to femto mc particle
1389+
femtolabels::FMcParticleId);
1390+
using FLambdaLabels = FLambdaLabels_001;
1391+
using FLambdaLabel = FLambdaLabels::iterator;
1392+
using StoredFLambdaLabels = StoredFLambdaLabels_001;
1393+
using StoredFLambdaLabel = StoredFLambdaLabels::iterator;
1394+
1395+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortLabels_001, "FK0SHORTLABEL", 1, //! label from femto k0short to femto mc particle
1396+
femtolabels::FMcParticleId);
1397+
using FK0shortLabels = FK0shortLabels_001;
1398+
using FK0shortLabel = FK0shortLabels::iterator;
1399+
using StoredFK0shortLabels = StoredFK0shortLabels_001;
1400+
using StoredFK0shortLabel = StoredFK0shortLabels::iterator;
1401+
1402+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Labels_001, "FD0LABEL", 1, //! label from femto d0 to femto mc particle
1403+
femtolabels::FMcParticleId);
1404+
using FD0Labels = FD0Labels_001;
1405+
using FD0Label = FD0Labels::iterator;
1406+
using StoredFD0Labels = StoredFD0Labels_001;
1407+
using StoredFD0Label = StoredFD0Labels::iterator;
1408+
1409+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FLcLabels_001, "FLCLABEL", 1, //! label from femto lc to femto mc particle
1410+
femtolabels::FMcParticleId);
1411+
using FLcLabels = FLcLabels_001;
1412+
using FLcLabel = FLcLabels::iterator;
1413+
using StoredFLcLabels = StoredFLcLabels_001;
1414+
using StoredFLcLabel = StoredFLcLabels::iterator;
1415+
1416+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaLabels_001, "FSIGMALABEL", 1, //! label from femto sigma to femto mc particle
1417+
femtolabels::FMcParticleId);
1418+
using FSigmaLabels = FSigmaLabels_001;
1419+
using FSigmaLabel = FSigmaLabels::iterator;
1420+
using StoredFSigmaLabels = StoredFSigmaLabels_001;
1421+
using StoredFSigmaLabel = StoredFSigmaLabels::iterator;
1422+
1423+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlusLabels_001, "FSIGMAPLUSLABEL", 1, //! label from femto sigma plus to femto mc particle
1424+
femtolabels::FMcParticleId);
1425+
using FSigmaPlusLabels = FSigmaPlusLabels_001;
1426+
using FSigmaPlusLabel = FSigmaPlusLabels::iterator;
1427+
using StoredFSigmaPlusLabels = StoredFSigmaPlusLabels_001;
1428+
using StoredFSigmaPlusLabel = StoredFSigmaPlusLabels::iterator;
1429+
1430+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiLabels_001, "FXILABEL", 1, //! label from femto xi to femto mc particle
1431+
femtolabels::FMcParticleId);
1432+
using FXiLabels = FXiLabels_001;
1433+
using FXiLabel = FXiLabels::iterator;
1434+
using StoredFXiLabels = StoredFXiLabels_001;
1435+
using StoredFXiLabel = StoredFXiLabels::iterator;
1436+
1437+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaLabels_001, "FOMEGALABEL", 1, //! label from femto omega to femto mc particle
1438+
femtolabels::FMcParticleId);
1439+
using FOmegaLabels = FOmegaLabels_001;
1440+
using FOmegaLabel = FOmegaLabels::iterator;
1441+
using StoredFOmegaLabels = StoredFOmegaLabels_001;
1442+
using StoredFOmegaLabel = StoredFOmegaLabels::iterator;
13821443

13831444
// for mc only processing, we also need Labels pointing from mc particles to mothers and partonic mothers
1384-
DECLARE_SOA_TABLE(FMcMotherLabels, "AOD", "FMCMOTHERLABEL",
1385-
femtolabels::FMcMotherId,
1386-
femtolabels::FMcPartMothId);
1445+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcMotherLabels_001, "FMCMOTHERLABEL", 1, //! labels from femto mc particle to its mother and partonic mother
1446+
femtolabels::FMcMotherId,
1447+
femtolabels::FMcPartMothId);
1448+
using FMcMotherLabels = FMcMotherLabels_001;
1449+
using FMcMotherLabel = FMcMotherLabels::iterator;
1450+
using StoredFMcMotherLabels = StoredFMcMotherLabels_001;
1451+
using StoredFMcMotherLabel = StoredFMcMotherLabels::iterator;
13871452

13881453
} // namespace o2::aod
13891454
#endif // PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_

0 commit comments

Comments
 (0)