Skip to content

Commit 62b1ced

Browse files
SteffimroStefanie Mrozinski
andauthored
[PWGEM] Add new bremsstrahlungstemplate histograms + centrality pool in mixer (#18709)
Co-authored-by: Stefanie Mrozinski <stefanie.mrozinski@stud.uni-frankfurt.de>
1 parent 9f44006 commit 62b1ced

4 files changed

Lines changed: 447 additions & 12 deletions

File tree

‎PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx‎

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
#include <Framework/AnalysisDataModel.h>
2626
#include <Framework/AnalysisHelpers.h>
2727
#include <Framework/AnalysisTask.h>
28-
#include <Framework/Concepts.h>
2928
#include <Framework/Configurable.h>
3029
#include <Framework/HistogramRegistry.h>
3130
#include <Framework/HistogramSpec.h>
3231
#include <Framework/InitContext.h>
32+
#include <Framework/Logger.h>
3333
#include <Framework/runDataProcessing.h>
3434

3535
#include <TH1.h>
@@ -48,6 +48,7 @@
4848
#include <map>
4949
#include <string_view>
5050
#include <unordered_map>
51+
#include <unordered_set>
5152
#include <vector>
5253

5354
using namespace o2;
@@ -97,6 +98,10 @@ struct AssociateMCInfoPhoton {
9798
Configurable<bool> useIsSelected{"useIsSelected", true, "flag to enable the usage of isSelected from our EM event selection. Disabling this will increase the derived data size!"};
9899
Configurable<bool> useIsEOI{"useIsEOI", true, "flag to enable the usage of the EOI table"};
99100

101+
Configurable<bool> fillBremsChain{"fillBremsChain", false, "MC truth histograms of the bremsstrahlung chain: photon conversion, radiation by a leg, conversion of the radiated photon (BremsChain/)"};
102+
Configurable<float> bremsChainMaxR{"bremsChainMaxR", 90.f, "max conversion radius (cm) for the bremsstrahlung chain histograms"};
103+
Configurable<float> bremsChainMinX{"bremsChainMinX", 0.05f, "min energy fraction E(radiated photon) / E(parent photon) for the bremsstrahlung chain histograms"};
104+
100105
HistogramRegistry registry{"EMMCEvent"};
101106

102107
void init(o2::framework::InitContext&)
@@ -133,6 +138,19 @@ struct AssociateMCInfoPhoton {
133138
registry.add<TH2>(Form("Generated/h2PtY_Accepted_%s", ParticleNames[i].data()), Form("Generated %s", ParticleNames[i].data()), kTH2F, {axisPt, axisRapidity}, true);
134139
}
135140

141+
if (fillBremsChain) {
142+
const AxisSpec axR{45, 0.f, 90.f, "#it{R}_{conv}(A) (cm)"};
143+
const AxisSpec axPhi{360, 0.f, 360.f, "#varphi_{conv}(A) (deg)"};
144+
const AxisSpec axPtA{{0.1, 0.2, 0.3, 0.4, 0.6, 0.8, 1.0, 1.5, 2.0, 10.0}, "#it{p}_{T}(A) (GeV/#it{c})"};
145+
const AxisSpec axX{{0.05, 0.1, 0.3, 0.5, 1.0}, "#it{E}(B) / #it{E}(A)"};
146+
registry.add("BremsChain/hGenPhiPt", "generated primary photons, |#eta| < cfg_max_eta_gamma;#varphi of the momentum (deg);#it{p}_{T} (GeV/#it{c})", kTH2F, {{360, 0.f, 360.f}, axPtA}, false);
147+
registry.add("BremsChain/hConvA", "true conversions of primary photons", kTH3F, {axR, axPhi, axPtA}, false);
148+
registry.add("BremsChain/hConvARec", "true conversions of primary photons, photon reconstructed", kTH3F, {axR, axPhi, axPtA}, false);
149+
registry.add("BremsChain/hChain", "photons radiated by a leg of A, cumulative stages", kTHnSparseF, {axR, axPhi, axPtA, axX, {4, -0.5f, 3.5f, "stage: 0 radiated (in the MC stack), 1 B converts, 2 B reconstructed, 3 B and A reconstructed"}}, false);
150+
registry.add("BremsChain/hGeometry", "radiated photons that convert: where, relative to A", kTHnSparseF, {{18, 0.f, 90.f, "#it{R}_{conv}(A) (cm)"}, {40, -5.f, 95.f, "#it{R}_{conv}(B) #minus #it{R}_{conv}(A) (cm)"}, {40, -20.f, 20.f, "#varphi_{conv}(B) #minus #varphi_{conv}(A) (deg)"}, axX, {3, 0.5f, 3.5f, "stage: 1 B converts, 2 B reconstructed, 3 B and A reconstructed"}}, false);
151+
registry.add("BremsChain/hEmission", "radiated photons with #it{E}(B) / #it{E}(A) > 0.1: emission point;#it{R}_{conv}(A) (cm);#it{R}_{emission} #minus #it{R}_{conv}(A) (cm)", kTH2F, {axR, {50, 0.f, 100.f}}, false);
152+
}
153+
136154
// reserve space for generated vectors if that process enabled
137155
auto hBinFinder = registry.get<TH2>(HIST("Generated/h2PtY_Pi0"));
138156
LOGF(info, "Binned generated processing enabled. Initialising with %i elements...", hBinFinder->GetNcells());
@@ -230,6 +248,108 @@ struct AssociateMCInfoPhoton {
230248
} // end of mother chain loop
231249
}
232250

251+
// conversion point of a photon: production vertex of its e+ e- daughters; false if the photon did not convert into e+ e- (in the MC stack)
252+
template <typename TMCParticle, typename TMCParticles>
253+
bool conversionPoint(TMCParticle const& photon, TMCParticles const& mcParticles, float& vx, float& vy, int64_t& idEle, int64_t& idPos)
254+
{
255+
idEle = -1;
256+
idPos = -1;
257+
if (!photon.has_daughters()) {
258+
return false;
259+
}
260+
for (int id = photon.daughtersIds()[0]; id <= photon.daughtersIds()[1]; ++id) {
261+
if (id < 0 || id >= mcParticles.size()) {
262+
continue;
263+
}
264+
const auto d = mcParticles.rawIteratorAt(id);
265+
if (d.pdgCode() == PDG_t::kElectron && idEle < 0) {
266+
idEle = id;
267+
vx = d.vx();
268+
vy = d.vy();
269+
} else if (d.pdgCode() == PDG_t::kPositron && idPos < 0) {
270+
idPos = id;
271+
}
272+
}
273+
return idEle >= 0 && idPos >= 0;
274+
}
275+
276+
// MC truth of the bremsstrahlung chain for one MC collision (see the histogram definitions in init)
277+
template <typename TGroupedMCParticles, typename TMCParticles>
278+
void fillBremsChainTruth(TGroupedMCParticles const& groupedMcParticles, TMCParticles const& mcParticles, std::unordered_set<int64_t> const& recoPhotons)
279+
{
280+
static constexpr float RadToDeg = 57.29578f;
281+
static constexpr float FullTurn = 360.f, HalfTurn = 180.f;
282+
auto phiDeg = [](float y, float x) {
283+
const float phi = std::atan2(y, x) * RadToDeg;
284+
return phi < 0.f ? phi + FullTurn : phi;
285+
};
286+
for (const auto& photon : groupedMcParticles) {
287+
if (photon.pdgCode() != PDG_t::kGamma || !(photon.isPhysicalPrimary() || photon.producedByGenerator()) || std::fabs(photon.eta()) > cfg_max_eta_photon) {
288+
continue;
289+
}
290+
registry.fill(HIST("BremsChain/hGenPhiPt"), phiDeg(photon.py(), photon.px()), photon.pt());
291+
float vxA = 0.f, vyA = 0.f;
292+
int64_t idEle = -1, idPos = -1;
293+
if (!conversionPoint(photon, mcParticles, vxA, vyA, idEle, idPos)) {
294+
continue;
295+
}
296+
const float rA = std::hypot(vxA, vyA);
297+
if (rA > bremsChainMaxR) {
298+
continue;
299+
}
300+
const float phiA = phiDeg(vyA, vxA);
301+
const bool recA = recoPhotons.contains(photon.globalIndex());
302+
registry.fill(HIST("BremsChain/hConvA"), rA, phiA, photon.pt());
303+
if (recA) {
304+
registry.fill(HIST("BremsChain/hConvARec"), rA, phiA, photon.pt());
305+
}
306+
for (const auto& idLeg : {idEle, idPos}) {
307+
const auto leg = mcParticles.rawIteratorAt(idLeg);
308+
if (!leg.has_daughters()) {
309+
continue;
310+
}
311+
for (int id = leg.daughtersIds()[0]; id <= leg.daughtersIds()[1]; ++id) {
312+
if (id < 0 || id >= mcParticles.size()) {
313+
continue;
314+
}
315+
const auto radiated = mcParticles.rawIteratorAt(id);
316+
if (radiated.pdgCode() != PDG_t::kGamma) {
317+
continue;
318+
}
319+
const float x = std::min(radiated.e() / std::max(photon.e(), 1.e-6f), 0.9999f);
320+
if (x < bremsChainMinX) {
321+
continue;
322+
}
323+
registry.fill(HIST("BremsChain/hChain"), rA, phiA, photon.pt(), x, 0.f);
324+
if (x > 0.1f) { // o2-linter: disable=magic-number (energy fraction of the calculation)
325+
registry.fill(HIST("BremsChain/hEmission"), rA, std::hypot(radiated.vx(), radiated.vy()) - rA);
326+
}
327+
float vxB = 0.f, vyB = 0.f;
328+
int64_t idEleB = -1, idPosB = -1;
329+
if (!conversionPoint(radiated, mcParticles, vxB, vyB, idEleB, idPosB)) {
330+
continue;
331+
}
332+
const float rB = std::hypot(vxB, vyB);
333+
if (rB > bremsChainMaxR) {
334+
continue;
335+
}
336+
float dPhi = phiDeg(vyB, vxB) - phiA;
337+
if (dPhi > HalfTurn) {
338+
dPhi -= FullTurn;
339+
} else if (dPhi < -HalfTurn) {
340+
dPhi += FullTurn;
341+
}
342+
const bool recB = recoPhotons.contains(radiated.globalIndex());
343+
const int lastStage = recB ? (recA ? 3 : 2) : 1;
344+
for (int stage = 1; stage <= lastStage; ++stage) {
345+
registry.fill(HIST("BremsChain/hChain"), rA, phiA, photon.pt(), x, static_cast<float>(stage));
346+
registry.fill(HIST("BremsChain/hGeometry"), rA, std::clamp(rB - rA, -4.99f, 94.99f), std::clamp(dPhi, -19.99f, 19.99f), x, static_cast<float>(stage));
347+
}
348+
}
349+
}
350+
}
351+
}
352+
233353
template <uint8_t system, typename TTracks, typename TFwdTracks, typename TPCMs, typename TPCMLegs, typename TPHOSs, typename TEMCs, typename TEMPrimaryElectrons>
234354
void skimmingMC(MyCollisionsMC const& collisions, aod::BCs const&, aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles, TTracks const& o2tracks, TFwdTracks const&, TPCMs const& v0photons, TPCMLegs const& legs, TPHOSs const&, TEMCs const& emcclusters, TEMPrimaryElectrons const& emprimaryelectrons)
235355
{
@@ -258,6 +378,33 @@ struct AssociateMCInfoPhoton {
258378
// mc collision iter
259379
auto mcCollisionIter = mcCollisions.begin();
260380

381+
// MC photons reconstructed as a stored V0 photon (both legs point to the same photon), for the bremsstrahlung chain histograms
382+
std::unordered_set<int64_t> recoPhotons;
383+
if constexpr (static_cast<bool>(system & kPCM) && !std::is_same_v<TPCMLegs, std::nullptr_t>) {
384+
if (fillBremsChain) {
385+
auto legIter = legs.begin();
386+
auto trackIter = o2tracks.begin();
387+
for (const auto& v0 : v0photons) {
388+
std::array<int64_t, 2> mother{-1, -2};
389+
int i = 0;
390+
for (const auto& legId : {v0.posTrackId(), v0.negTrackId()}) {
391+
legIter.setCursor(legId);
392+
trackIter.setCursor(legIter.trackId());
393+
if (trackIter.has_mcParticle()) {
394+
mcParticleIter.setCursor(trackIter.mcParticleId());
395+
if (mcParticleIter.has_mothers()) {
396+
mother[i] = mcParticleIter.mothersIds()[0];
397+
}
398+
}
399+
++i;
400+
}
401+
if (mother[0] == mother[1] && mother[0] >= 0) {
402+
recoPhotons.insert(mother[0]);
403+
}
404+
}
405+
}
406+
}
407+
261408
for (const auto& collision : collisions) {
262409
registry.fill(HIST("hEventCounter"), 1);
263410

@@ -320,6 +467,9 @@ struct AssociateMCInfoPhoton {
320467

321468
// make an entry for this MC event only if it was not already added to the table
322469
if (!fEventLabels.contains(mcCollisionIter.globalIndex())) {
470+
if (fillBremsChain) {
471+
fillBremsChainTruth(groupedMcParticles, mcParticles, recoPhotons);
472+
}
323473
mcevents(mcCollisionIter.globalIndex(), mcCollisionIter.generatorsID(), mcCollisionIter.posX(), mcCollisionIter.posY(), mcCollisionIter.posZ(), mcCollisionIter.impactParameter(), mcCollisionIter.eventPlaneAngle());
324474
fEventLabels[mcCollisionIter.globalIndex()] = fCounter.events;
325475
fCounter.events++;

‎PWGEM/PhotonMeson/TableProducer/photonMixedEventProducer.cxx‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include <numeric>
5353
#include <random>
5454
#include <set>
55+
#include <tuple>
5556
#include <unordered_map>
5657
#include <utility>
5758
#include <vector>
@@ -122,6 +123,7 @@ struct PhotonMixedEventProducer {
122123
Configurable<int> cfgCentEstimator{"cfgCentEstimator", 2, "centrality estimator: 0 FT0M, 1 FT0A, 2 FT0C"};
123124
Configurable<float> cfgCentMin{"cfgCentMin", 10.f, "min centrality (one class)"};
124125
Configurable<float> cfgCentMax{"cfgCentMax", 20.f, "max centrality"};
126+
Configurable<float> cfgCentBinWidth{"cfgCentBinWidth", 0.f, "pool centrality bin width (%) inside [cfgCentMin, cfgCentMax); 0 = one bin. Partner events are then matched in centrality, which removes the Delta E tilt of the mixed event (same-event pairs share the spectrum of their event)"};
125127
Configurable<float> cfgZMax{"cfgZMax", 10.f, "max |z_vtx| (cm)"};
126128
Configurable<float> cfgZBinWidth{"cfgZBinWidth", 2.f, "pool z bin width (cm)"};
127129
Configurable<int> cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "occupancy: 0 trackOccupancyInTimeRange, 1 ft0cOccupancyInTimeRange"};
@@ -139,7 +141,7 @@ struct PhotonMixedEventProducer {
139141

140142
HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false};
141143

142-
std::map<std::pair<int, int>, std::deque<EventCopy>> mPools;
144+
std::map<std::tuple<int, int, int>, std::deque<EventCopy>> mPools; // (z bin, occupancy bin, centrality bin)
143145
std::mt19937 mRandom;
144146
int mRunNumber = -1;
145147
int64_t mEventUid = 0;
@@ -173,6 +175,7 @@ struct PhotonMixedEventProducer {
173175
registry.add("Event/hOccupancy", "accepted events;occupancy", kTH1D, {{200, 0.f, 20000.f}});
174176
registry.add("Pool/hDepthVsZ", "pool size when used;z_{vtx} (cm);events in the pool", kTH2D, {{nZ, -cfgZMax, cfgZMax}, {cfgPoolDepth + 1, -0.5f, cfgPoolDepth + 0.5f}});
175177
registry.add("Pool/hDepthVsOccBin", "pool size when used;occupancy bin;events in the pool", kTH2D, {{static_cast<int>(cfgOccupancyBins->size()) - 1, -0.5f, cfgOccupancyBins->size() - 1.5f}, {cfgPoolDepth + 1, -0.5f, cfgPoolDepth + 0.5f}});
178+
registry.add("Pool/hDepthVsCentBin", "pool size when used;centrality bin;events in the pool", kTH2D, {{std::max(1, nCentBins()), -0.5f, std::max(1, nCentBins()) - 0.5f}, {cfgPoolDepth + 1, -0.5f, cfgPoolDepth + 0.5f}});
176179
registry.add("Pool/hPartnersVsN", "partner events available vs needed;N of the current event;events in the pool", kTH2D, {axN, {cfgPoolDepth + 1, -0.5f, cfgPoolDepth + 0.5f}});
177180
registry.add("Pool/hNPooledPhotons", "photons in all pools (memory), per event;photons", kTH1D, {{500, 0.f, 5.e5f}});
178181
registry.add("Pool/hNPools", "filled pools, per event;pools", kTH1D, {{1000, 0.f, 10000.f}});
@@ -224,6 +227,20 @@ struct PhotonMixedEventProducer {
224227
return cfgOccupancyEstimator.value == 1 ? collision.ft0cOccupancyInTimeRange() : static_cast<float>(collision.trackOccupancyInTimeRange());
225228
}
226229

230+
int nCentBins() const
231+
{
232+
if (cfgCentBinWidth.value <= 0.f) {
233+
return 1;
234+
}
235+
return std::max(1, static_cast<int>(std::ceil((cfgCentMax.value - cfgCentMin.value) / cfgCentBinWidth.value - 1e-4f))); // o2-linter: disable=magic-number (rounding guard)
236+
}
237+
int centralityBin(const float cent) const
238+
{
239+
if (cfgCentBinWidth.value <= 0.f) {
240+
return 0;
241+
}
242+
return std::clamp(static_cast<int>(std::floor((cent - cfgCentMin.value) / cfgCentBinWidth.value)), 0, nCentBins() - 1);
243+
}
227244
int occupancyBin(const float occ) const
228245
{
229246
const auto& edges = cfgOccupancyBins.value;
@@ -590,8 +607,10 @@ struct PhotonMixedEventProducer {
590607
const int nPhotons = static_cast<int>(current.photons.size());
591608
registry.fill(HIST("Event/hNPhotons"), nPhotons);
592609

593-
auto& pool = mPools[{zBin, occBin}];
610+
const int centBin = centralityBin(cent);
611+
auto& pool = mPools[{zBin, occBin, centBin}];
594612
const int depth = static_cast<int>(pool.size());
613+
registry.fill(HIST("Pool/hDepthVsCentBin"), centBin, depth);
595614
registry.fill(HIST("Pool/hPartnersVsN"), nPhotons, depth);
596615
registry.fill(HIST("Pool/hDepthVsZ"), collision.posZ(), depth);
597616
registry.fill(HIST("Pool/hDepthVsOccBin"), occBin, depth);

0 commit comments

Comments
 (0)