Skip to content

Commit bf1f2cf

Browse files
committed
[PWGJE] Enhance GammaJetAnalysisTree with additional MC information
1 parent 0ce0e1b commit bf1f2cf

2 files changed

Lines changed: 133 additions & 26 deletions

File tree

PWGJE/DataModel/GammaJetAnalysisTree.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,16 @@ namespace gjgammamcinfo
106106
{
107107
DECLARE_SOA_COLUMN(Origin, origin, uint16_t);
108108
DECLARE_SOA_COLUMN(LeadingEnergyFraction, leadingEnergyFraction, float); // fraction of energy from the leading MC particle
109+
// further information about the particle that produced this cluster, one could also linnk to mcgen particle table
110+
// but for now this is easier as the MCgen table is filtered and I do not want to deal with ensuring the filered table exists and
111+
// does not filter out a mother
112+
DECLARE_SOA_COLUMN(Eta, eta, float);
113+
DECLARE_SOA_COLUMN(Phi, phi, float);
114+
DECLARE_SOA_COLUMN(Energy, energy, float);
115+
DECLARE_SOA_COLUMN(Pt, pt, float);
116+
DECLARE_SOA_COLUMN(MCIso, mcIso, float);
109117
} // namespace gjgammamcinfo
110-
DECLARE_SOA_TABLE(GjGammaMCInfos, "AOD", "GJGAMMAMCINFO", gjgamma::GjEventId, gjgammamcinfo::Origin, gjgammamcinfo::LeadingEnergyFraction)
118+
DECLARE_SOA_TABLE(GjGammaMCInfos, "AOD", "GJGAMMAMCINFO", gjgamma::GjEventId, gjgammamcinfo::Origin, gjgammamcinfo::LeadingEnergyFraction, gjgammamcinfo::Eta, gjgammamcinfo::Phi, gjgammamcinfo::Energy, gjgammamcinfo::Pt, gjgammamcinfo::MCIso)
111119

112120
// Generator level particle information from the MC collision that was matched to the reconstructed collision
113121
namespace gjmcparticle
@@ -178,6 +186,17 @@ DECLARE_SOA_COLUMN(PerpConeRho, perpconerho, float);
178186
} // namespace gjmcjet
179187
DECLARE_SOA_TABLE(GjMCJets, "AOD", "GJMCJET", gjgamma::GjEventId, gjmcjet::Pt, gjmcjet::Eta, gjmcjet::Phi, gjmcjet::Radius, gjmcjet::Energy, gjmcjet::Mass, gjmcjet::Area, gjmcjet::PerpConeRho)
180188

189+
// MC gen level substructure
190+
namespace gjmcjetsubstructure
191+
{
192+
DECLARE_SOA_COLUMN(EnergyMother, energyMother, std::vector<float>); //! energy of mother subjet at each splitting
193+
DECLARE_SOA_COLUMN(PtLeading, ptLeading, std::vector<float>); //! pt of leading subjet at each splitting
194+
DECLARE_SOA_COLUMN(PtSubLeading, ptSubLeading, std::vector<float>); //! pt of subleading subjet at each splitting
195+
DECLARE_SOA_COLUMN(Theta, theta, std::vector<float>); //! opening angle theta at each splitting
196+
} // namespace gjmcjetsubstructure
197+
DECLARE_SOA_TABLE(GjMCJetSubstructures, "AOD", "GJMCJETSUBSTR", gjgamma::GjEventId, gjmcjetsubstructure::EnergyMother, gjmcjetsubstructure::PtLeading, gjmcjetsubstructure::PtSubLeading, gjmcjetsubstructure::Theta)
198+
199+
181200
} // namespace o2::aod
182201

183202
#endif // PWGJE_DATAMODEL_GAMMAJETANALYSISTREE_H_

PWGJE/Tasks/gammaJetTreeProducer.cxx

Lines changed: 113 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "Common/Core/RecoDecay.h"
2626

2727
#include <CommonConstants/MathConstants.h>
28+
#include <CommonConstants/PhysicsConstants.h>
2829
#include <Framework/ASoA.h>
2930
#include <Framework/AnalysisDataModel.h>
3031
#include <Framework/AnalysisHelpers.h>
@@ -69,6 +70,7 @@ using namespace o2;
6970
using namespace o2::aod;
7071
using namespace o2::framework;
7172
using namespace o2::framework::expressions;
73+
using namespace o2::constants::physics;
7274
using emcClusters = o2::soa::Join<o2::aod::JClusters, o2::aod::JClusterTracks>;
7375
using emcMCClusters = o2::soa::Join<o2::aod::JMcClusterLbs, o2::aod::JClusters, o2::aod::JClusterTracks>;
7476

@@ -85,6 +87,7 @@ struct GammaJetTreeProducer {
8587
Produces<aod::GjChJetMCInfos> chJetMCInfosTable; // detector level charged jets MC information
8688
Produces<aod::GjMCJets> mcJetsTable; // gen level jets
8789
Produces<aod::GjJetSubstructures> jetSubstructuresTable; // jet substructure observables
90+
Produces<aod::GjMCJetSubstructures> mcJetSubstructuresTable; // MC gen-level jet substructure observables
8891

8992
HistogramRegistry mHistograms{"GammaJetTreeProducerHisto"};
9093

@@ -95,7 +98,7 @@ struct GammaJetTreeProducer {
9598
// ---------------
9699

97100
// event cuts
98-
Configurable<double> mVertexCut{"vertexCut", 10.0, "apply z-vertex cut with value in cm"};
101+
Configurable<double> vertexCut{"vertexCut", 10.0, "apply z-vertex cut with value in cm"};
99102
Configurable<std::string> eventSelections{"eventSelections", "sel8", "choose event selection"};
100103
Configurable<std::string> triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"};
101104
Configurable<std::string> trackSelections{"trackSelections", "globalTracks", "set track selections"};
@@ -139,6 +142,9 @@ struct GammaJetTreeProducer {
139142
std::vector<float> ptSubLeadingVec;
140143
std::vector<float> thetaVec;
141144

145+
// other constants
146+
const float kInvalidValue = -99.0f;
147+
142148
// keeping track of the current collision index
143149
// to determine if we need to rebuild the kdTree
144150
// this makes loadorder more robust
@@ -397,7 +403,7 @@ struct GammaJetTreeProducer {
397403
{
398404
mHistograms.fill(HIST("eventQA"), 0);
399405

400-
if (std::abs(collision.posZ()) > mVertexCut) {
406+
if (std::abs(collision.posZ()) > vertexCut) {
401407
return false;
402408
}
403409
mHistograms.fill(HIST("eventQA"), 1);
@@ -566,8 +572,7 @@ struct GammaJetTreeProducer {
566572
{
567573
T current = particle;
568574
int depth = 0;
569-
bool continueTracing = true;
570-
while (continueTracing) {
575+
while (depth < kMaxRecursionDepth) {
571576
LOG(info) << "Level " << depth
572577
<< " | PDG: " << current.pdgCode()
573578
<< " | E: " << current.energy()
@@ -719,7 +724,7 @@ struct GammaJetTreeProducer {
719724
// check if it has mothers that are etas
720725
const auto& mothers = particle.template mothers_as<aod::JMcParticles>();
721726
for (const auto& mother : mothers) {
722-
if (mother.pdgCode() == 221) {
727+
if (mother.pdgCode() == Pdg::kEta) {
723728
return true;
724729
}
725730
}
@@ -736,7 +741,7 @@ struct GammaJetTreeProducer {
736741
// check if you find a pi0 mother or a eta mother
737742
const auto& mothers = particle.template mothers_as<aod::JMcParticles>();
738743
for (const auto& mother : mothers) {
739-
if (mother.pdgCode() == PDG_t::kPi0 || mother.pdgCode() == 221) {
744+
if (mother.pdgCode() == PDG_t::kPi0 || mother.pdgCode() == Pdg::kEta) {
740745
return false;
741746
}
742747
}
@@ -927,15 +932,16 @@ struct GammaJetTreeProducer {
927932
/// \brief Gets the origin bitmap for a cluster
928933
/// \param cluster The cluster to check
929934
/// \param mcParticles The MC particles collection
930-
/// \return A bitmap indicating the cluster's origin
935+
/// \return A a pari containing the bitmap of the origin of the particle, as well as the MC index of the associated MC gen particle
931936
template <typename T, typename U>
932-
uint16_t getClusterOrigin(const T& cluster, U const& mcParticles)
937+
std::pair<uint16_t, int> getClusterOrigin(const T& cluster, U const& mcParticles)
933938
{
934939
uint16_t origin = 0;
940+
int returnMCIndex = -1;
935941
auto inducerIDs = cluster.mcParticlesIds();
936942
if (inducerIDs.size() == 0) {
937943
SETBIT(origin, static_cast<uint16_t>(gjanalysis::ClusterOrigin::kUnknown));
938-
return origin;
944+
return std::make_pair(origin, returnMCIndex);
939945
}
940946

941947
// loop over all inducers and print their energy
@@ -960,7 +966,7 @@ struct GammaJetTreeProducer {
960966
LOG(debug) << "Leading particle primary ID: " << leadingParticlePrimaryID;
961967
if (leadingParticlePrimaryID == -1) {
962968
SETBIT(origin, static_cast<uint16_t>(gjanalysis::ClusterOrigin::kUnknown));
963-
return origin;
969+
return std::make_pair(origin, returnMCIndex);
964970
}
965971
const auto& leadingParticlePrimary = mcParticles.iteratorAt(leadingParticlePrimaryID);
966972
LOG(debug) << "Leading particle primary PDG: " << leadingParticlePrimary.pdgCode();
@@ -993,17 +999,25 @@ struct GammaJetTreeProducer {
993999
LOG(debug) << "Leading particle primary is a decay photon from eta";
9941000
}
9951001

1002+
// for all the cases so far, we can use as MC index the index of the leading particle primary
1003+
returnMCIndex = leadingParticlePrimaryID;
1004+
9961005
// Do checks if a cluster is a merged pi0 decay
9971006
// we classify a cluster as merged pi0 if the leading and subleading contribution to a cluster come from two photons that are part of a pi0 decay
9981007
if (isMergedFromPDGDecay(cluster, mcParticles, PDG_t::kPi0)) {
9991008
SETBIT(origin, static_cast<uint16_t>(gjanalysis::ClusterOrigin::kMergedPi0));
10001009
LOG(debug) << "Cluster is a merged pi0";
1010+
// if this is a merged pion decay, it should return the MC index of the pi0 mother (it is ensured that this is properly returned otherwise we would not be in this if statement)
1011+
returnMCIndex = getIndexMotherChain(mcParticles.iteratorAt(inducerIDs[0]), mcParticles, PDG_t::kPi0);
1012+
10011013
}
1002-
if (isMergedFromPDGDecay(cluster, mcParticles, 221)) {
1014+
if (isMergedFromPDGDecay(cluster, mcParticles, Pdg::kEta)) {
10031015
SETBIT(origin, static_cast<uint16_t>(gjanalysis::ClusterOrigin::kMergedEta));
10041016
LOG(debug) << "Cluster is a merged eta";
1017+
returnMCIndex = getIndexMotherChain(mcParticles.iteratorAt(inducerIDs[0]), mcParticles, Pdg::kEta);
10051018
}
10061019

1020+
10071021
// check if photon conversion
10081022
// check that leading contribution is an electron or positron
10091023
LOG(debug) << "Checking if cluster is a converted photon";
@@ -1023,6 +1037,8 @@ struct GammaJetTreeProducer {
10231037
if ((daughters.iteratorAt(0).pdgCode() == PDG_t::kElectron && daughters.iteratorAt(1).pdgCode() == PDG_t::kPositron) || (daughters.iteratorAt(0).pdgCode() == PDG_t::kPositron && daughters.iteratorAt(1).pdgCode() == PDG_t::kElectron)) {
10241038
SETBIT(origin, static_cast<uint16_t>(gjanalysis::ClusterOrigin::kConvertedPhoton));
10251039
LOG(debug) << "Cluster is a converted photon";
1040+
// if we found a converted photon, it should use for the the MC index the one of the photon
1041+
returnMCIndex = mother.globalIndex();
10261042
}
10271043
}
10281044
}
@@ -1031,7 +1047,7 @@ struct GammaJetTreeProducer {
10311047
}
10321048
// display bit origin
10331049
LOG(debug) << "Origin bits: " << std::bitset<16>(origin);
1034-
return origin;
1050+
return std::make_pair(origin, returnMCIndex);
10351051
}
10361052

10371053
// ---------------------
@@ -1046,7 +1062,6 @@ struct GammaJetTreeProducer {
10461062
mcCollisionsMultiRecCollisions.clear();
10471063
mcJetIndexMapping.clear();
10481064
}
1049-
PROCESS_SWITCH(GammaJetTreeProducer, processClearMaps, "process function that clears all the maps in each dataframe", true);
10501065

10511066
// WARNING: This function always has to run second in the processing chain
10521067
/// \brief Processes MC event matching QA
@@ -1063,7 +1078,7 @@ struct GammaJetTreeProducer {
10631078
int nRecCollisions = 0;
10641079
mHistograms.fill(HIST("mcCollisionsWithRecCollisions"), 0);
10651080
for (auto const& collision : collisions) {
1066-
if (std::abs(collision.posZ()) > mVertexCut) {
1081+
if (std::abs(collision.posZ()) > vertexCut) {
10671082
continue;
10681083
}
10691084
if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, true, true, rctLabel)) {
@@ -1099,7 +1114,6 @@ struct GammaJetTreeProducer {
10991114
mHistograms.fill(HIST("numberRecCollisionsVsPhotonPt"), nRecCollisions, particle.pt());
11001115
}
11011116
}
1102-
PROCESS_SWITCH(GammaJetTreeProducer, processMCCollisionsMatching, "Process MC event matching QA", false);
11031117

11041118
/// \brief Processes data events in data fill event table
11051119
/// \param collision The collision to process
@@ -1113,7 +1127,6 @@ struct GammaJetTreeProducer {
11131127
eventsTable(collision.multFT0M(), collision.centFT0M(), collision.rho(), collision.eventSel(), collision.trackOccupancyInTimeRange(), collision.alias_raw());
11141128
collisionMapping[collision.globalIndex()] = eventsTable.lastIndex();
11151129
}
1116-
PROCESS_SWITCH(GammaJetTreeProducer, processEventData, "Process event data", true);
11171130

11181131
using MCCol = o2::soa::Join<aod::JMcCollisions, aod::BkgChargedMcRhos>;
11191132

@@ -1154,7 +1167,6 @@ struct GammaJetTreeProducer {
11541167
}
11551168
mcEventsTable(eventsTable.lastIndex(), mcCollision.weight(), mcCollision.rho(), isMultipleAssigned);
11561169
}
1157-
PROCESS_SWITCH(GammaJetTreeProducer, processEventMC, "Process MC event MC", false);
11581170

11591171
// ---------------------
11601172
// Processing functions can be safely added below this line
@@ -1224,8 +1236,6 @@ struct GammaJetTreeProducer {
12241236
mHistograms.fill(HIST("trackPt"), track.pt());
12251237
}
12261238
}
1227-
PROCESS_SWITCH(GammaJetTreeProducer, processClusters, "Process EMCal clusters", true);
1228-
12291239
/// \brief Processes MC cluster information (rec level)
12301240
/// \param collision The collision to process
12311241
/// \param mcClusters The MC clusters to process
@@ -1240,7 +1250,7 @@ struct GammaJetTreeProducer {
12401250
// TODO: add weights
12411251
for (const auto& mcCluster : mcClusters) {
12421252
mHistograms.fill(HIST("clusterMC_E_All"), mcCluster.energy());
1243-
uint16_t origin = getClusterOrigin(mcCluster, mcParticles);
1253+
auto [origin, mcIndex] = getClusterOrigin(mcCluster, mcParticles);
12441254
float leadingEnergyFraction = mcCluster.amplitudeA()[0] / mcCluster.energy();
12451255
// Fill MC origin QA histograms
12461256
if (origin & (1 << static_cast<uint16_t>(gjanalysis::ClusterOrigin::kPhoton))) {
@@ -1283,11 +1293,26 @@ struct GammaJetTreeProducer {
12831293
mHistograms.fill(HIST("clusterMC_E_ConvertedPhoton"), mcCluster.energy());
12841294
mHistograms.fill(HIST("clusterMC_m02_ConvertedPhoton"), mcCluster.m02());
12851295
}
1296+
1297+
// determine properties fo particle that produced the given cluster
1298+
float mcIsolation = -1;
1299+
float mcEnergy = kInvalidValue;
1300+
float mcPt = kInvalidValue;
1301+
float mcEta = kInvalidValue;
1302+
float mcPhi = kInvalidValue;
1303+
if (mcIndex != -1) {
1304+
const auto& mcParticle = mcParticles.iteratorAt(mcIndex);
1305+
mcIsolation = ch_iso_in_cone(mcParticle, isoR, true);
1306+
mcEnergy = mcParticle.energy();
1307+
mcPt = mcParticle.pt();
1308+
mcEta = mcParticle.eta();
1309+
mcPhi = mcParticle.phi();
1310+
}
1311+
12861312
// fill table
1287-
gammaMCInfosTable(storedColIndex, origin, leadingEnergyFraction);
1313+
gammaMCInfosTable(storedColIndex, origin, leadingEnergyFraction, mcEta, mcPhi, mcEnergy, mcPt, mcIsolation);
12881314
}
12891315
}
1290-
PROCESS_SWITCH(GammaJetTreeProducer, processClustersMCInfo, "Process MC cluster information", false);
12911316

12921317
/// \brief Fills the charged jet table with jet information and calculates jet properties
12931318
/// \param storedColIndex The stored collision index
@@ -1369,6 +1394,58 @@ struct GammaJetTreeProducer {
13691394
jetSubstructuresTable(storedColIndex, energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec);
13701395
}
13711396

1397+
/// \brief Fills the MC gen-level substructure table for each splitting in the jet
1398+
/// \param storedColIndex The stored collision index
1399+
/// \param jet The MC particle-level jet to process
1400+
/// \param mcparticles The MC particles collection
1401+
template <typename T, typename U>
1402+
void fillMCSubstructureTable(int32_t storedColIndex, T const& jet, U const& /*mcparticles*/)
1403+
{
1404+
// adjust settings according to the jet radius
1405+
jetReclusterer.jetR = jet.r() / 100.0;
1406+
// clear vectors
1407+
energyMotherVec.clear();
1408+
ptLeadingVec.clear();
1409+
ptSubLeadingVec.clear();
1410+
thetaVec.clear();
1411+
jetReclustered.clear();
1412+
jetConstituents.clear();
1413+
1414+
if (jet.pt() < jetPtMin) {
1415+
return;
1416+
}
1417+
for (const auto& jetConstituent : jet.template tracks_as<U>()) {
1418+
fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex());
1419+
}
1420+
1421+
fastjet::ClusterSequenceArea clusterSeq(jetReclusterer.findJets(jetConstituents, jetReclustered));
1422+
jetReclustered = sorted_by_pt(jetReclustered);
1423+
1424+
if (jetReclustered.size() == 0) {
1425+
return;
1426+
}
1427+
1428+
fastjet::PseudoJet daughterSubJet = jetReclustered[0];
1429+
fastjet::PseudoJet parentSubJet1;
1430+
fastjet::PseudoJet parentSubJet2;
1431+
1432+
while (daughterSubJet.has_parents(parentSubJet1, parentSubJet2)) {
1433+
if (parentSubJet1.perp() < parentSubJet2.perp()) {
1434+
std::swap(parentSubJet1, parentSubJet2);
1435+
}
1436+
1437+
energyMotherVec.push_back(daughterSubJet.e());
1438+
ptLeadingVec.push_back(parentSubJet1.pt());
1439+
ptSubLeadingVec.push_back(parentSubJet2.pt());
1440+
thetaVec.push_back(parentSubJet1.delta_R(parentSubJet2));
1441+
1442+
// Continue with harder parent
1443+
daughterSubJet = parentSubJet1;
1444+
}
1445+
1446+
mcJetSubstructuresTable(storedColIndex, energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec);
1447+
}
1448+
13721449
Filter jetCuts = aod::jet::pt > jetPtMin;
13731450
/// \brief Processes charged jets and fills jet table
13741451
/// \param collision The collision to process
@@ -1395,7 +1472,6 @@ struct GammaJetTreeProducer {
13951472
}
13961473
}
13971474
}
1398-
PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsData, "Process charged jets", true);
13991475

14001476
Preslice<aod::JetParticles> ParticlesPerMCCollisions = aod::jmcparticle::mcCollisionId;
14011477
/// \brief Processes MC particles and fills MC particle table
@@ -1482,7 +1558,6 @@ struct GammaJetTreeProducer {
14821558
}
14831559
}
14841560
}
1485-
PROCESS_SWITCH(GammaJetTreeProducer, processMCParticles, "Process MC particles", false);
14861561

14871562
// NOTE: The KD tree is now built lazily in each function that needs it, so execution order is no longer critical
14881563
Preslice<aod::ChargedMCParticleLevelJets> PJetsPerMCCollisions = aod::jmcparticle::mcCollisionId;
@@ -1515,9 +1590,12 @@ struct GammaJetTreeProducer {
15151590
mcJetIndexMapping[pjet.globalIndex()] = localIndex;
15161591
localIndex++;
15171592
mHistograms.fill(HIST("mcpJetPt"), pjet.pt());
1593+
1594+
if (calculateJetSubstructure) {
1595+
fillMCSubstructureTable(storedColIndex, pjet, mcgenparticles);
1596+
}
15181597
}
15191598
}
1520-
PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsMCP, "Process MC particle level jets", false);
15211599

15221600
// NOTE: It is important that this function runs after the processChargedJetsMCP function (where the mc jet index mapping is built)
15231601
using JetMCPTable = soa::Filtered<soa::Join<aod::ChargedMCParticleLevelJets, aod::ChargedMCParticleLevelJetConstituents, aod::ChargedMCParticleLevelJetsMatchedToChargedMCDetectorLevelJets>>;
@@ -1564,6 +1642,16 @@ struct GammaJetTreeProducer {
15641642
chJetMCInfosTable(storedColIndex, iLocalIndexGeo, iLocalIndexPt);
15651643
}
15661644
}
1645+
// definition of all process switches, ordering is important!
1646+
PROCESS_SWITCH(GammaJetTreeProducer, processClearMaps, "process function that clears all the maps in each dataframe", true); // always run first
1647+
PROCESS_SWITCH(GammaJetTreeProducer, processMCCollisionsMatching, "Process MC event matching QA", false);
1648+
PROCESS_SWITCH(GammaJetTreeProducer, processEventData, "Process event data", true);
1649+
PROCESS_SWITCH(GammaJetTreeProducer, processEventMC, "Process MC event MC", false);
1650+
PROCESS_SWITCH(GammaJetTreeProducer, processClusters, "Process EMCal clusters", true);
1651+
PROCESS_SWITCH(GammaJetTreeProducer, processMCParticles, "Process MC particles", false); // has to run before processClustersMCInfo
1652+
PROCESS_SWITCH(GammaJetTreeProducer, processClustersMCInfo, "Process MC cluster information", false);
1653+
PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsData, "Process charged jets", true);
1654+
PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsMCP, "Process MC particle level jets", false);
15671655
PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsMCD, "Process MC detector level jets", false);
15681656
};
15691657

0 commit comments

Comments
 (0)